diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md new file mode 100644 index 00000000..3623e116 --- /dev/null +++ b/.github/CHANGELOG.md @@ -0,0 +1,11 @@ +## Release 0.1.0 + +### New features since last release + +* This is the initial public release. + +### Contributors + +This release contains contributions from (in alphabetical order): + +[Mikhail Andrenkov](https://github.com/Mandrenkov), [Jack Brown](https://github.com/brownj85), [Lee J. O'Riordan](https://github.com/mlxd), [Trevor Vincent](https://github.com/trevor-vincent). diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..0ed79a00 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant 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, 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. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at research@xanadu.ai. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..096ace93 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,154 @@ +# Contributing to Jet + +Thank you for taking the time to contribute to Jet! +:airplane: :confetti_ball: :tada: :fireworks: :balloon: + +Jet is a collaborative effort with the quantum computation community - while we +will continue working on adding new and exciting features to Jet, we invite you +to join us and suggest improvements, research ideas, or even just to discuss how +Jet fits into your workflow. + +## How can I get involved in the community? + +If you want to contribute but don't know where to start, check out our +[documentation](https://quantum-jet.readthedocs.io) and have a go at working +through some of the tutorials. Afterwards, take a look at the Jet API to see +how things work under the hood. + +## How can I contribute? + +It's up to you! + +* **Be a part of our community** - provide exciting updates of the projects or + experiments you are investigating with Jet. + + You can even write your own Jet tutorials, or blog about your simulation results. + Send us the link, and we may even add it to our documentation as an external + resource! + +* **Test the cutting-edge Jet releases** - clone our GitHub repository, and keep + up to date with the latest features. If you run into any bugs, make a bug + report on our [issue tracker](https://github.com/XanaduAI/jet/issues). + +* **Report bugs** - even if you are not using the development branch of Jet, if + you come across any bugs or issues, make a bug report. See the next section + for more details on the bug reporting procedure. + +* **Suggest new features and enhancements** - use the GitHub issue tracker and + let us know what will make Jet even better for your workflow. + +* **Contribute to our documentation, or to Jet directly** - we are hoping for + our documentation to become an online, open-source resource for all things + tensor. If you would like to add to it, or suggest improvements/changes, let + us know - or even submit a pull request directly. All authors who have + contributed to the Jet codebase will be listed alongside the latest release. + +* **Build an application on top of Jet** - have an idea for an application, and + Jet provides the perfect computational backbone? Consider making a fully + separate app that builds upon Jet as a base. Ask us if you have any questions, + and send a link to your application to support@xanadu.ai so we can highlight + it in our documentation! + +Appetite whetted? Keep reading below for all the nitty-gritty on reporting bugs, +contributing to the documentation, and submitting pull requests. + +## Reporting bugs + +We use the [GitHub issue tracker](https://github.com/XanaduAI/jet/issues) to +keep track of all reported bugs and issues. If you find a bug, or have an issue +with Jet, please submit a bug report! User reports help us make Jet better on +all fronts. + +To submit a bug report, please work your way through the following checklist: + +* **Search the issue tracker to make sure the bug wasn't previously reported**. + If it was, you can add a comment to expand on the issue and share your + experience. + +* **Fill out the issue template**. If you cannot find an existing issue + addressing the problem, create a new issue by filling out the + [bug issue template](./ISSUE_TEMPLATE/BUG.md). This template is added + automatically to the comment box when you create a new issue. Please try and + add as many details as possible! + +* Try and make your issue as **clear, concise, and descriptive** as possible. + Include a clear and descriptive title, and include all code snippets and + commands required to reproduce the problem. If you're not sure what caused the + issue, describe what you were doing when the issue occurred. + +## Suggesting features, document additions, and enhancements + +To suggest features and enhancements, use the GitHub tracker. No template is +required for feature requests and enhancements, but here are a couple of +suggestions for things to include: + +* **Use a clear and descriptive title** +* **Provide a step-by-step description of the suggested feature**. + + - If the feature is related to any theoretical results in quantum computation, + provide any relevant equations. Alternatively, provide references to + papers or preprints with the relevant sections and equations noted. + - If the feature is workflow-related, or related to the use of Jet, explain + why the enhancement would be useful and where/how you would like to use it. + +* **For documentation additions**, point us towards any relevant equations, + papers, and preprints with the relevant sections and equations noted. Short + descriptions of its use and importance would also be helpful. + +## Pull requests + +If you would like to contribute directly to the Jet codebase, simply make a +fork of the main branch and submit a +[pull request](https://help.github.com/articles/about-pull-requests). We +encourage everyone to have a go forking and modifying the Jet source code; +however, we have a couple of guidelines on pull requests to ensure the main +branch conforms to existing standards and quality. + +### General guidelines + +* **Do not make a pull request for minor typos/cosmetic code changes** - create + an issue instead. +* **For major features, consider making an independent application** that runs + on top of Jet, rather than modifying Jet directly. + +### Before submitting + +Before submitting a pull request, please make sure the following is done: + +* **All new features must include a unit test.** If you've fixed a bug or added + code that should be tested, add a test to the [`test/`](test/) directory! +* **All new classes, functions, and members must be clearly commented and documented**. + If you do make documentation changes, make sure that the docs build and render + correctly by running `make docs`. +* **Ensure that the test suite passes.** Verify that `make test` passes. +* **Ensure that the modified code is formatted correctly.** Verify that + `make format` passes. + +### Submitting the pull request +* When ready, submit your fork as a + [pull request](https://help.github.com/articles/about-pull-requests) to the + Jet repository, filling out the + [pull request template](./PULL_REQUEST_TEMPLATE.md). This template is added + automatically to the comment box when you create a new PR. + +* When describing the pull request, please include as much detail as possible + regarding the changes made, new features, and performance improvements. If + including any bug fixes, mention the issue numbers associated with the bugs. + +* Once you have submitted the pull request, two things will automatically occur: + + - The **test suite** will automatically run on + [CircleCI](https://app.circleci.com/pipelines/github/XanaduAI/jet) to ensure + that all tests continue to pass. + + - The **formatter** will automatically run on + [CircleCI](https://app.circleci.com/pipelines/github/XanaduAI/jet) to ensure + that all the code is properly formatted. + + Based on these results, we may ask you to make small changes to your branch + before merging the pull request into the main branch. Alternatively, you can + [grant us permission to make changes to your pull request branch](https://help.github.com/articles/allowing-changes-to-a-pull-request-branch-created-from-a-fork/). + +:airplane: Thank you for contributing to Jet! :airplane: + +\- The Jet team \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 00000000..bbaa005f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,38 @@ +--- +name: Bug Report +about: Submit a bug report. +title: '' +labels: bug +assignees: '' + +--- + +#### Before posting an issue + +* Search existing GitHub issues to make sure the issue does not already exist: https://github.com/XanaduAI/jet/issues. + +* Delete everything above the dashed line and fill in the template. + +* For general technical details, check out our documentation: https://quantum-jet.readthedocs.io. + +------------------------------------------------------------------------------------------------------------- + +#### Bug description + +Description of the issue - include code snippets and screenshots here if relevant. You may use the following template below: + +* *Expected behavior:* (What you expect to happen) + +* *Actual behavior:* (What actually happens) + +* *Reproduces how often:* (Percentage of the time this issue reproduces) + +* *System information:* (Relevant compilation or execution environment details, including your operating system, compiler, Jet version, and linked libraries) + +#### Source code and backtraces + +Please include any additional code snippets and backtraces related to the issue here. + +#### Additional information + +Any additional information, configuration or data that might be necessary to reproduce the issue. diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 00000000..15efd3f4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,30 @@ +--- +name: Feature Request +about: Submit a feature request. +title: '' +labels: enhancement +assignees: '' + +--- + +#### Before posting an issue + +* Search existing GitHub issues to make sure the issue does not already exist: https://github.com/XanaduAI/jet/issues. + +* Delete everything above the dashed line and describe, in detail, the feature and why it is needed. + +* For general technical details, check out our documentation: https://quantum-jet.readthedocs.io. + +------------------------------------------------------------------------------------------------------------- + +#### Feature description + +Description of the feature - include code snippets, documentation, or any other relevant details here. Ideally, a feature request should read like a story and address the following points: + +* *Context:* What is the problem to be solved? + +* *Factors:* What should be taken into account by the implementation? + +* *Review:* What other projects have implemented this feature? + +* *Proposals:* What are the candidate solutions? diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..89631338 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,32 @@ +### Before submitting + +Please complete the following checklist when submitting a PR: + +- [ ] All new features must include a unit test. If you've fixed a bug or added + code that should be tested, add a test to the [`test/`](test/) directory! + +- [ ] All new classes, functions, and members must be clearly commented and + documented. If you do make documentation changes, make sure that the docs + build and render correctly by running `make docs`. + +- [ ] Ensure that the test suite passes by running `make test`. + +- [ ] Ensure that code is properly formatted by running `make format`. + +- [ ] Add a new entry to [`CHANGELOG.MD`](.github/CHANGELOG.md), summarizing the + change and including a link back to the PR. + +When all the above are checked, delete everything above the dashed +line and fill in the pull request template. + +------------------------------------------------------------------------------------------------------------ + +**Context:** + +**Description of the Change:** + +**Benefits:** + +**Possible Drawbacks:** + +**Related GitHub Issues:** \ No newline at end of file diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000..9ebb3116 --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,35 @@ +name: Documentation +on: + pull_request: + push: + branches: + - main + paths: + - "docs/**" + - "include/**" + +jobs: + build: + name: Build (HTML) + runs-on: ubuntu-20.04 + + steps: + - name: Cancel previous runs + uses: styfle/cancel-workflow-action@0.4.1 + with: + access_token: ${{ github.token }} + + - name: Checkout code + uses: actions/checkout@v2 + + - uses: josh146/sphinx-action@master + with: + docs-folder: "docs/" + pre-build-command: "apt install -y doxygen && pip3 install -r requirements.txt" + build-command: "make html" + + - name: Upload HTML + uses: actions/upload-artifact@v2 + with: + name: html + path: docs/_build/html/ \ No newline at end of file diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 00000000..8f7686d4 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,29 @@ +name: Format +on: + pull_request: + push: + branches: + - main + paths: + - "include/**" + - "test/**" + +jobs: + format: + name: Format + runs-on: ubuntu-20.04 + + steps: + - name: Cancel previous runs + uses: styfle/cancel-workflow-action@0.4.1 + with: + access_token: ${{ github.token }} + + - name: Install dependencies + run: sudo apt update && sudo apt -y install clang-format python3 + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Run formatter + run: ./bin/format --check include test \ No newline at end of file diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 00000000..dc491415 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,62 @@ +name: Nightly +on: + schedule: + # Run this workflow at midnight every workday. + - cron: "0 0 * * 1-5" + +jobs: + test-ubuntu: + name: Build (Ubuntu) + runs-on: ubuntu-20.04 + + steps: + - name: Install dependencies + run: sudo apt install -y libopenmpi-dev libopenblas-dev + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Initialize build directory + run: | + mkdir build + cd build + cmake -DENABLE_SANITIZERS=ON -DBUILD_TESTS=ON ../ + + - name: Build Jet + run: | + cd build + make -j`nproc` + + - name: Run tests + run: | + cd build + mkdir test/results + ./test/runner --order lex + + test-macos: + name: Build (MacOS) + runs-on: macos-10.15 + + steps: + - name: Install dependencies + run: brew install openmpi libomp + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Initialize build directory + run: | + mkdir build + cd build + cmake -DENABLE_SANITIZERS=ON -DBUILD_TESTS=ON ../ + + - name: Build Jet + run: | + cd build + make -j`sysctl -n hw.physicalcpu` + + - name: Run tests + run: | + cd build + mkdir test/results + ./test/runner --order lex diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..232394ea --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,105 @@ +name: Tests +on: + pull_request: + push: + branches: + - main + paths-ignore: + - ".github/**" + - "docs/**" + - "README.rst" + +jobs: + test-ubuntu: + name: Build (Ubuntu) + runs-on: ubuntu-20.04 + + steps: + - name: Cancel previous runs + uses: styfle/cancel-workflow-action@0.4.1 + with: + access_token: ${{ github.token }} + + - name: Install dependencies + run: sudo apt install -y libomp-dev libopenblas-dev + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Initialize build directory + run: | + mkdir build + cd build + cmake -DENABLE_OPENMP=ON -DBUILD_TESTS=ON ../ + + - name: Build Jet + run: | + cd build + make -j`nproc` + + - name: Run tests + run: | + cd build + mkdir test/results + ./test/runner --order lex --reporter junit --out test/results/report.xml + + - name: Upload test results + uses: actions/upload-artifact@v2 + if: always() + with: + name: ubuntu-test-report + path: build/test/results/report.xml + + - name: Publish test results + uses: EnricoMi/publish-unit-test-result-action@v1 + if: always() + with: + check_name: Test Report (Ubuntu) + files: build/test/results/report.xml + + test-macos: + name: Build (MacOS) + runs-on: macos-10.15 + + steps: + - name: Cancel previous runs + uses: styfle/cancel-workflow-action@0.4.1 + with: + access_token: ${{ github.token }} + + - name: Install dependencies + run: brew install libomp + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Initialize build directory + run: | + mkdir build + cd build + cmake -DENABLE_OPENMP=ON -DBUILD_TESTS=ON ../ + + - name: Build Jet + run: | + cd build + make -j`sysctl -n hw.physicalcpu` + + - name: Run tests + run: | + cd build + mkdir test/results + ./test/runner --order lex --reporter junit --out test/results/report.xml + + - name: Upload test results + uses: actions/upload-artifact@v2 + if: always() + with: + name: macos-test-report + path: build/test/results/report.xml + + - name: Publish test results + uses: EnricoMi/publish-unit-test-result-action/composite@v1 + if: always() + with: + check_name: Test Report (MacOS) + files: build/test/results/report.xml \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c709e58a --- /dev/null +++ b/.gitignore @@ -0,0 +1,52 @@ +# Prerequisites +*.d + +# Compiled object files +*.slo +*.lo +*.o +*.obj + +# Precompiled headers +*.gch +*.pch + +# Compiled dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +*~ +build +# +*# +*#* +.dir-locals.el +/presentation/.ipynb_checkpoints/Untitled-checkpoint.ipynb + +# CMake build artifacts +include/jet/CmakeMacros.hpp + +# Python virtualenv +.venv + +# Sphinx documentation +docs/__pycache__/* +docs/_build/* +docs/_ext/__pycache__/* +docs/api/* +docs/doxyoutput/* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..a8a5e66b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,161 @@ +########################## +## Set Project version +########################## +cmake_minimum_required(VERSION 3.13) +set(JET_LOGO " + ▄▄ ▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄ + ██ ██▀▀▀▀▀▀ ▀▀▀██▀▀▀ + ██ ██ ██ + ██ ███████ ██ + ██ ██ ██ +█▄▄▄▄▄██ ██▄▄▄▄▄▄ ██ + ▀▀▀▀▀ ▀▀▀▀▀▀▀▀ ▀▀ +") +message(${JET_LOGO}) + +project("Jet" + VERSION 0.1.0 + DESCRIPTION "A task-based tensor network contraction engine" + LANGUAGES CXX C +) + +########################## +## Set Default Options +########################## +# Compiler options +option(ENABLE_SANITIZERS "Enable sanitizers" OFF) +option(ENABLE_WARNINGS "Enable warnings" ON) +option(ENABLE_OPENMP "Enable OpenMP if supported" OFF) +option(ENABLE_NATIVE "Enable native build tuning" OFF) +option(ENABLE_IPO "Enable interprocedural/link-time optimisation" OFF) + +# Build options +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING + "Default build type: Release" FORCE) +endif() +option(BUILD_TESTS "Build tests" OFF) + +########################## +## Enfore Compiler Support +########################## +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "7.0") + message(STATUS "CMAKE_CXX_COMPILER_VERSION: ${CMAKE_CXX_COMPILER_VERSION}") + message(FATAL_ERROR "\nJet requires g++ at least v7.0") + endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0") + message(STATUS "CMAKE_CXX_COMPILER_VERSION: ${CMAKE_CXX_COMPILER_VERSION}") + message(FATAL_ERROR "\nJet requires clang++ at least v5.0") + endif() +## AppleClang +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.0") + message(FATAL_ERROR "\nJet requires AppleClang at least v8.0") + endif() +option(USING_APPLECLANG "AppleClang" On) +## microsoft visual c++ +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0.1") + message(STATUS "CMAKE_CXX_COMPILER_VERSION: ${CMAKE_CXX_COMPILER_VERSION}") + message(FATAL_ERROR "\nJet requires icpc at least v19.0.1") + endif() +else() + message(FATAL_ERROR "\nJet does not support the selected ${CMAKE_CXX_COMPILER_ID} compiler.") +endif() + +########################## +## Include BLAS modules +########################## + +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") + +find_package(MKL QUIET) + +if(MKL_FOUND) + add_definitions("-DENABLE_MKL") + set(BLAS_INCLUDE_DIRS "${MKL_INCLUDE_DIR}") + set(BLAS_LIBRARIES ${MKL_LIBRARY}) +else() + find_package(CBLAS REQUIRED) + set(BLAS_LIBRARIES ${CBLAS_LIBRARIES}) + set(BLAS_INCLUDE_DIRS ${CBLAS_INCLUDE_DIRS}) +endif() + + +########################## +## Fetch Taskflow +########################## +Include(FetchContent) + +FetchContent_Declare( + Taskflow + GIT_REPOSITORY https://github.com/taskflow/taskflow.git + GIT_TAG v3.1.0 +) + +# FetchContent_MakeAvailable() requires CMake 3.14 or newer. +FetchContent_GetProperties(Taskflow) +if(NOT Taskflow_POPULATED) + FetchContent_Populate(Taskflow) + # Don't build the Taskflow tests or examples. + set(TF_BUILD_EXAMPLES OFF CACHE INTERNAL "Build Taskflow examples") + set(TF_BUILD_TESTS OFF CACHE INTERNAL "Build Taskflow tests") + add_subdirectory(${taskflow_SOURCE_DIR} ${taskflow_BINARY_DIR}) +endif() + +find_package(OpenMP QUIET) + +message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") +message(STATUS "BLAS_LIBRARIES: ${BLAS_LIBRARIES}") +message(STATUS "BLAS_INCLUDE_DIRS: ${BLAS_INCLUDE_DIRS}") +message(STATUS "ENABLE_NATIVE: ${ENABLE_NATIVE}") +message(STATUS "ENABLE_IPO: ${ENABLE_IPO}") + +########################## +## Create Jet target +########################## + +add_library(Jet INTERFACE) +target_include_directories(Jet INTERFACE + $ + ${BLAS_INCLUDE_DIRS} +) + +target_link_libraries(Jet INTERFACE ${BLAS_LIBRARIES} Taskflow) + +########################## +## Compile options +########################## + +if (ENABLE_OPENMP AND OPENMP_FOUND) + target_link_libraries(Jet INTERFACE OpenMP::OpenMP_CXX) +elseif (ENABLE_OPENMP AND NOT OPENMP_FOUND) + message(FATAL_ERROR "\nOpenMP is enabled but could not be found") +endif() +if(ENABLE_SANITIZERS) + target_compile_options(Jet INTERFACE -g -fsanitize=address,undefined) + target_link_options(Jet INTERFACE -fsanitize=address,undefined) +endif() +if(ENABLE_WARNINGS) + target_compile_options(Jet INTERFACE -Wall -Wextra -Werror) +endif() +if(ENABLE_NATIVE) + target_compile_options(Jet INTERFACE -march=native) +endif() +if(ENABLE_IPO) + target_compile_options(Jet INTERFACE -flto) +endif() + +########################## +## Build tests +########################## + +if(BUILD_TESTS) + enable_testing() + add_subdirectory(test) +endif(BUILD_TESTS) diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..dc3727d0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,197 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + Copyright [yyyy] [name of copyright owner] + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..ea74e853 --- /dev/null +++ b/Makefile @@ -0,0 +1,75 @@ +.DEFAULT_PREFIX=/usr/local +.TEST_BUILD_DIR=./build +.VENV_DIR=./.venv + +prefix=$(.DEFAULT_PREFIX) + +define HELP_BODY +Please use 'make [target]'. + +TARGETS + install [prefix=] Install Jet headers to /include, defaults to $(.DEFAULT_PREFIX) + + uninstall [prefix=] Remove Jet headers from /include, defaults to $(.DEFAULT_PREFIX) + + test Build and run tests (requires cmake) + + docs Build docs (requires doxygen, pandoc and pip) + + format [check=1] Apply formatters; use with 'check=1' to check instead of modify (requires clang-format) + + clean Remove all build artifacts + +endef + +.PHONY: help +help: + @: $(info $(HELP_BODY)) + + +.PHONY: format +format: +ifdef check + ./bin/format --check include test +else + ./bin/format include test +endif + + +.PHONY: install +install: ./include/Jet.hpp ./include/jet + mkdir -p $(prefix)/include + cp -r $^ $(prefix)/include/ + + +.PHONY: docs +uninstall: + rm -r $(prefix)/include/jet $(prefix)/include/Jet.hpp + + +.PHONY: test +test: $(.TEST_BUILD_DIR) + cd $(.TEST_BUILD_DIR) && $(MAKE) + $(.TEST_BUILD_DIR)/test/runner + + +.PHONY: docs +docs: $(.VENV_DIR) + . $(.VENV_DIR)/bin/activate; cd ./docs && $(MAKE) html + + +.PHONY: clean +clean: + rm -rf docs/_build docs/api docs/doxyoutput + rm -rf $(.TEST_BUILD_DIR) + rm -rf $(.VENV_DIR) + + +$(.VENV_DIR): + python3 -m venv $@ + $@/bin/pip install -r docs/requirements.txt + + +$(.TEST_BUILD_DIR): + mkdir -p $@ + cd $@ && cmake -DBUILD_TESTS=ON ../ diff --git a/README.rst b/README.rst new file mode 100644 index 00000000..2dd3d8d5 --- /dev/null +++ b/README.rst @@ -0,0 +1,135 @@ +.. raw:: html + +

+ Jet +

+ +################################################## + +.. image:: https://github.com/XanaduAI/jet/actions/workflows/tests.yml/badge.svg + :alt: GitHub Actions + :target: https://github.com/XanaduAI/jet/actions/workflows/tests.yml + +.. image:: https://img.shields.io/badge/Docs-English-yellow.svg + :alt: Documentation + :target: https://quantum-jet.readthedocs.io + +.. image:: https://img.shields.io/badge/C%2B%2B-17-blue.svg + :alt: Standard + :target: https://en.wikipedia.org/wiki/C%2B%2B17 + +.. image:: https://img.shields.io/badge/License-Apache%202.0-orange.svg + :alt: License + :target: https://www.apache.org/licenses/LICENSE-2.0 + +`Jet `_ is a cross-platform C++ library for +simulating quantum circuits using tensor network contractions. + +Features +======== + +* Runs on a variety of systems, from single-board machines to massively parallel + supercomputers. + +* Accelerates tensor contractions using a novel task-based parallelism approach. + +* Models quantum systems with an arbitrary number of basis states. + +To get started with Jet, read one of our `tutorial walkthroughs +`__ or +browse the full `API documentation +`__. + +Installation +============ + +Jet requires `Taskflow `_, a BLAS library +with a CBLAS interface, and a C++ compiler with C++17 support. To use Jet, add +``#include `` to the top of your header file and link your program with +the CBLAS library. + +For example, assuming that the Taskflow headers can be found in your ``g++`` +include path and OpenBLAS is installed on your system, you can compile the +``hellojet.cpp`` program below + +.. code-block:: cpp + + #include + #include + #include + + #include + + int main(){ + using tensor_t = Jet::Tensor>; + + std::array tensors; + tensors[0] = tensor_t({"i", "j", "k"}, {2, 2, 2}); + tensors[1] = tensor_t({"j", "k", "l"}, {2, 2, 2}); + + tensors[0].FillRandom(); + tensors[1].FillRandom(); + tensors[2] = Jet::ContractTensors(tensors[0], tensors[1]); + + for (const auto &datum : tensors[2].GetData()) { + std::cout << datum << std::endl; + } + + std::cout << "You have successfully used Jet version " << Jet::Version() << std::endl; + + return 0; + } + +by running + +.. code-block:: bash + + git clone https://github.com/XanaduAI/jet + g++ --std=c++17 -O3 -I$PWD/jet/include -lopenblas ./hellojet.cpp -o hellojet + +The output of this program should resemble + +.. code-block:: text + + $ ./hellojet + (0.804981,0) + (1.53207,0) + (0.414398,0) + (0.721263,0) + You have successfully used Jet version 0.1.0 + +For more detailed instructions, see the `development guide +`_. + +Contributing to Jet +=================== + +We welcome new contributions - simply fork the Jet repository and make a +`pull request `_ +containing your contribution. All contributers to Jet will be listed as authors +on the releases. See our `changelog <.github/CHANGELOG.md>`_ for more details. + +We also encourage bug reports, suggestions for new features and enhancements, +and even links to cool projects or applications built using Jet. Visit the +`contributions page <.github/CONTRIBUTIONS.md>`_ to learn more about sharing +your ideas with the Jet team. + +Support +======= + +- **Source Code:** https://github.com/XanaduAI/jet +- **Issue Tracker:** https://github.com/XanaduAI/jet/issues + +If you are having issues, please let us know by posting the issue on our GitHub +issue tracker. + +License +======= + +Jet is **free** and **open source**, released under the +`Apache License, Version 2.0 `_. + +Jet contains a copy of +`JSON for Modern C++ `_ +from Niels Lohmann which is licenced under the +`MIT License `_. diff --git a/bin/format b/bin/format new file mode 100755 index 00000000..d39caa3c --- /dev/null +++ b/bin/format @@ -0,0 +1,120 @@ +#!/usr/bin/python3 + +import argparse +import json +import pathlib +import subprocess +import sys + +CLANG_FMT_BIN = "clang-format" +CLANG_FMT_STYLE_CFG = { + "BasedOnStyle": "llvm", + "BreakBeforeBraces": "Stroustrup", # function braces on newline + "IndentWidth": 4, +} + +SRCFILE_EXT = ("c", "cpp", "cxx", "h", "hpp", "hxx") +IGNORE_PATTERN = "external" + +BASE_CMD = ("clang-format", f"-style={json.dumps(CLANG_FMT_STYLE_CFG)}") + + +def check_bin(): + try: + subprocess.run( + ("clang-format", "--help"), universal_newlines=True, capture_output=True + ) + except FileNotFoundError as exc: + raise FileNotFoundError( + "clang-format is not installed or is not in PATH." + ) from exc + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Opinionated C/C++ formatter. Based on clang-format" + ) + parser.add_argument( + "paths", nargs="+", metavar="DIR", help="paths to the root source directories" + ) + parser.add_argument( + "-c", + "--check", + action="store_true", + help="don't write files, just return status. " + "A non-zero return code indicates some files would be re-formatted", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="print detailed information about format violations", + ) + + return parser.parse_args() + + +def get_files(args): + files = [] + + for path in args.paths: + for ext in SRCFILE_EXT: + for file_path in pathlib.Path(path).rglob(f"*.{ext}"): + files.append(str(file_path)) + + return [f for f in files if IGNORE_PATTERN not in f] + + +def fmt(args, files) -> int: + cmd = (*BASE_CMD, "-i", *files) + + paths = ", ".join(args.paths) + sys.stderr.write(f"Formatting {len(files)} files in {paths}.\n") + + ret = subprocess.run(cmd, capture_output=True, universal_newlines=True) + if ret.returncode != 0: + sys.stderr.write(ret.stderr) + return 1 + + return 0 + + +def check(args, files) -> int: + cmd = (*BASE_CMD, "--dry-run", "-Werror") + + needs_reformatted_ct = 0 + + for src_file in files: + ret = subprocess.run( + (*cmd, src_file), capture_output=True, universal_newlines=True + ) + + if ret.returncode != 0: + sys.stderr.write(f"Error: {src_file} would be reformatted.\n") + if args.verbose: + sys.stderr.write(ret.stderr) + + needs_reformatted_ct += 1 + + sys.stderr.write(f"{needs_reformatted_ct} files would be re-formatted.\n") + sys.stderr.write(f"{len(files) - needs_reformatted_ct} would be left unchanged.\n") + + return needs_reformatted_ct + + +if __name__ == "__main__": + check_bin() + args = parse_args() + + files = get_files(args) + + if len(files) == 0: + print("No source files found! Nothing to do.") + sys.exit(0) + + if args.check: + ret = check(args, files) + else: + ret = fmt(args, files) + + sys.exit(int(ret > 0)) diff --git a/cmake/FindCBLAS.cmake b/cmake/FindCBLAS.cmake new file mode 100644 index 00000000..57b1c4f1 --- /dev/null +++ b/cmake/FindCBLAS.cmake @@ -0,0 +1,74 @@ +# ================================================================================================== +# This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This +# project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max- +# width of 100 characters per line. +# +# Author(s): +# Cedric Nugteren +# +# ================================================================================================== +# +# Defines the following variables: +# CBLAS_FOUND Boolean holding whether or not the Netlib BLAS library was found +# CBLAS_INCLUDE_DIRS The Netlib BLAS include directory +# CBLAS_LIBRARIES The Netlib BLAS library +# +# In case BLAS is not installed in the default directory, set the CBLAS_ROOT variable to point to +# the root of BLAS, such that 'cblas.h' can be found in $CBLAS_ROOT/include. This can either be +# done using an environmental variable (e.g. export CBLAS_ROOT=/path/to/BLAS) or using a CMake +# variable (e.g. cmake -DCBLAS_ROOT=/path/to/BLAS ..). +# +# ================================================================================================== + +# Sets the possible install locations +set(CBLAS_HINTS + ${CBLAS_ROOT} + $ENV{CBLAS_ROOT} +) +set(CBLAS_PATHS + /usr + /usr/local + /usr/local/opt + /System/Library/Frameworks +) + +# Finds the include directories +find_path(CBLAS_INCLUDE_DIRS + NAMES cblas.h + HINTS ${CBLAS_HINTS} + PATH_SUFFIXES + include inc include/x86_64 include/x64 + openblas/include include/blis blis/include blis/include/blis + Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Versions/Current/Headers + PATHS ${CBLAS_PATHS} + DOC "Netlib BLAS include header cblas.h" +) +mark_as_advanced(CBLAS_INCLUDE_DIRS) + +# Finds the library +find_library(CBLAS_LIBRARIES + NAMES cblas blas blis openblas accelerate + HINTS ${CBLAS_HINTS} + PATH_SUFFIXES + lib lib64 lib/x86_64 lib/x64 lib/x86 lib/Win32 lib/import lib64/import + openblas/lib blis/lib lib/atlas-base + PATHS ${CBLAS_PATHS} + DOC "Netlib BLAS library" +) +mark_as_advanced(CBLAS_LIBRARIES) + +# ================================================================================================== + +# Notification messages +if(NOT CBLAS_INCLUDE_DIRS) + message(STATUS "Could NOT find 'cblas.h', install a CPU Netlib BLAS or set CBLAS_ROOT") +endif() +if(NOT CBLAS_LIBRARIES) + message(STATUS "Could NOT find a CPU Netlib BLAS library, install it or set CBLAS_ROOT") +endif() + +# Determines whether or not BLAS was found +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CBLAS DEFAULT_MSG CBLAS_INCLUDE_DIRS CBLAS_LIBRARIES) + +# ================================================================================================== diff --git a/cmake/FindMKL.cmake b/cmake/FindMKL.cmake new file mode 100644 index 00000000..9b0004d7 --- /dev/null +++ b/cmake/FindMKL.cmake @@ -0,0 +1,78 @@ +########################################################### +# Adapted from PRACE course materials at: +# https://repository.prace-ri.eu/git/CodeVault/hpc-kernels/spectral_methods/-/blob/master/cmake/Modules/FindMKL.cmake +########################################################### + +# This script looks for MKL in two locations: +# - The environment variable MKLROOT, which is defined by +# sourcing an MKL environment +# - The directory `/opt/intel/mkl`, which is a common +# install location for MKL. +# It may be possible to install MKL using python -m pip, +# though this is not guaranteed to be found, and may +# require explicitly setting the MKLROOT variable. + +########################################################### +# Stage 1: find the root directory +########################################################### + +set(MKLROOT_PATH $ENV{MKLROOT}) + +if (NOT MKLROOT_PATH) + if (EXISTS "/opt/intel/mkl") + set(MKLROOT_PATH "/opt/intel/mkl") + endif () +endif () + +########################################################### +# Stage 2: find include path and libraries +########################################################### + +if (MKLROOT_PATH) + + set(EXPECT_MKL_INCPATH "${MKLROOT_PATH}/include") + set(EXPECT_ICC_LIBPATH "$ENV{ICC_LIBPATH}") + + # MacOS will have a different path structure + if (CMAKE_SYSTEM_NAME MATCHES "Darwin") + set(EXPECT_MKL_LIBPATH "${MKLROOT_PATH}/lib") + elseif (CMAKE_SYSTEM_NAME MATCHES "Linux") + set(EXPECT_MKL_LIBPATH "${MKLROOT_PATH}/lib/intel64") + endif() + + ########################################################### + # Set MKL_INCLUDE and MKL_LIBRARY_DIR + ########################################################### + + if (IS_DIRECTORY ${EXPECT_MKL_INCPATH}) + set(MKL_INCLUDE_DIR ${EXPECT_MKL_INCPATH}) + endif (IS_DIRECTORY ${EXPECT_MKL_INCPATH}) + + if (IS_DIRECTORY ${EXPECT_MKL_LIBPATH}) + set(MKL_LIBRARY_DIR ${EXPECT_MKL_LIBPATH}) + endif (IS_DIRECTORY ${EXPECT_MKL_LIBPATH}) + + ########################################################### + # find specific library files + ########################################################### + + find_library(LIB_MKL_RT NAMES mkl_rt mkl_rt.1 HINTS ${MKL_LIBRARY_DIR}) + find_library(LIB_PTHREAD NAMES pthread) + +endif (MKLROOT_PATH) + +set(MKL_LIBRARY "${LIB_MKL_RT};${LIB_PTHREAD}") + +########################################################### +# deal with QUIET and REQUIRED argument +########################################################### + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(MKL DEFAULT_MSG + MKL_LIBRARY_DIR + LIB_MKL_RT + LIB_PTHREAD + MKL_INCLUDE_DIR) + +mark_as_advanced(LIB_MKL_RT LIB_PTHREAD MKL_INCLUDE_DIR) diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..5bb4e83b --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,216 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Xanaduquantumcompiler.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Xanaduquantumcompiler.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Xanaduquantumcompiler" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Xanaduquantumcompiler" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/_ext/edit_on_github.py b/docs/_ext/edit_on_github.py new file mode 100644 index 00000000..fb62a3a3 --- /dev/null +++ b/docs/_ext/edit_on_github.py @@ -0,0 +1,44 @@ +""" +Sphinx extension to add ReadTheDocs-style "Edit on GitHub" links to the +sidebar. +Loosely based on https://github.com/astropy/astropy/pull/347 +""" + +import os +import warnings + +__licence__ = "Apache License v2.0" + + +def get_github_url(app, view, path): + return "https://github.com/{project}/{view}/{branch}/{path}".format( + project=app.config.edit_on_github_project, + view=view, + branch=app.config.edit_on_github_branch, + path=path, + ) + + +def html_page_context(app, pagename, templatename, context, doctree): + if templatename != "page.html": + return + + if not app.config.edit_on_github_project: + warnings.warn("edit_on_github_project not specified") + return + + if not doctree: + return + + path = os.path.relpath(doctree.get("source"), app.builder.srcdir) + show_url = get_github_url(app, "blob", path) + edit_url = get_github_url(app, "edit", path) + + context["show_on_github_url"] = show_url + context["edit_on_github_url"] = edit_url + + +def setup(app): + app.add_config_value("edit_on_github_project", "", True) + app.add_config_value("edit_on_github_branch", "master", True) + app.connect("html-page-context", html_page_context) diff --git a/docs/_static/666.png b/docs/_static/666.png new file mode 100644 index 00000000..707bc0c3 Binary files /dev/null and b/docs/_static/666.png differ diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico new file mode 100644 index 00000000..774251a4 Binary files /dev/null and b/docs/_static/favicon.ico differ diff --git a/docs/_static/jet_title.svg b/docs/_static/jet_title.svg new file mode 100755 index 00000000..302fb47b --- /dev/null +++ b/docs/_static/jet_title.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/_static/logo_new.png b/docs/_static/logo_new.png new file mode 100644 index 00000000..6cf58207 Binary files /dev/null and b/docs/_static/logo_new.png differ diff --git a/docs/_static/logo_new_small.png b/docs/_static/logo_new_small.png new file mode 100644 index 00000000..ca77e0b4 Binary files /dev/null and b/docs/_static/logo_new_small.png differ diff --git a/docs/_static/schema/tensor_network.json b/docs/_static/schema/tensor_network.json new file mode 100644 index 00000000..ace2e25c --- /dev/null +++ b/docs/_static/schema/tensor_network.json @@ -0,0 +1,90 @@ +{ + "$schema": "http://json-schema.org/schema", + "title": "Tensor Network File schema", + "type": "object", + "required": [ + "tensors" + ], + "properties": { + "path": { + "title": "Path", + "description": "List of tensor indices describing a contraction path", + "type": "array", + "items": { + "type": "array", + "additionalItems": false, + "items": [ + {"$ref": "#/$defs/tensor_index"}, + {"$ref": "#/$defs/tensor_index"} + ] + } + }, + "tensors": { + "title": "Tensors", + "description": "List of tensors in network", + "type": "array", + "items": {"$ref": "#/$defs/tensor"} + } + }, + "$defs": { + "complex_number": { + "title": "Complex Number", + "type": "array", + "additionalItems": false, + "items": [ + { + "title": "Real", + "type": "number" + }, + { + "title": "Imaginary", + "type": "number" + } + ] + }, + "tensor": { + "title": "Tensor", + "type": "array", + "additionalItems": false, + "items": [ + { + "title": "Tags", + "description": "Tags for identifying or categorizing the tensor", + "type": "array", + "items": { + "type": "string" + } + }, + { + "title": "Indices", + "description": "Indices of the tensor", + "type": "array", + "items": { + "type": "string" + } + }, + { + "title": "Shape", + "description": "Dimension of the corresponding indices", + "type": "array", + "items": { + "type": "integer" + } + }, + { + "title": "Data", + "description": "Complex elements of the tensor", + "type": "array", + "items": { + "$ref": "#/$defs/complex_number" + } + } + ] + }, + "tensor_index": { + "title": "Tensor Index", + "description": "Index of a tensor in 'tensors'", + "type": "integer" + } + } +} diff --git a/docs/_static/tensor_expec_val.svg b/docs/_static/tensor_expec_val.svg new file mode 100644 index 00000000..77021800 --- /dev/null +++ b/docs/_static/tensor_expec_val.svg @@ -0,0 +1,3 @@ + + +
\langle...
\langle...
\vert 0...
i
j
\sigma_...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/_static/tensor_matvec.svg b/docs/_static/tensor_matvec.svg new file mode 100644 index 00000000..b37ce75c --- /dev/null +++ b/docs/_static/tensor_matvec.svg @@ -0,0 +1,3 @@ + + +
=
i
N_j
j
M_{i,j}
=
\langle...
L_i
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/_static/tensor_network_bell_state_circuit.svg b/docs/_static/tensor_network_bell_state_circuit.svg new file mode 100644 index 00000000..3bea781a --- /dev/null +++ b/docs/_static/tensor_network_bell_state_circuit.svg @@ -0,0 +1,3 @@ + + +
\vert 0 \rangle
\vert 0 \rangle
H
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/_static/tensor_network_bell_state_network.svg b/docs/_static/tensor_network_bell_state_network.svg new file mode 100644 index 00000000..ed3e1c39 --- /dev/null +++ b/docs/_static/tensor_network_bell_state_network.svg @@ -0,0 +1,3 @@ + + +
i
m
~\vert...
H
j
k
~\vert...
CNOT
n
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/_static/tensor_network_contraction_example.svg b/docs/_static/tensor_network_contraction_example.svg new file mode 100644 index 00000000..04d090fd --- /dev/null +++ b/docs/_static/tensor_network_contraction_example.svg @@ -0,0 +1,3 @@ + + +
n
E_n
m
i
n
A_m
B_{m,i...
C_{i,k...
D_{j,k...
j
k
CD
BCD
E
\mapsto
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/_static/tensor_network_example.svg b/docs/_static/tensor_network_example.svg new file mode 100644 index 00000000..bbf9b30a --- /dev/null +++ b/docs/_static/tensor_network_example.svg @@ -0,0 +1,3 @@ + + +
m
i
n
A_m
B_{m,i...
C_{i,k...
D_{j,k...
j
k
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/_static/tensor_network_task_graph.svg b/docs/_static/tensor_network_task_graph.svg new file mode 100644 index 00000000..6fed2cd3 --- /dev/null +++ b/docs/_static/tensor_network_task_graph.svg @@ -0,0 +1,3 @@ + + +
~\vert...
H
~\vert...
CNOT
A_{k}
B_{m,n...
C_{m,n...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/_static/tensors.svg b/docs/_static/tensors.svg new file mode 100644 index 00000000..9b21decb --- /dev/null +++ b/docs/_static/tensors.svg @@ -0,0 +1,3 @@ + + +
B_i
C_{i,j...
D_{i,j,...
A
rank 0
tensor
(scalar)
rank 0...
rank 1
tensor
(vector)
rank 1...
rank 2
tensor
(matrix)
rank 2...
rank 3
tensor
rank 3...
i
i
j
j
i
k
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/_static/xanadu_gallery.css b/docs/_static/xanadu_gallery.css new file mode 100644 index 00000000..109822f3 --- /dev/null +++ b/docs/_static/xanadu_gallery.css @@ -0,0 +1,239 @@ + +/* +Sphinx-Gallery has compatible CSS to fix default sphinx themes +Tested for Sphinx 1.3.1 for all themes: default, alabaster, sphinxdoc, +scrolls, agogo, traditional, nature, haiku, pyramid +Tested for Read the Docs theme 0.1.7 */ +.sphx-glr-thumbcontainer { + background: #fff; + border: solid #dedede 0px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + box-shadow: 0 2px 5px 0 rgba(0,0,0,.05),0 2px 25px 2px rgba(0,0,0,.08); + float: left; + margin: 5px; + min-height: 230px; + padding-top: 5px; + position: relative; + text-align: center; + border-radius: 10px; + transition: 0.5s cubic-bezier(0.25, 0.1, 0.25, 1); +} +.sphx-glr-thumbcontainer:hover { + border: solid #b4ddfc 0px; + box-shadow: 0 2px 5px 0 rgba(0,0,0,.05),0 2px 25px 2px rgba(0,0,0,.2); + transition: 0.5s cubic-bezier(0.25, 0.1, 0.25, 1); +} +/*.sphx-glr-thumbcontainer:hover > .figure > img {*/ + /*transform: scale(1.08);*/ + /*transition: 0.5s cubic-bezier(0.25, 0.1, 0.25, 1);*/ +/*}*/ + + +.sphx-glr-thumbcontainer a.internal { + bottom: 0; + display: block; + left: 0; + padding: 150px 10px 0; + position: absolute; + right: 0; + top: 0; + color: #575757; +} + +/* Next one is to avoid Sphinx traditional theme to cover all the +thumbnail with its default link Background color */ +.sphx-glr-thumbcontainer a.internal:hover { + background-color: transparent; + color: #575757; + text-decoration: none; +} + +.sphx-glr-thumbcontainer p { + margin: 0 0 .1em 0; +} +.sphx-glr-thumbcontainer .figure { + margin: 10px; + width: 160px; +} +.sphx-glr-thumbcontainer img { + display: inline; + max-height: 160px; + width: 160px; +} +.sphx-glr-thumbcontainer[tooltip]:hover:after { + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + color: #fff; + content: attr(tooltip); + left: 95%; + padding: 5px 15px; + position: absolute; + z-index: 98; + width: 220px; + bottom: 52%; + display: none; +} +.sphx-glr-thumbcontainer[tooltip]:hover:before { + border: solid; + border-color: #333 transparent; + border-width: 18px 0 0 20px; + bottom: 58%; + content: ''; + left: 85%; + position: absolute; + z-index: 99; + display: none; +} + +.highlight-pytb pre { + background-color: #ffe4e4; + border: 1px solid #f66; + margin-top: 10px; + padding: 7px; +} + +.sphx-glr-script-out { + color: #888; + margin: 0; +} +.sphx-glr-script-out .highlight { + background-color: transparent; + margin-left: 2.5em; + margin-top: -1.4em; +} +.sphx-glr-script-out .highlight pre { + background-color: #fafae2; + border: 0; + max-height: 30em; + overflow: auto; + padding-left: 1ex; + margin: 0px; + word-break: break-word; +} +.sphx-glr-script-out + p { + margin-top: 1.8em; +} +blockquote.sphx-glr-script-out { + margin-left: 0pt; +} + +div.sphx-glr-footer { + text-align: center; + margin-bottom: -40px; +} + +div.binder-badge { + margin: 1em auto; + vertical-align: middle; +} + +div.sphx-glr-download { + margin: 1em auto; + vertical-align: middle; +} + +div.sphx-glr-download a { + background-color: #fff; + background-image: none; + border-radius: 0px; + border-bottom: 1px solid #c2c22d; + color: #000; + display: inline-block; + font-weight: bold; + padding: 0ex; + text-align: center; + border: none; +} + +div.sphx-glr-download code.download { + display: inline; + white-space: normal; + word-break: normal; + overflow-wrap: break-word; + border: none; + background: none; + font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; + +} + +div.sphx-glr-download a:hover { + box-shadow: none; + text-decoration: none; + background-image: none; + background-color: #fff; + border-bottom: 1px solid #405c4d; +} + +.sphx-glr-example-title > :target::before { + display: block; + content: ""; + margin-top: -50px; + height: 50px; + visibility: hidden; +} + +ul.sphx-glr-horizontal { + list-style: none; + padding: 0; +} +ul.sphx-glr-horizontal li { + display: inline; +} +ul.sphx-glr-horizontal img { + height: auto !important; +} + +.sphx-glr-single-img { + margin: auto; + display: block; + max-width: 100%; +} + +.sphx-glr-multi-img { + max-width: 42%; + height: auto; +} + +p.sphx-glr-signature a.reference.external { + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + padding: 3px; + font-size: 75%; + text-align: right; + margin-left: auto; + display: table; +} +.sphx-glr-download-link-note { + display: none; +} + +.container { + width: unset; +} + +.sphx-glr-script-out .highlight pre { + background-color: #f7f7f7; +} + + +#tutorial-type { + display: none; +} + + +.sphx-glr-download-link-note.admonition.note, +.sphx-glr-signature { + display: none; +} + +.sphx-glr-timing { + margin-bottom: 40px; + margin-top: 20px; + text-align: center; + font-size: small; +} \ No newline at end of file diff --git a/docs/_static/xanadu_x.svg b/docs/_static/xanadu_x.svg new file mode 100755 index 00000000..b8ef5649 --- /dev/null +++ b/docs/_static/xanadu_x.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..fb7364ec --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Jet documentation build configuration file, created by +# sphinx-quickstart on Fri Sep 8 14:44:21 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import inspect +import os +import re +import sys + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath("..")) +sys.path.insert(0, os.path.abspath("_ext")) +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(".")), "docs")) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = "1.5" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "breathe", + "edit_on_github", + "exhale", + "m2r2", + "nbsphinx", + "sphinx_copybutton", + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.coverage", + "sphinx.ext.mathjax", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "sphinxcontrib.bibtex" +] + +bibtex_bibfiles = [] + +autosummary_generate = True +autosummary_imported_members = False + +exclude_patterns = ["_build", "**.ipynb_checkpoints"] +nbsphinx_execute = "never" +nbsphinx_epilog = """ +.. note:: :download:`Click here <../{{env.docname}}.ipynb>` to download this gallery page as an interactive Jupyter notebook. +""" + +# Setup the breathe extension +breathe_projects = {"Jet": "./doxyoutput/xml"} +breathe_default_project = "Jet" + +# Setup the exhale extension +exhale_args = { + # These arguments are required + "containmentFolder": "./api", + "rootFileName": "library_root.rst", + "rootFileTitle": "Overview", + "doxygenStripFromPath": "..", + # Suggested optional arguments + "createTreeView": True, + # TIP: if using the sphinx-bootstrap-theme, you need + # "treeViewIsBootstrap": True, + "exhaleExecutesDoxygen": True, + "exhaleDoxygenStdin": ( + "INPUT = " + "../include/Jet.hpp " + "../include/jet/Abort.hpp " + "../include/jet/PathInfo.hpp " + "../include/jet/TaskBasedCpuContractor.hpp " + "../include/jet/Tensor.hpp " + "../include/jet/TensorNetwork.hpp " + "../include/jet/TensorNetworkIO.hpp " + "../include/jet/Utilities.hpp " + "../include/jet/Version.hpp" + ), + "afterTitleDescription": inspect.cleandoc( + """ + Jet is provided as a C++ header-only library, :download:`Jet.hpp <../../include/Jet.hpp>`, which can be included at the top of your source file: + + .. code-block:: cpp + + #include + """ + ), +} + +# Tell sphinx what the primary language being documented is. +primary_domain = "cpp" + +# Tell sphinx what the pygments highlight language should be. +highlight_language = "cpp" + +mathjax_path = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" +nbsphinx_requirejs_path = "" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates", "xanadu_theme"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "Jet" +copyright = "2021, Xanadu Quantum Technologies Inc" +author = "Xanadu Inc." + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The full version, including alpha/beta/rc tags. +release = "0.1.0" + +# The short X.Y version. +version = re.match(r"^(\d+\.\d+)", release).expand(r"\1") + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = "%Y-%m-%d" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ["_build"] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +add_module_names = False + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +show_authors = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# html_theme = 'nature' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = "_static/favicon.ico" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# This is required for the alabaster theme +# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars +# html_sidebars = { +# '**': [ +# 'about.html', +# 'navigation.html', +# 'relations.html', # needs 'show_related': True theme option to display +# 'searchbox.html', +# 'donate.html', +# ] +# } +html_sidebars = { + "**": [ + "logo-text.html", + "searchbox.html", + "globaltoc.html", + # 'sourcelink.html' + ] +} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = "jetsdoc" + +# # -- Xanadu theme --------------------------------------------------------- +html_theme = "xanadu_theme" +html_theme_path = ["."] + +# Register the theme as an extension to generate a sitemap.xml +# extensions.append("guzzle_sphinx_theme") + +# xanadu theme options (see theme.conf for more information) +html_theme_options = { + # Set the path to a special layout to include for the homepage + # "homepage": "special_index.html", + # Set the name of the project to appear in the left sidebar. + "project_nav_name": "Jet", + "touch_icon": "_static/logo_new.png", + # TODO: Set Google Analytics ID to enable tracking. + # "google_analytics_account": "UA-116279123-2", + # colors + "navigation_button": "#5e35b1", + "navigation_button_hover": "#320b86", + "toc_caption": "#7e57c2", + "toc_hover": "#7e57c2", + "table_header_bg": "#ffdce5", + "table_header_border": "#7e57c2", + "download_button": "#7e57c2", +} + +edit_on_github_project = "XanaduAI/jet" +edit_on_github_branch = "master/docs" + + +def setup(app): + app.add_css_file("xanadu_gallery.css") diff --git a/docs/dev/guide.rst b/docs/dev/guide.rst new file mode 100644 index 00000000..dfbf451b --- /dev/null +++ b/docs/dev/guide.rst @@ -0,0 +1,277 @@ +Development guide +================= + +Dependencies +------------ + +Jet requires the following libraries be installed: + +* `Taskflow `_ >= 3.1.0 +* BLAS library with support for the C API (CBLAS interface) +* C++ compiler with C++17 support (GCC >= 7, clang >= 5, Intel icpc >= 19.0.1) +* [Optional] MPI library (OpenMPI >= 3.0, MPICH >= 3.0) +* [Optional] CMake >=3.14 + +Installation +------------ + +For development purposes, a few additional dependencies are required. +For the examples below, we will use OpenBLAS as the BLAS library. +Please choose whichever option below best suits your system: + +.. code-block:: bash + + # Ubuntu installation + sudo apt-get install libopenblas-dev + + # CentOS/RedHat/Fedora + sudo yum install openblas openblas-devel + + # Custom OpenBLAS installation + git clone https://github.com/xianyi/OpenBLAS + cd OpenBLAS && make && sudo make install + +We also require the header-only library Taskflow: + +.. code-block:: bash + + git clone https://github.com/taskflow/taskflow + export TASKFLOW=$PWD/taskflow + +Finally, to install Jet: + +.. code-block:: bash + + git clone https://github.com/XanaduAI/jet + export JET=$PWD/jet/include + +You are now ready to build your first Jet program! + +.. _ex1-section: + +Example (Hello World) +--------------------- + +Let us create a file called `ex1.cpp` as: + +.. code-block:: cpp + + #include + #include + #include "Jet.hpp" + + int main(){ + using namespace Jet; + + Tensor> t0({"i", "j", "k"}, {2, 2, 2}); + Tensor> t1({"j", "k", "l"}, {2 ,2, 2}); + + t0.FillRandom(); + t1.FillRandom(); + + Tensor t2 = ContractTensors(t0, t1); + + for (auto &d : t2.GetData()) + std::cout << d << std::endl; + + std::cout << "You have successfully used Jet version " << Version() << std::endl; + + return 0; + } + +To compile this example, and verify Jet works on your machine, you can build with the following command (assuming GCC): + +.. code-block:: bash + + g++ --std=c++17 -O3 -I$JET -I$TASKFLOW -lopenblas ./ex1.cpp -o ex1 + +Running the example should produce output similar to: + +.. code-block:: text + + $ ./ex1 + (0.804981,0) + (1.53207,0) + (0.414398,0) + (0.721263,0) + You have successfully used Jet version 0.1.0 + +Congratulations, you have successfully run your first Jet program! + + +Example (CMake Project) +----------------------- + +.. note:: CMake is required to build this project example. + +Now that we can run a simple single-file example, we can build upon this and run a larger-scale +project example. We now build a CMake-enabled project that explictly depends on Jet. + +Begin by creating a directory for our project and adding our example code from :ref:`Example 1` as well as a `CMakeLists.txt` file: + +.. code-block:: bash + + mkdir my_project + cd my_project + touch ./ex1.cpp + touch CMakeLists.txt + +The purpose of our `CMakeLists.txt` file is to label our project, define its dependencies, acquire them, and ensure all paths are set to compile our program. Copy the following block into the `CMakeLists.txt` file: + +.. code-block:: cmake + + ############################# + ## I. Set project details + ############################# + cmake_minimum_required(VERSION 3.14) + + project("MyProject" + VERSION 0.1.0 + DESCRIPTION "A sample Jet project" + LANGUAGES CXX C + ) + + ############################# + ## II. Fetch Jet project + ############################# + + Include(FetchContent) + + FetchContent_Declare( + Jet + GIT_REPOSITORY https://github.com/XanaduAI/jet.git + GIT_TAG v0.1.0 + ) + FetchContent_MakeAvailable(Jet) + + ############################# + ## III. Create project target + ############################# + + add_executable(my_jet_project ex1.cpp) + target_link_libraries(my_jet_project Jet) + +Section `I.` sets up your project with a given name, source-code type, and version information. + +Section `II.` labels Jet as an external project to fetch, and will automatically pull the repository, as well as set up all of the Jet dependencies. + +Section `III.` defines an executable for your project, and sets Jet as a dependency of it. This will ensure all headers and libraries are available at compile-time. You can now build your project with the following code-block: + +.. code-block:: bash + + cmake . + make + ./my_jet_project + +The output will be the same as :ref:`Example 1`. Congratulations, you have now built a project with Jet as a dependency! + +Performance optimization +------------------------ + +Jet has several options for improving the performance of your application. They can be enabled from the CMake builder using the following flags: + +* :code:`-DENABLE_OPENMP=on` : Jet uses shared-memory parallelism via OpenMP where applicable. +* :code:`-DENABLE_NATIVE=on` : Jet compiles all code targetted specifically for your CPU architecture. +* :code:`-DENABLE_IPO=on` : Jet will compile with inter-procedural (link-time) optimisation. + +For example, to enable the OpenMP and native architecture options with CMake, you may use the following: + +.. code-block:: bash + + cmake . -DENABLE_OPENMP=on -DENABLE_NATIVE=on + +Any project that depends on Jet will now also be built using these options. Try combining these in various ways to determine the options best suited for your system. + +Similarly, Jet features support to find the best available BLAS library on your system. If you wish to use a different BLAS library than what is found, please ensure your required BLAS library is available on your path. + +.. _test-section: + +Tests +----- + +.. note:: CMake is required to build the test suite, which uses the `Catch2 `_ testing framework. + + +To ensure that Jet is working correctly after installation, the test suite can +be run by creating a top-level ``build/`` directory in the Jet repository and running + +.. code-block:: bash + + cd build + cmake .. -DBUILD_TESTS=ON + make + ./test/runner + +All available tests for Jet will be run, with output similar to + +.. code-block:: text + + =============================================================================== + All tests passed (414 assertions in 64 test cases) + + +To see all test options, run + +.. code-block:: bash + + ./test/runner --help + +Format +------ + +Contributions are checked for format alignment in the pipeline. Changes can be +formatted locally using: + +.. code-block:: bash + + ./bin/format include test + +All files within the listed directories will be modified to fit the expected format, if required. + +Documentation +------------- + +A few Python packages are required to build the documentation, as specified in +``docs/requirements.txt``. These packages can be installed using: + +.. code-block:: bash + + pip install -r docs/requirements.txt + +To build the HTML documentation, change into the ``docs/`` folder and run + +.. code-block:: bash + + make html + +The documentation can then be found in the :file:`docs/_build/html/` directory. + +Submitting a pull request +------------------------- + +Before submitting a pull request, please make sure the following is done: + +* **All new features must include a unit test.** If you've fixed a bug or added + code that should be tested, add a test to the ``test/`` directory. + +* **All new functions and code must be clearly commented and documented.** + + Have a look through the source code at some of the existing functions --- + the easiest approach is to simply copy an existing Doxygen comment and modify + it as appropriate. + + If you do make documentation changes, make sure that the docs build and render + correctly by running ``cd docs && make html``. + +* **Ensure that the test suite passes**, by following the :ref:`test suite guide`. + +When ready, submit your fork as a `pull request `_ +to the Jet repository, filling out the pull request template. This template is +added automatically to the comment box when you create a new issue. + +* When describing the pull request, please include as much detail as possible + regarding the changes made/new features added/performance improvements. If + including any bug fixes, mention the issue numbers associated with the bugs. + +* Once you have submitted the pull request, the **test suite** will + automatically run on CircleCI to ensure that all tests continue to pass. diff --git a/docs/dev/releases.rst b/docs/dev/releases.rst new file mode 100644 index 00000000..e5fec49a --- /dev/null +++ b/docs/dev/releases.rst @@ -0,0 +1,6 @@ +Release notes +============= + +This page contains the release notes for Jet. + +.. mdinclude:: ../../.github/CHANGELOG.md diff --git a/docs/dev/research.rst b/docs/dev/research.rst new file mode 100644 index 00000000..483f8051 --- /dev/null +++ b/docs/dev/research.rst @@ -0,0 +1,30 @@ +Research and contribution +========================= + +Research +-------- + +We are always open for collaboration, and can be contacted at research@xanadu.ai. + +Contribution +------------- + +Jet is an open-source library, with the up-to-date code available on GitHub: + +- **Source Code:** https://github.com/XanaduAI/jet +- **Issue Tracker:** https://github.com/XanaduAI/jet/issues + +We welcome contributions - simply fork the Jet repository, and then make a +`pull request `_ containing +your contribution. All contributers to Jet will be listed as authors on the +releases. + +We also encourage bug reports, suggestions for new features and enhancements, +and even links to cool projects or applications built on Jet. + +Support +------- + +If you are having issues, please let us know by posting the issue on our GitHub issue tracker. + +Sometimes, it might take us a couple of hours to reply - please be patient! diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..f6c6c057 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,146 @@ +Jet Documentation +################# + +.. rst-class:: lead grey-text ml-2 + +:Release: |release| + +.. raw:: html + + +
+ + +Features +======== + +* *Heterogeneous.* Runs on a **variety of systems**, from single-board machines to massively parallel supercomputers. + +.. + +* *Speed.* Accelerates tensor contractions using a novel **task-based parallelism** approach. + +.. + +* *Qudits.* Models quantum systems with an **arbitrary number of basis states**. + +Support +======= + +- **Source Code:** https://github.com/XanaduAI/Jet +- **Issue Tracker:** https://github.com/XanaduAI/Jet/issues + +If you are having issues, please let us know, either by email or by posting the +issue on our GitHub issue tracker. + +License +======= + +The Jet library is **free** and **open source**, released under the Apache, +Version 2.0. + +.. toctree:: + :maxdepth: 2 + :caption: Using Jet + :hidden: + + use/introduction + use/tensors + use/tensor_networks + use/tensor_network_files + +.. toctree:: + :maxdepth: 2 + :caption: Development + :hidden: + + dev/guide + dev/research + dev/releases + + +.. toctree:: + :maxdepth: 2 + :caption: API + :hidden: + + Overview + Jet + Jet::PathInfo + Jet::TaskBasedCpuContractor + Jet::Tensor + Jet::TensorNetwork + Jet::TensorNetworkSerializer + Jet::Utilities \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..cdc870c1 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,13 @@ +breathe==4.29.0 +docutils<0.17 +exhale +ipykernel +m2r2 +nbsphinx +repoze.lru>=0.7 +scipy>=1.2.1 +sphinx-copybutton +sphinx==3.5.4 +sphinxcontrib-bibtex +sympy>=1.5.1 +version_information diff --git a/docs/use/introduction.rst b/docs/use/introduction.rst new file mode 100644 index 00000000..fd3fccd9 --- /dev/null +++ b/docs/use/introduction.rst @@ -0,0 +1,38 @@ +Introduction +============ + +.. image:: ../_static/666.png + :align: right + :width: 200px + :target: javascript:void(0); + +Jet is an open-source tensor network contraction engine which aims to support +the following workflows: + +* Simulate discrete and continuous-variable quantum circuits. + +* Estimate the memory and computational requirements of a simulation. + +* Contract tensor networks with customizable precision and GPU acceleration. + +Follow the `development guide <../dev/guide.html>`_ to get Jet up and running +and then have a look at the quickstart tutorials to see what you can do with Jet. + +Quickstart guides +----------------- + +The following sections outline the key features of Jet: + +1. :doc:`tensors` offers a gentle introduction to tensors and how they are + modeled in Jet. Learn about tensor notation and contractions here. + +.. + +2. :doc:`tensor_networks` provides an overview of tensor networks and how Jet + leverages task-based parallelism to contract tensor networks concurrently. + +.. + +3. :doc:`tensor_network_files` shows how to serialize and deserialize tensor + networks. This section details how to use the Jet serializer and presents + a formal specification of the tensor network file format. diff --git a/docs/use/tensor_network_files.rst b/docs/use/tensor_network_files.rst new file mode 100644 index 00000000..f3453a49 --- /dev/null +++ b/docs/use/tensor_network_files.rst @@ -0,0 +1,110 @@ +Tensor network files +==================== + +Jet defines and provides tools for saving and loading tensor +networks to/from JSON strings. + +Tensor networks are represented as JSON objects with a 'tensors' key, +which contains a list of tensors with labeled indices, and an optional +'path' key describing a contraction path through those tensors. + +Tensors are represented as a tuple of 4 elements: + +* **tags**: a list of string tags +* **indices**: a list of string labels for each index +* **shape**: a list of integers containing the dimension of each index +* **data**: an array containing the unshaped complex data of the tensor, in row-major order. Complex numbers are represented using 2-element arrays ``[real, imaginary]`` + +Saving and loading are both handled by the :doc:`TensorNetworkSerializer ` class. +Like the :doc:`TensorNetwork ` class, the +``TensorNetworkSerializer`` class is templated by a ``Tensor`` type and +can serialize or deserialize any valid ``TensorNetwork`` instance. + +An ``invalid_tensor_file`` exception will be thrown when a string cannot +be parsed as JSON, or does not encode a valid tensor network. + + +Example +------- + +The following C++ program demonstrates creating a tensor network and dumping it +to a JSON string. First, create a simple network of three tensors with a +contraction path and initialize the serializer: + +.. code-block:: cpp + + #include + #include + #include + + #include + + int main(){ + using Tensor = Jet::Tensor>; + + Jet::TensorNetwork tn; + + Tensor A({"i", "j"}, {2, 2}, {{1, 0}, {0, 1}, {0, -1}, {1, 0}}); + tn.AddTensor(A, {"A", "hermitian"}); + + Tensor B({"j", "k"}, {2, 2}, {{1, 0}, {0, 0}, {0, 0}, {1, 0}}); + tn.AddTensor(B, {"B", "identity", "real"}); + + Tensor C({"k"}, {2}, {{1,0}, {0, 0}}); + tn.AddTensor(C, {"C", "vec", "real"}); + + Jet::PathInfo path(tn, {{0, 2}, {2, 1}}); + + Jet::TensorNetworkSerializer serializer(); + ... + + +Serialization +------------- +To serialize, call the serializer with a tensor network (and an optional path): + +.. code-block:: cpp + + ... + + std::string tn_json = serializer(tn, path); + std::cout << tn_json; + + +The output of this program will be: + +.. code-block:: json + + { + "path": [[0, 2], [2, 1]], + "tensors": [ + [["A", "hermitian"], ["i", "j"], [2, 2], [[1, 0], [0, 1], [0, -1], [1, 0]]], + [["B", "identity", "real"], ["j", "k"], [2, 2], [[1, 0], [0, 0], [0, 0], [1, 0]]], + [["C", "vec", "real"], ["k"], [2], [[1, 0], [0, 0]]] + ] + } + + +Deserialization +--------------- +To deserialize a tensor network, call the serializer with a string: + +.. code-block:: cpp + + ... + + std::string tn_json = serializer(tn_path); + + TensorNetworkFile tensor_file = serializer(tn_json); + + Jet::TensorNetwork tn_copy = tensor_file.tensors; + Jet::PathInfo path_copy = tensor_file.path.value(); // uses std::optional + + + +JSON Schema +----------- + +:download:`Download ` + +.. literalinclude:: /_static/schema/tensor_network.json diff --git a/docs/use/tensor_networks.rst b/docs/use/tensor_networks.rst new file mode 100644 index 00000000..a7f9c58f --- /dev/null +++ b/docs/use/tensor_networks.rst @@ -0,0 +1,276 @@ +Tensor networks +=============== +.. |br| raw:: html + +
+ +A **tensor network** is a graph where each node represents a tensor and each +edge represents a shared index between tensors. In the `Tensor `_ +section, it was shown that a tensor can be graphically modelled as a circle with +a leg for each index of the tensor. It follows that a tensor network can be +represented as a collection of circles and lines where stray legs denote free +indices: + +|br| + +.. image:: ../_static/tensor_network_example.svg + :width: 400 + :alt: Example of a tensor network. + :align: center + +|br| + +One of the key operations that can be performed over a tensor network is a +*contraction*. Local contractions are discussed in the `Tensor `_ +section and combine two tensors which share at least one index in a tensor +network. Global contractions reduce a tensor network to a single node by +iteratively performing local contractions until all of the edges in the tensor +network are consumed. For example: + +|br| + +.. image:: ../_static/tensor_network_contraction_example.svg + :width: 600 + :alt: Example of a tensor network contraction. + :align: center + +|br| + +Above, the result of the tensor network contraction is the node :math:`E`. +Observe that :math:`E` was produced by first contracting nodes :math:`C` and +:math:`D` to create node :math:`CD`, then contracting node :math:`CD` with +node :math:`B` to generate node :math:`BCD`, and then finally contracting node +:math:`BCD` with node :math:`A`. Here, nodes :math:`CD` and :math:`BCD` are +*intermediary tensors* and the order of contractions is summarized by the +contraction path + +.. math:: + + P = \{(C, D), (CD, B), (BCD, A)\}\,. + +In general, the contraction path of a tensor network is not unique and has a +significant impact on the memory requirements and running time of a tensor +network contraction. + +Modelling quantum circuits +-------------------------- + +Although tensor networks are pure mathematical objects, they are often used to +model and simulate quantum circuits. For example, consider the following +circuit which generates an EPR pair from two unentangled :math:`\vert 0 \rangle` +qubits: + +|br| + +.. image:: ../_static/tensor_network_bell_state_circuit.svg + :width: 600 + :alt: Diagram of a circuit that generates an EPR pair. + :align: center + +|br| + +This circuit can be directly modelled with the following tensor network: + +|br| + +.. image:: ../_static/tensor_network_bell_state_network.svg + :width: 300 + :alt: Tensor network modelling the EPR pair quantum circuit. + :align: center + +|br| + +To construct this tensor network in Jet, it is necessary to first define each +of the consituent tensors using the ``Tensor`` class. Recall that: + +.. math:: + + \vert 0 \rangle = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \qquad H = \begin{bmatrix} \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \end{bmatrix} \qquad CNOT = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \end{bmatrix} \,. + +The :math:`\vert 0 \rangle` qubits are relatively simple to create: + +.. code-block:: cpp + + // The control qubit is defined as a 1-D vector with 2 elements. + Tensor q0({"i"}, {2}, {1, 0}); + + // Note that the index of `q1` differs from `q0`. + Tensor q1({"j"}, {2}, {1, 0}); + +The Hadamard gate :math:`H` can also be constructed in the usual way: + +.. code-block:: cpp + + constexpr float inv_sqrt_2 = 1 / std::sqrt(2); + Tensor H({"i", "k"}, {2, 2}, {inv_sqrt_2, inv_sqrt_2, + inv_sqrt_2, -inv_sqrt_2}); + +The controlled NOT gate :math:`CNOT` is slightly trickier. From the diagram, +:math:`CNOT \in \mathbb{C}^{2 \times 2 \times 2 \times 2}`. To derive this +:math:`CNOT` tensor, note that a two-qubit state +:math:`\vert \psi \rangle \in \mathbb{C}^{4}` can be encoded as a +:math:`\mathbb{C}^{2 \times 2}` matrix: + +.. math:: + + \vert \psi \rangle = \alpha_{00} \vert 00 \rangle + \alpha_{01} \vert 01 \rangle + \alpha_{10} \vert 10 \rangle + \alpha_{11} \vert 11 \rangle = \begin{bmatrix} \alpha_{00} & \alpha_{01} \\ \alpha_{10} & \alpha_{11} \end{bmatrix}\,. + +It follows that + +.. math:: + + CNOT_{0, 0} = \begin{bmatrix} 1 & 0 \\ 0 & 0 \end{bmatrix} \quad + CNOT_{0, 1} = \begin{bmatrix} 0 & 1 \\ 0 & 0 \end{bmatrix} \quad + CNOT_{1, 0} = \begin{bmatrix} 0 & 0 \\ 0 & 1 \end{bmatrix} \quad + CNOT_{1, 1} = \begin{bmatrix} 0 & 0 \\ 1 & 0 \end{bmatrix}\,. + +The :math:`CNOT` gate is then given by + +.. code-block:: cpp + + Tensor CNOT({"m", "n", "j", "k"}, {2, 2, 2, 2}); + CNOT.SetValue({0, 0, 0, 0}, 1); + CNOT.SetValue({0, 1, 1, 0}, 1); + CNOT.SetValue({1, 1, 0, 1}, 1); + CNOT.SetValue({1, 0, 1, 1}, 1); + +Now, creating the tensor network is easy with the ``TensorNetwork`` class: + +.. code-block:: cpp + + TensorNetwork>> tn; + // The second argument can be used to associated a tensor with a set of tags. + tn.AddTensor(q0, {}); + tn.AddTensor(q1, {}); + tn.AddTensor(H, {}); + tn.AddTensor(CNOT, {}); + +By default, the ``TensorNetwork`` class performs contractions in random order: + +.. code-block:: cpp + + tn.Contract(); + +An explicit contraction path can also be specified by providing a list of pair +of node IDs (0-indexed) to the ``Contract()`` function. The ID of a node is the +order in which it was added to the tensor network. Intermediate tensors are +assigned node IDs according to SSA convention (i.e., they are assigned the node +ID immediately following the largest node ID in the tensor network in use at the +time the intermediate tensor was created). + +.. code-block:: cpp + + tn.Contract({{0, 2}, {1, 3}, {4, 5}}); + +Putting it all together, + +.. code-block:: cpp + + #include + #include + #include + + #include "Jet.hpp" + + int main() { + using namespace Jet; + + Tensor q0({"i"}, {2}, {1, 0}); + Tensor q1({"j"}, {2}, {1, 0}); + + constexpr float inv_sqrt_2 = 1 / std::sqrt(2); + Tensor H({"i", "k"}, {2, 2}, {inv_sqrt_2, inv_sqrt_2, + inv_sqrt_2, -inv_sqrt_2}); + + Tensor CNOT({"m", "n", "j", "k"}, {2, 2, 2, 2}); + CNOT.SetValue({0, 0, 0, 0}, 1); + CNOT.SetValue({0, 1, 0, 1}, 1); + CNOT.SetValue({1, 0, 1, 1}, 1); + CNOT.SetValue({1, 1, 1, 0}, 1); + + TensorNetwork>> tn; + tn.AddTensor(q0, {}); + tn.AddTensor(q1, {}); + tn.AddTensor(H, {}); + tn.AddTensor(CNOT, {}); + + // Returns the node with the greatest ID in the tensor network. + Tensor result = tn.Contract(); + + std::cout << "|00> = " << result.GetValue({0, 0}) << std::endl; + std::cout << "|01> = " << result.GetValue({0, 1}) << std::endl; + std::cout << "|10> = " << result.GetValue({1, 0}) << std::endl; + std::cout << "|11> = " << result.GetValue({1, 1}) << std::endl; + + return 0; + }; + +The output of the program is + +.. code-block:: text + + |00> = (0.707107,0) + |01> = (0,0) + |10> = (0,0) + |11> = (0.707107,0) + +Task-based contraction +---------------------- + +While ``TensorNetwork::Contract()`` is simple to use, it is unlikely to exhibit +optimal performance for large tensor networks. One alternative to the vanilla +tensor network contractor is the ``TaskBasedCpuContractor`` class which models a +tensor network contraction as a parallel task scheduling problem where each task +encapsulates a local tensor contraction. Such a formulation enables +intermediate tensors which do not depend on each another to be contracted +concurrently. As an example, consider the task graph for the quantum circuit +described in the previous section: + +|br| + +.. image:: ../_static/tensor_network_task_graph.svg + :width: 500 + :alt: Task graph for the EPR pair quantum circuit. + :align: center + +|br| + +Clearly, the leftmost nodes in the top row (:math:`\vert 0 \rangle` and +:math:`CNOT`) may be contracted in parallel with the rightmost nodes in the +top row (the other :math:`\vert 0 \rangle` and :math:`H`); however, the +contraction representing the final output of the circuit may only be performed +once nodes :math:`A_k` and :math:`B_{m,n,k}` have been computed. + +Despite its underlying complexity, the interface to ``TaskBasedCpuContractor`` +is relatively straightforward. After constructing the ``TensorNetwork`` in the +previous section, the contraction path is specified using a ``PathInfo`` object: + +.. code-block:: cpp + + PathInfo path_info(tn, {{0, 2}, {1, 3}, {4, 5}}); + +The contraction tasks can then be added to a new ``TaskBasedCpuContractor`` +instance: + +.. code-block:: cpp + + TaskBasedCpuContractor>> tbcc; + tbcc.AddContractionTasks(tn, path_info); + +Finally, ``TaskBasedCpuContractor::Contract()`` launches the contraction and +returns a future that becomes available when the contraction is complete: + +.. code-block:: cpp + + // Start the tensor network contraction and wait for it to finish. + auto future = tbcc.Contract(); + future.wait(); + + // Each call to AddContractionTasks() generates a new result. + const auto results = tbcc.GetResults(); + const auto result = results[0]; + +.. note:: + + Currently, ``TaskBasedCpuContractor`` expects the final contraction of a + tensor network to be a scalar. This may change in a future release of Jet. diff --git a/docs/use/tensors.rst b/docs/use/tensors.rst new file mode 100644 index 00000000..dcbe07aa --- /dev/null +++ b/docs/use/tensors.rst @@ -0,0 +1,180 @@ +Tensors +======= + +.. |br| raw:: html + +
+ +**Tensors** can be described as multi-dimensional arrays, where the dimension is called the *rank*. A tensor of rank 0 is a scalar, a tensor of rank 1 is a vector and a tensor of rank 2 is a matrix, but in general tensors can have arbitrary rank. Visually, tensors are usually represented as circles with legs: + +|br| + +.. image:: ../_static/tensors.svg + :width: 600 + :alt: Example of tensors from rank 0 to rank 3 + :align: center + +|br| + +To build the following examples, please read the `installation instructions `_. + +|br| + +In Jet we can create these four different tensors easily in a simple C++ program: + +.. code-block:: cpp + + #include "Jet.hpp" + + int main() { + using namespace Jet; + + Tensor A; // a scalar + Tensor B({"i"}, {2}); // a vector, with index i and size 2 + Tensor C({"i","j"},{4,3}); // a matrix, with indices i,j and size 4x3 + Tensor D({"i","j","k"},{3,2,4}); // a rank 3 tensor, with indices i,j,k, and size 3x2x4 + + //Fill the tensors with random values + A.FillRandom(); + B.FillRandom(); + C.FillRandom(7); // Seed RNG with value + D.FillRandom(7); // Seed RNG with same value + + return 0; + }; + + +For any given tensor, each leg corresponds to an index variable (:math:`i, j, k,` etc). The power of the tensor representation comes from the intuitive way it expresses problems. Let us take a rank 2 tensor (i.e., a matrix) of size 2x2 as an example. + +|br| + +.. math:: + + M_{i,j}=\begin{bmatrix} + m_{0,0} & m_{0,1} \\ + m_{1,0} & m_{1,1} \\ + \end{bmatrix} + +|br| + +Here, we can showcase the various constructors offered by the ``Tensor`` class, allowing you to choose whichever best suits your needs. + +.. code-block:: cpp + + /// Create a tensor with single datum of complex {0.0, 0.0} + Tensor M0; + + /// Create a 3x2 tensor, with automatically labeled indices, and data zero-initialised + Tensor M1({3,2}); + + /// Create a 2x3x2 tensor, with labeled indices (i,j,k), and data zero-initialised + Tensor M2({"i","j","k"}, {2,3,2}); + + /// Create a copy of the M2 2x3x2 tensor + Tensor M3(M2); + + /// Create a 2x2 tensor, with labeled indices (i,j), + /// and data as provided in row-major encoding + Tensor M4({"i","j"}, {2,2}, {{0,0}, {1,0}, {1,0}, {0,0}}); + +|br| + +Let us now generate a few familiar rank 2 tensors, the Pauli operators, using the ``Tensor`` class. + +.. code-block:: cpp + + std::vector size {2,2}; + std::vector indices {"i","j"}; + + std::vector> pauli_x_data { {0,0}, {1,0}, {1,0}, {0,0} }; + std::vector> pauli_y_data { {0,0}, {0,-1}, {0,1}, {0,0} }; + std::vector> pauli_z_data { {1,0}, {0,0}, {0,0}, {-1,0} }; + + Tensor X(indices, size, pauli_x_data); + Tensor Y(indices, size, pauli_y_data); + Tensor Z(indices, size, pauli_z_data); + + +The two indices :math:`i,j`, allow us to label the axes of the matrices. This notation easily allows operations like matrix-vector and matrix-matrix products to generalize for arbitrary dimensions. As an example, a matrix-vector product, described by notation: + +.. math:: + + L=\displaystyle\sum\limits_{j} M_{i,j} N_j =\begin{bmatrix} + m_{0,0} & m_{0,1} \\ + m_{1,0} & m_{1,1} \\ + \end{bmatrix} + \begin{bmatrix} + n_0 \\ + n_1 + \end{bmatrix}= + \begin{bmatrix} + m_{0,0}n_0 + m_{0,1}n_1 \\ + m_{1,0}n_0 + m_{1,1}n_1 \\ + \end{bmatrix} + +|br| + +can be expressed in graphical notation as: + +|br| + +.. image:: ../_static/tensor_matvec.svg + :width: 500 + :alt: Matrix-vector product + :align: center + +|br| + +The above demonstrates a unique property of tensors: by connecting legs with shared indices, we can perform Einstein summation over the shared indices. After this index *contraction*, the resulting tensor is formed with indices that did not participate in the operation. For the above example, over a shared index :math:`j`, the tensors :math:`M_{i,j}` and :math:`N_j` form a new rank 1 tensor, :math:`L_i`. + +|br| + +Taking our Pauli operators from earlier, we can use this tensor representation to describe operations on quantum states, just as one would with a quantum circuit. +Expanding on the above, we now aim to calculate an expectation value of Pauli-Z operator, :math:`\langle 0 \vert \sigma_z \vert 0 \rangle`, defined as: + +.. math:: + \langle 0 \vert \sigma_z \vert 0 \rangle=\begin{bmatrix} + 1 & 0 + \end{bmatrix}\begin{bmatrix} + 1 & 0 \\ + 0 & -1 \\ + \end{bmatrix}\begin{bmatrix} + 1 \\ + 0 + \end{bmatrix} + +|br| + +which can be represented in graphical notation as: + +.. image:: ../_static/tensor_expec_val.svg + :width: 450 + :alt: Expectation value + :align: center + +|br| + +Since we already know the result of this calculation (:math:`1.0`), we can easily compare with Jet, as + +.. code-block:: cpp + + Tensor bra ({"i"}, {2}, {{1,0},{0,0}}); + Tensor ket = bra; //Transposes are handled internally + + Tensor op_ket = ContractTensors(Z, ket); + Tensor bra_op_ket = ContractTensors(bra, op_ket); + + std::cout << "<0|sigma_z|0>=" << bra_op_ket.GetScalar() << std::endl; + + +which outputs + +.. code-block:: text + + <0|sigma_z|0>=(1,0) + +as expected. + +|br| + +We can see that tensors, though useful individually, provide an incredibly powerful representation for performing calculations when combined together. We can next extend the above ideas to `Tensor Networks `_. diff --git a/docs/xanadu_theme/LICENSE b/docs/xanadu_theme/LICENSE new file mode 100644 index 00000000..3cbe22e7 --- /dev/null +++ b/docs/xanadu_theme/LICENSE @@ -0,0 +1,20 @@ +Original work Copyright (c) 2013 Michael Dowling +Modified work Copyright (c) 2018 Xanadu Quantum Technologies Inc. + +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. diff --git a/docs/xanadu_theme/comments.html b/docs/xanadu_theme/comments.html new file mode 100644 index 00000000..42a95fb9 --- /dev/null +++ b/docs/xanadu_theme/comments.html @@ -0,0 +1,16 @@ +{% if theme_disqus_comments_shortname %} +
+
+ + + comments powered by Disqus +
+{% endif %} diff --git a/docs/xanadu_theme/footer.html b/docs/xanadu_theme/footer.html new file mode 100644 index 00000000..636f9d23 --- /dev/null +++ b/docs/xanadu_theme/footer.html @@ -0,0 +1,72 @@ + diff --git a/docs/xanadu_theme/globaltoc.html b/docs/xanadu_theme/globaltoc.html new file mode 100644 index 00000000..7dd8db90 --- /dev/null +++ b/docs/xanadu_theme/globaltoc.html @@ -0,0 +1,14 @@ + + diff --git a/docs/xanadu_theme/header.html b/docs/xanadu_theme/header.html new file mode 100644 index 00000000..ee161cd5 --- /dev/null +++ b/docs/xanadu_theme/header.html @@ -0,0 +1,66 @@ + + + \ No newline at end of file diff --git a/docs/xanadu_theme/layout.html b/docs/xanadu_theme/layout.html new file mode 100644 index 00000000..5600ca6c --- /dev/null +++ b/docs/xanadu_theme/layout.html @@ -0,0 +1,332 @@ +{%- extends "basic/layout.html" %} + +{# Do this so that bootstrap is included before the main css file #} +{%- block htmltitle %} + + + + + + + + + + + + + + + + + {%- block ga %} + {%- if theme_google_analytics_account %} + + + + {%- endif %} + {%- endblock %} + {{ super() }} +{%- endblock %} + +{# Displays the URL for the homepage if it's set or the master_doc if it is not #} +{% macro homepage() -%} + {%- if theme_homepage %} + {%- if hasdoc(theme_homepage) %} + {{ pathto(theme_homepage) }} + {%- else %} + {{ theme_homepage }} + {%- endif %} + {%- else %} + {{ pathto(master_doc) }} + {%- endif %} +{%- endmacro %} + +{# Displays the URL for the tospage if it's set or falls back to homepage macro #} +{% macro tospage() -%} + {%- if theme_tospage %} + {%- if hasdoc(theme_tospage) %} + {{ pathto(theme_tospage) }} + {%- else %} + {{ theme_tospage }} + {%- endif %} + {%- else %} + {{ homepage() }} + {%- endif %} +{%- endmacro %} + +{# Displays the URL for the projectpage if it's set or falls back to homepage macro #} +{% macro projectlink() -%} + {%- if theme_projectlink %} + {%- if hasdoc(theme_projectlink) %} + {{ pathto(theme_projectlink) }} + {%- else %} + {{ theme_projectlink }} + {%- endif %} + {%- else %} + {{ homepage() }} + {%- endif %} +{%- endmacro %} + +{# Displays the next and previous links both before and after content #} +{% macro render_relations() -%} + {% if prev or next %} + +
+ {% endif %} +{%- endmacro %} + +{%- macro guzzle_sidebar() %} +
+
+ {%- if sidebars != None %} + {#- new style sidebar: explicitly include/exclude templates #} + {%- for sidebartemplate in sidebars %} + {%- include sidebartemplate %} + {%- endfor %} + {% else %} + {% include "searchbox.html" %} + {% include "globaltoc.html" %} + {%- endif %} +
+
+{%- endmacro %} + +{%- block header -%} + {% include "header.html" %} +{%- endblock %} + +{%- block content %} + + {%- if pagename == 'index' and theme_index_template %} + {% include theme_index_template %} + {%- else %} +
+ {%- block sidebar1 %}{{ guzzle_sidebar() }}{% endblock %} + + {%- block document_wrapper %} + {%- block document %} +
+
+ {% block breadcrumbs %} +
+ +
+ {% endblock %} +
+ + {% block body %} {% endblock %} + + +
+ {%- block bottom_rel_links %} + {{ render_relations() }} + {%- endblock %} +
+ {%- block comments -%} + {% include "localtoc.html" %} + {%- endblock %} + +
+
+ + {%- endblock %} + {%- endblock %} + + +
+ {%- endif %} + {%- endblock %} + +{%- block footer %} + + + + + + + + + + + + + + + + + + + {% include "footer.html" %} +{%- endblock %} diff --git a/docs/xanadu_theme/localtoc.html b/docs/xanadu_theme/localtoc.html new file mode 100644 index 00000000..eb48c8dc --- /dev/null +++ b/docs/xanadu_theme/localtoc.html @@ -0,0 +1,33 @@ +
+
+ {% if display_toc %} +
+

Contents

+ {% set toctree = toctree(maxdepth=3, collapse=True, includehidden=True) %} + {% if display_toc %} + {{ toc | replace("
  • ", "
  • ") + | replace("
      ", "
        ")}} + {% else %} +
        + {{ toctree }} + {% endif %} +
  • + {% endif %} + +
    +
    diff --git a/docs/xanadu_theme/logo-text.html b/docs/xanadu_theme/logo-text.html new file mode 100644 index 00000000..e69de29b diff --git a/docs/xanadu_theme/search.html b/docs/xanadu_theme/search.html new file mode 100644 index 00000000..f2c56e64 --- /dev/null +++ b/docs/xanadu_theme/search.html @@ -0,0 +1,33 @@ +{%- extends "basic/search.html" %} + +{% block body %} +

    {{ _('Search') }}

    +
    + +

    + {% trans %}Please activate JavaScript to enable the search + functionality.{% endtrans %} +

    +
    +

    + {% trans %} Note that the search function will only return results containing all of the search terms; if you can't find the page you are looking for, try removing some search terms and searching again.{% endtrans %} +

    + {% if search_performed %} +

    {{ _('Search Results') }}

    + {% if not search_results %} +

    {{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}

    + {% endif %} + {% endif %} +
    + {% if search_results %} +
      + {% for href, caption, context in search_results %} +
    • {{ caption }} +
      {{ context|e }}
      +
    • + {% endfor %} +
    + {% endif %} +
    +{% endblock %} + diff --git a/docs/xanadu_theme/searchbox.html b/docs/xanadu_theme/searchbox.html new file mode 100644 index 00000000..452384a5 --- /dev/null +++ b/docs/xanadu_theme/searchbox.html @@ -0,0 +1,13 @@ + diff --git a/docs/xanadu_theme/sourcelink.html b/docs/xanadu_theme/sourcelink.html new file mode 100644 index 00000000..e0cb698e --- /dev/null +++ b/docs/xanadu_theme/sourcelink.html @@ -0,0 +1,30 @@ +{%- if show_source and has_source and sourcename %} + +{%- endif %} \ No newline at end of file diff --git a/docs/xanadu_theme/static/css/nanoscroller.css b/docs/xanadu_theme/static/css/nanoscroller.css new file mode 100644 index 00000000..5b2c5229 --- /dev/null +++ b/docs/xanadu_theme/static/css/nanoscroller.css @@ -0,0 +1,55 @@ +/** initial setup **/ +.nano { + position : relative; + width : 100%; + height : 100%; + overflow : hidden; +} +.nano > .nano-content { + position : absolute; + overflow : scroll; + overflow-x : hidden; + top : 0; + right : 0; + bottom : 0; + left : 0; +} +.nano > .nano-content:focus { + outline: thin dotted; +} +.nano > .nano-content::-webkit-scrollbar { + display: none; +} +.has-scrollbar > .nano-content::-webkit-scrollbar { + display: block; +} +.nano > .nano-pane { + background : rgba(0,0,0,.25); + position : absolute; + width : 10px; + right : 0; + top : 0; + bottom : 0; + visibility : hidden\9; /* Target only IE7 and IE8 with this hack */ + opacity : .01; + -webkit-transition : .2s; + -moz-transition : .2s; + -o-transition : .2s; + transition : .2s; + -moz-border-radius : 5px; + -webkit-border-radius : 5px; + border-radius : 5px; +} +.nano > .nano-pane > .nano-slider { + background: #444; + background: rgba(0,0,0,.5); + position : relative; + margin : 0 1px; + -moz-border-radius : 3px; + -webkit-border-radius : 3px; + border-radius : 3px; +} +.nano:hover > .nano-pane, .nano-pane.active, .nano-pane.flashed { + visibility : visible\9; /* Target only IE7 and IE8 with this hack */ + opacity : 0.99; +} diff --git a/docs/xanadu_theme/static/jquery.js b/docs/xanadu_theme/static/jquery.js new file mode 100644 index 00000000..e4ed78a0 --- /dev/null +++ b/docs/xanadu_theme/static/jquery.js @@ -0,0 +1,5 @@ +/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license + //# sourceMappingURL=jquery.min.map + */(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
    a",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="
    t
    ",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
    ",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; + return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="
    ",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:b.support.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) +}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("