diff --git a/CITATION.cff b/CITATION.cff
new file mode 100644
index 0000000..dd318d9
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,22 @@
+cff-version: 1.2.0
+license: Apache-2.0
+message: If you use this software, please cite it using these metadata.
+authors:
+ - name: TNO Quantum
+ city: The Hague
+ country: NL
+ email: tnoquantum@tno.nl
+ website: https://tno.nl
+type: software
+url: https://tno.nl
+contact:
+ - name: TNO Quantum
+ city: The Hague
+ country: NL
+ email: tnoquantum@tno.nl
+ website: https://tno.nl
+repository-code: https://github.com/TNO-Quantum/problems.portfolio_optimization
+repository-artifact: https://pypi.org/project/tno.quantum.problems.portfolio_optimization
+title: TNO Quantum - Problems - Portfolio Optimization
+version: v1.0.0
+date-released: 2024-05-01
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..999d7a7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ 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 2024 The Netherlands Organisation for Applied Scientific Research (TNO)
+
+ 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.
diff --git a/README.md b/README.md
index 8ab6f9c..4425d13 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,3 @@
-# Coming soon!
-
-This repository will be released in the near future.
-
-For more details you can contact the developers of this repository at tnoquantum@tno.nl.
-
-Dataset can already be found in the `tno/quantum/problems/portfolio_optimization/datasets/` folder.
-
# Portfolio optimization
Real-world investment decisions involve multiple, often conflicting, objectives that needs to be balanced.
@@ -13,14 +5,13 @@ Primary goals typically revolve around maximizing returns while minimizing risks
At the same time, one might want to require additional constraints such as demanding a minimum carbon footprint reduction.
Finding a portfolio that balances these objectives is a challenging task and can be solved using multi-objective portfolio optimization.
-
This repository provides Python code that converts the multi-objective portfolio optimization problem
-into a `QUBO`_ problem. The transformed problem can then be solved using quantum annealing techniques.
+into a [QUBO](https://en.wikipedia.org/wiki/Quadratic_unconstrained_binary_optimization) problem. The transformed problem can then be solved using quantum annealing techniques.
The following objectives can be considered
- `return on capital`, indicated by `ROC`,
-- `diversification`, indicated by the Herfindahl-Hirschman Index `HHI`.
+- `diversification`, indicated by the [Herfindahl-Hirschman Index](https://en.wikipedia.org/wiki/Herfindahl%E2%80%93Hirschman_inde) `HHI`.
Additionally, we allow for a capital growth factor and arbitrary emission reduction constraints to be considered.
@@ -30,3 +21,155 @@ can be computed for the objectives return on capital and diversification.
The codebase is based on the following paper:
- [Aguilera et al., - Multi-objective Portfolio Optimisation Using the Quantum Annealer (2024)](https://www.mdpi.com/2227-7390/12/9/1291)
+
+**Funding:** This research was funded by Rabobank and Stichting TKI High Tech Systems
+and Materials, under a program by Brightland's Techruption.
+
+*Limitations in (end-)use: the content of this software package may solely be used for applications that comply with international export control laws.*
+
+## Documentation
+
+Documentation of the `tno.quantum.problems.portfolio_optimization` package can be found [here](https://tno-quantum.github.io/problems.portfolio_optimization/).
+
+## Install
+
+Easily install the `tno.quantum.problems.portfolio_optimization` package using pip:
+
+```console
+$ python -m pip install tno.quantum.problems.portfolio_optimization
+```
+
+If you wish to use D-Wave quantum hardware:
+```console
+$ python -m pip install 'tno.quantum.problems.portfolio_optimization[quantum]'
+```
+
+If you wish to run the tests you can use:
+```console
+$ python -m pip install 'tno.quantum.problems.portfolio_optimization[tests]'
+```
+
+## Usage
+
+
+ Solve portfolio optimization problem.
+
+Here's an example of how the `PortfolioOptimizer` class can be used to define an portfolio optimization problem,
+and subsequently, how the Pareto front can be computed using the simulated annealing sampler from D-Wave.
+
+```python
+import numpy as np
+from dwave.samplers import SimulatedAnnealingSampler
+
+from tno.quantum.problems.portfolio_optimization import PortfolioOptimizer
+
+# Choose sampler for solving qubo
+sampler = SimulatedAnnealingSampler()
+sampler_kwargs = {"num_reads": 20, "num_sweeps": 200}
+
+# Set up penalty coefficients for the constraints
+lambdas1 = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+lambdas2 = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+lambdas3 = np.array([1])
+
+# Create portfolio optimization problem
+portfolio_optimizer = PortfolioOptimizer("benchmark_dataset")
+portfolio_optimizer.add_minimize_hhi(weights=lambdas1)
+portfolio_optimizer.add_maximize_roc(formulation=1, weights_roc=lambdas2)
+portfolio_optimizer.add_emission_constraint(
+ weights=lambdas3,
+ emission_now="emis_intens_now",
+ emission_future="emis_intens_future",
+ name="emission"
+)
+
+# Solve the portfolio optimization problem
+results = portfolio_optimizer.run(sampler, sampler_kwargs)
+```
+
+
+
+ Visualize results.
+
+The results can be inspected in more detail by looking at the Pandas results DataFrame
+`results.results_df`.
+
+Alternatively, the results can be plotted in a `(Diversification, ROC)`-graph. The
+following example first slices the results in data points that do and do not satisfy the
+constraints using the method `slice_results`.
+
+Note that:
+
+- Individual data points can subsequently be plotted using the `plot_points` function.
+- The Pareto front can be plotted using the `plot_front` function.
+
+```python
+import matplotlib.pyplot as plt
+
+from tno.quantum.problems.portfolio_optimization import plot_front, plot_points
+
+(x1, y1), (x2, y2) = results.slice_results()
+fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 5))
+
+# Plot data points
+plot_points(x2, y2, color="orange", label="QUBO constraint not met", ax=ax1)
+plot_points(x1, y1, color="green", label="QUBO constraint met", ax=ax1)
+ax1.set_title("Points")
+
+# Plot Pareto front
+plot_front(x2, y2, color="orange", label="QUBO constraint not met", ax=ax2)
+plot_front(x1, y1, color="green", label="QUBO constraint met", ax=ax2)
+ax2.set_title("Pareto Front")
+fig.tight_layout()
+plt.show()
+```
+
+
+
+![(Diversification, ROC)-Graph](./images_for_docs/example.png)
+
+
+More elaborate examples can be found in our [examples repository](https://github.com/TNO-Quantum/examples ).
+
+Data input
+----------
+
+The data used for the portfolio optimization can be imported via an excel file, csv file,
+json file or as a Pandas DataFrame.
+The data needs to contain at least the following columns:
+
+- `asset`: The name of the asset.
+- `outstanding_now`: Current outstanding amount per asset.
+- `min_outstanding_future`: Lower bound outstanding amount in the future per asset.
+- `max_outstanding_future`: Upper bound outstanding amount in the future per asset.
+- `income_now`: Current income per asset, corresponds to return multiplied by the current outstanding amount.
+- `regcap_now`: Current regulatory capital per asset.
+
+
+If the input datafile contains all the correct information, but has different column
+names, it is possible to rename the columns without altering the input file.
+Details and examples can be found in the [documentation]((https://tno-quantum.github.io/problems.portfolio_optimization/)).
+
+The data that was used for the publication can be found in the `tno/quantum/problems/portfolio_optimization/datasets/` folder.
+
+
+Using Quantum Annealing Solvers
+-------------------------------
+
+By default, the portfolio optimization QUBO is solved using simulated annealing.
+Any D-Wave ``Sampler`` is however supported and can be provided to the `PortfolioOptimizer.run` method.
+
+
+Below is an example how to initialise a quantum annealing sampler that uses `100` micro seconds annealing time per sample.
+The example assumes a proper [configuration setup](https://docs.ocean.dwavesys.com/en/stable/overview/sapi.html) to the D-Wave's Solver API.
+
+```python
+from dwave.system import DWaveSampler, LazyFixedEmbeddingComposite
+
+# Define QPU D-Wave Sampler
+qpu = DWaveSampler()
+sampler = LazyFixedEmbeddingComposite(qpu)
+sampler_kwargs = {"annealing_time": 100}
+```
+
+We refer to the [D-Wave Sampler documentation](https://docs.ocean.dwavesys.com/projects/system/en/stable/reference/samplers.html) for information on usage of different samplers and their sampler arguments.
diff --git a/docs/.buildinfo b/docs/.buildinfo
new file mode 100644
index 0000000..b619992
--- /dev/null
+++ b/docs/.buildinfo
@@ -0,0 +1,4 @@
+# Sphinx build info version 1
+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
+config: 218433b376044e18c0aa0ad6ae95cf20
+tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/docs/.doctrees/environment.pickle b/docs/.doctrees/environment.pickle
new file mode 100644
index 0000000..0b528a8
Binary files /dev/null and b/docs/.doctrees/environment.pickle differ
diff --git a/docs/.doctrees/index.doctree b/docs/.doctrees/index.doctree
new file mode 100644
index 0000000..0a7ff01
Binary files /dev/null and b/docs/.doctrees/index.doctree differ
diff --git a/docs/.doctrees/portfolio_optimization.components.doctree b/docs/.doctrees/portfolio_optimization.components.doctree
new file mode 100644
index 0000000..9d631b2
Binary files /dev/null and b/docs/.doctrees/portfolio_optimization.components.doctree differ
diff --git a/docs/.doctrees/portfolio_optimization.components.io.doctree b/docs/.doctrees/portfolio_optimization.components.io.doctree
new file mode 100644
index 0000000..563d577
Binary files /dev/null and b/docs/.doctrees/portfolio_optimization.components.io.doctree differ
diff --git a/docs/.doctrees/portfolio_optimization.components.postprocess.doctree b/docs/.doctrees/portfolio_optimization.components.postprocess.doctree
new file mode 100644
index 0000000..5799885
Binary files /dev/null and b/docs/.doctrees/portfolio_optimization.components.postprocess.doctree differ
diff --git a/docs/.doctrees/portfolio_optimization.components.qubos.doctree b/docs/.doctrees/portfolio_optimization.components.qubos.doctree
new file mode 100644
index 0000000..6981926
Binary files /dev/null and b/docs/.doctrees/portfolio_optimization.components.qubos.doctree differ
diff --git a/docs/.doctrees/portfolio_optimization.components.results.doctree b/docs/.doctrees/portfolio_optimization.components.results.doctree
new file mode 100644
index 0000000..0a9fae6
Binary files /dev/null and b/docs/.doctrees/portfolio_optimization.components.results.doctree differ
diff --git a/docs/.doctrees/portfolio_optimization.components.visualization.doctree b/docs/.doctrees/portfolio_optimization.components.visualization.doctree
new file mode 100644
index 0000000..840db55
Binary files /dev/null and b/docs/.doctrees/portfolio_optimization.components.visualization.doctree differ
diff --git a/docs/.doctrees/portfolio_optimization.doctree b/docs/.doctrees/portfolio_optimization.doctree
new file mode 100644
index 0000000..cb1fdbe
Binary files /dev/null and b/docs/.doctrees/portfolio_optimization.doctree differ
diff --git a/docs/.nojekyll b/docs/.nojekyll
new file mode 100644
index 0000000..e69de29
diff --git a/docs/_modules/index.html b/docs/_modules/index.html
new file mode 100644
index 0000000..b753535
--- /dev/null
+++ b/docs/_modules/index.html
@@ -0,0 +1,125 @@
+
+
+
[docs]classPortfolioData:
+"""The ``PortfolioData`` stores the data used for portfolio optimization."""
+
+
[docs]def__init__(
+ self,
+ portfolio_dataframe:DataFrame,
+ columns_rename:dict[str,str]|None=None,
+ ):
+"""Creates a ``PortfolioData`` object from a pandas ``DataFrame``.
+
+ The portfolio data is expected to contain at least the following columns names:
+
+ - ``"assets"``: The name of the asset.
+ - ``"outstanding_now_now"``: Current outstanding amount per asset.
+ - ``"min_outstanding_future"``: Lower bound outstanding amount in the future per asset.
+ - ``"max_outstanding_future"``: Upper bound outstanding amount in the future per asset.
+ - ``"income_now"``: Current income per asset, corresponds to return multiplied by the current outstanding amount.
+ - ``"regcap_now"``: Current regulatory capital per asset.
+
+ Different column names in the dataset can be used but need to be provided as a
+ renaming dictionary to the ``columns_rename`` argument.
+
+ Args:
+ portfolio_dataframe: Pandas ``DataFrame`` containing the portfolio data.
+ column_rename: to rename columns provided as dict with new column names as keys
+ and to replace column name as value. Example
+ ``{"outstanding_2021": "outstanding_now"}``.
+
+ Raises:
+ ValueError if required columns are not present in dataset.
+ """
+ ifcolumns_renameisnotNone:
+ portfolio_dataframe.rename(columns=columns_rename,inplace=True)
+
+ # Validate dataset to contain required column names
+ forrequired_column_nameinDEFAULT_REQUIRED_COLUMN_NAMES:
+ ifrequired_column_namenotinportfolio_dataframe.columns:
+ raiseValueError(
+ f"Required column name {required_column_name} is not in dataset."
+ )
+
+ self.portfolio_df=portfolio_dataframe
+
+
[docs]@classmethod
+ deffrom_file(
+ cls:type[PortfolioDataT],
+ filename:str|Path,
+ columns_rename:dict[str,str]|None=None,
+ )->PortfolioDataT:
+"""Reads portfolio data object into ``PortfolioData``.
+
+ The portfolio data is expected to contain at least the following columns names:
+
+ - ``"assets"``: The name of the asset.
+ - ``"outstanding_now_now"``: Current outstanding amount per asset.
+ - ``"min_outstanding_future"``: Lower bound outstanding amount in the future per asset.
+ - ``"max_outstanding_future"``: Upper bound outstanding amount in the future per asset.
+ - ``"income_now"``: Current income per asset, corresponds to return multiplied by the current outstanding amount.
+ - ``"regcap_now"``: Current regulatory capital per asset.
+
+ Different column names in the dataset can be used but need to be provided as a
+ renaming dictionary to the ``columns_rename`` argument.
+
+ Args:
+ filename: path to portfolio data. If instead ``benchmark_dataset`` is
+ provided, a default benchmark dataset containing 52 assets will be used.
+ column_rename: to rename columns provided as dict with new column names as keys
+ and to replace column name as value. Example
+ ``{"outstanding_2021": "outstanding_now"}``.
+
+ Raises:
+ ValueError if required columns are not present in dataset.
+ """
+ ifstr(filename)=="benchmark_dataset":
+ filename=Path(__file__).parents[1]/"datasets"/"benchmark_dataset.xlsx"
+
+ filename=str(filename)
+ iffilename.endswith(".xlsx"):
+ portfolio_data=pd.read_excel(filename)
+ eliffilename.endswith(".csv"):
+ portfolio_data=pd.read_csv(filename)
+ eliffilename.endswith(".json"):
+ portfolio_data=pd.read_json(filename)
+ else:
+ raiseValueError("Datatype not supported.")
+ returncls(portfolio_data,columns_rename)
+
+
[docs]defget_outstanding_now(self)->NDArray[np.float_]:
+"""Gets the `outstanding_now` data from the dataset.
+
+ Returns:
+ The `outstanding_now` column from the dataset as a numpy array.
+ """
+ returncast(NDArray[np.float_],self.portfolio_df["outstanding_now"].to_numpy())
+
+
[docs]defget_l_bound(self)->NDArray[np.float_]:
+"""Gets the `l_bound` data from the dataset.
+
+ Returns:
+ The `min_outstanding_future` column from the dataset as a numpy array.
+ """
+ returncast(
+ NDArray[np.float_],self.portfolio_df["min_outstanding_future"].to_numpy()
+ )
+
+
[docs]defget_u_bound(self)->NDArray[np.float_]:
+"""Gets the `u_bound` data from the dataset.
+
+ Returns:
+ The `max_outstanding_future` column from the dataset as a numpy array.
+ """
+ returncast(
+ NDArray[np.float_],self.portfolio_df["max_outstanding_future"].to_numpy()
+ )
+
+
[docs]defget_income(self)->NDArray[np.float_]:
+"""Gets the `income` data from the dataset.
+
+ Returns:
+ The `income_now` column from the dataset as a numpy array.
+ """
+ returncast(NDArray[np.float_],self.portfolio_df["income_now"].to_numpy())
+
+
[docs]defget_capital(self)->NDArray[np.float_]:
+"""Gets the `capital` data from the dataset.
+
+ Returns:
+ The `regcap_now` column from the dataset as a numpy array.
+ """
+ returncast(NDArray[np.float_],self.portfolio_df["regcap_now"].to_numpy())
+
+
[docs]defget_returns(self)->NDArray[np.float_]:
+"""Gets the `returns` data from the dataset.
+
+ Returns:
+ Returns is defined as income / outstanding_now
+ """
+ income=self.get_income()
+ outstanding_now=self.get_outstanding_now()
+ returncast(NDArray[np.float_],income/outstanding_now)
+
+
[docs]defget_column(self,column_name:str)->NDArray[np.float_]:
+"""Gets the specified column from the dataset.
+
+ Args:
+ column_name: Name of the column to get.
+
+ Returns:
+ The `regcap_now` columns from the dataset as a numpy array.
+ """
+ returncast(NDArray[np.float_],self.portfolio_df[column_name].to_numpy())
+
+
[docs]defprint_portfolio_info(self)->None:
+"""Prints information about portfolio data to terminal."""
+ outstanding_now=self.get_outstanding_now()
+ l_bound=self.get_l_bound()
+ u_bound=self.get_u_bound()
+ income=self.get_income()
+ capital=self.get_capital()
+
+ # Calculate the total outstanding amount in now
+ total_outstanding_now=np.sum(outstanding_now)
+ print(f"Total outstanding now: {total_outstanding_now:.2f}")
+
+ # Calculate the ROC for now
+ roc_now=np.sum(income)/np.sum(capital)
+ print(f"ROC now: {roc_now:.4f}")
+
+ # Calculate the HHI diversification for now
+ hhi_now=(
+ np.sum(total_outstanding_now**2)/np.sum(total_outstanding_now)**2
+ )
+ print(f"HHI now: {hhi_now:.4f}")
+
+ if"emis_intens_now"inself.portfolio_df:
+ # Calculate the total emissions for now
+ total_emission_now=np.sum(
+ self.get_column("emis_intens_now")*total_outstanding_now
+ )
+ print(f"Total Emission now: {total_emission_now:.2f}")
+
+ # Calculate the average emission intensity now
+ relative_total_emission=total_emission_now/total_outstanding_now
+ print(f"Relative emission intensity now: {relative_total_emission:.2f}")
+
+ # Estimate the total outstanding amount and its standard deviation for future. This
+ # follows from the assumption of a symmetric probability distribution on the
+ # interval [l_bound, u_bound] and the central limit theorem.
+ expected_total_outstanding_future=np.sum(u_bound+l_bound)/2
+ expected_stddev_total_outstanding_future=np.linalg.norm(
+ (u_bound-l_bound)/2
+ )
+ print(
+ f"Expected total outstanding future: {expected_total_outstanding_future:.2f}",
+ f"Std dev: {expected_stddev_total_outstanding_future:.2f}",
+ )
+
+ # Estimate a average growth factor and its standard deviation for now-future. This
+ # consists of the (averaged) amount per asset in future, which is the outcome of the
+ # optimization, divided by the amount for now.
+ expected_average_growth_fac=np.sum(
+ (u_bound+l_bound)/(2*total_outstanding_now)
+ )
+ expected_stddev_average_growth_fac=np.linalg.norm(
+ (u_bound-l_bound)/(2*total_outstanding_now)
+ )
+ print(
+ f"Expected average growth factor: {expected_average_growth_fac:.4f}",
+ f"Std dev: {expected_stddev_average_growth_fac:.4f}",
+ )
+
+
[docs]def__len__(self)->int:
+"""Length of the dataset."""
+ returnlen(self.portfolio_df)
+
+
[docs]def__repr__(self)->str:
+"""Representation for debugging."""
+ txt=f"{self.__class__.__name__} object containing the following data:\n"
+ txt+=repr(self.portfolio_df)
+ returntxt
+
+
[docs]def__str__(self)->str:
+"""String representation of the ``PortfolioData`` object."""
+ txt=f"{self.__class__.__name__} object containing the following data:\n"
+ txt+=str(self.portfolio_df)
+ returntxt
+
+
[docs]def__contains__(self,other:object)->bool:
+"""Check if ``other`` is part of the dataset."""
+ returnotherinself.portfolio_df
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/_modules/portfolio_optimization/components/postprocess.html b/docs/_modules/portfolio_optimization/components/postprocess.html
new file mode 100644
index 0000000..eac7726
--- /dev/null
+++ b/docs/_modules/portfolio_optimization/components/postprocess.html
@@ -0,0 +1,267 @@
+
+
+
+
+
+ portfolio_optimization.components.postprocess — tno.quantum.problems.portfolio_optimization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[docs]classDecoder:
+"""``Decoder`` class for decoding samples and samplesets."""
+
+
[docs]def__init__(
+ self,
+ portfolio_data:PortfolioData,
+ k:int,
+ )->None:
+"""
+ Init for the ``Decoder`` Class.
+
+ Args:
+ portfolio_data: A ``PortfolioData`` object containing the portfolio to
+ optimize.
+ k: The number of bits that are used to represent the outstanding amount for
+ each asset. A fixed point representation is used to represent `$2^k$`
+ different equidistant values in the range `$[LB_i, UB_i]$` for asset i.
+ """
+ self.number_of_assets=len(portfolio_data)
+ self.k=k
+ self.mantissa=np.power(2,np.arange(self.k))
+ self.l_bound=portfolio_data.get_l_bound()
+ self.u_bound=portfolio_data.get_u_bound()
+ self.multiplier=(self.u_bound-self.l_bound)/(2**self.k-1)
+
+
[docs]defdecode_sample(self,sample:Mapping[int,int])->NDArray[np.float_]:
+"""Decodes a sample to the `oustanding_future` array.
+
+ Args:
+ sample: Sample as returned by D-Wave.
+
+ Returns:
+ Array containing all `outstanding future` values.
+ """
+ sample_array=np.array(
+ [sample[i]foriinrange(self.number_of_assets*self.k)],dtype=np.uint8
+ )
+ sample_reshaped=sample_array.reshape((self.number_of_assets,self.k))
+ ints=np.sum(sample_reshaped*self.mantissa,axis=1)
+ outstanding_future=self.l_bound+self.multiplier*ints
+ if(self.l_bound>outstanding_future).any()or(
+ self.u_bound<outstanding_future
+ ).any():
+ raiseValueError("Bounds not obeyed.")
+
+ returnnp.asarray(outstanding_future,dtype=np.float_)
+
+
[docs]defdecode_sampleset(self,sampleset:SampleSet)->NDArray[np.float_]:
+"""Efficiently decodes a `sampleset` create a matrix of `oustanding_future`
+ values.
+
+ Each row in the matrix corresponds to a different sample in the `sampleset`.
+
+ Args:
+ sampleset: ``SampleSet`` as returned by D-Wave.
+
+ Returns:
+ Matrix containing all `outstanding future` values.
+ """
+ samples_matrix=sampleset.record.sample[:,:self.number_of_assets*self.k]
+ samples_reshaped=samples_matrix.reshape(
+ (len(sampleset),self.number_of_assets,self.k)
+ )
+
+ ints=np.sum(samples_reshaped*self.mantissa,axis=2)
+ outstanding_future=self.l_bound+self.multiplier*ints
+
+ if(self.l_bound>outstanding_future).any()or(
+ self.u_bound<outstanding_future
+ ).any():
+ raiseValueError("Bounds not obeyed.")
+
+ returnnp.asarray(outstanding_future,dtype=np.float_)
+
+
+
[docs]defpareto_front(
+ xvals:ArrayLike,
+ yvals:ArrayLike,
+ min_points:int=50,
+ upper_right_quadrant:bool=True,
+)->tuple[NDArray[np.float_],NDArray[np.float_]]:
+"""Calculates the pareto front with at least min_points data points by repeatedly
+ creating a convex hull around data points.
+
+ Args:
+ xvals: x-values of data points
+ yvals: y-values of data points
+ min_points: minimum number of points to be selected
+ upper_right_quadrant: If ``True``, only show the upper right quadrant of the
+ pareto front.
+
+ Returns:
+ x, y values of the points that are on the pareto front
+ """
+ points=np.vstack((xvals,yvals)).T
+ points=np.unique(points,axis=0)
+ iflen(points)<3:
+ returnpoints.T[0],points.T[1]
+
+ hull=ConvexHull(points)
+ pareto_points=points[hull.vertices]
+
+ # Expand the pareto front so that it contains at least min_points.
+ for_inrange(min_points):
+ iflen(pareto_points)>=min_points:
+ break
+ # Remove current hull vertices from data and create a new hull
+ points=np.delete(points,hull.vertices,axis=0)
+ iflen(points)<3:
+ break
+ hull=ConvexHull(points)
+ # Add the new hull vertices to the pareto front
+ new_points=points[hull.vertices]
+ pareto_points=np.vstack((pareto_points,new_points))
+ ifupper_right_quadrant:
+ pareto_points=_get_upper_quadrant(pareto_points)
+
+ ifupper_right_quadrant:
+ pareto_points=_get_upper_quadrant(pareto_points)
+
+ returnpareto_points.T[0],pareto_points.T[1]
+
+
+def_get_upper_quadrant(points:NDArray[np.float_])->NDArray[np.float_]:
+"""Removes all values that are not in the upper right quadrant of the pareto front."""
+ x_values=points.T[0]
+ y_values=points.T[1]
+
+ x_bound=x_values[np.argmax(y_values)]
+ y_bound=y_values[np.argmax(x_values)]
+ mask=(x_values>=x_bound)&(y_values>=y_bound)
+
+ x_values=x_values[mask]
+ y_values=y_values[mask]
+
+ returnnp.vstack((x_values,y_values)).T
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/_modules/portfolio_optimization/components/qubos/_qubo_compiler.html b/docs/_modules/portfolio_optimization/components/qubos/_qubo_compiler.html
new file mode 100644
index 0000000..b2b1b9f
--- /dev/null
+++ b/docs/_modules/portfolio_optimization/components/qubos/_qubo_compiler.html
@@ -0,0 +1,339 @@
+
+
+
+
+
+ portfolio_optimization.components.qubos._qubo_compiler — tno.quantum.problems.portfolio_optimization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Source code for portfolio_optimization.components.qubos._qubo_compiler
+"""This module contains the ``QuboCompiler`` class.
+
+The ``QuboCompiler`` can create a variety of QUBO formulation by combining different
+objectives and constraints with their corresponding penalty or preference parameters.
+"""
+from__future__importannotations
+
+fromcollections.abcimportCallable
+fromfunctoolsimportpartial
+fromtypingimportTypeVar
+
+importnumpyasnp
+fromnumpy.typingimportNDArray
+
+fromtno.quantum.problems.portfolio_optimization.components.ioimportPortfolioData
+
+from._qubo_factoryimportQuboFactory
+
+QuboCompilerT=TypeVar("QuboCompilerT",bound="QuboCompiler")
+
+
+
[docs]classQuboCompiler:
+"""QuboCompiler - A compiler class for creating QUBO instances.
+
+ This class provides a convenient interface for combining different QUBO formulations
+ without needing to worry about the qubo size.
+
+ Methods:
+
+ - `add_minimize_hhi`: Adds the to minimize HHI QUBO to the compile list.
+ - `add_maximize_roc`: Adds a ROC and optionally a stabilizing QUBO to the compile
+ list.
+ - `add_emission_constraint`: Adds an emission constraint QUBO to the compile list.
+ - `add_growth_factor_constraint`: Adds the growth factor constraint QUBO to the
+ compile list.
+
+ """
+
+
[docs]def__init__(self,portfolio_data:PortfolioData,k:int)->None:
+"""Init of the ``QuboCompiler`` class.
+
+ The ``QuboCompiler`` can create a variety of QUBO formulation by combining
+ different objectives and constraints with penalty or preference parameters.
+
+ Args:
+ portfolio_data: A ``PortfolioData`` object containing the portfolio to
+ optimize.
+ k: The number of bits that are used to represent the outstanding amount for
+ each asset. A fixed point representation is used to represent `$2^k$`
+ different equidistant values in the range `$[LB_i, UB_i]$` for asset i.
+ """
+ self._qubo_factory=QuboFactory(portfolio_data,k)
+
+ self._to_compile:list[Callable[[],tuple[NDArray[np.float_],float]]]=[]
+ self._compiled_qubos:list[NDArray[np.float_]]=[]
+
+
[docs]defadd_minimize_hhi(
+ self:QuboCompilerT,
+ )->QuboCompilerT:
+r"""Adds the minimize HHI objective to the compile list.
+
+ The HHI objective is given by
+
+ $$HHI(x) = \sum_{i=1}^N\left(\frac{x_i}{\sum_{j=1}^N x_j}\right)^2,$$
+
+ where
+
+ - `$N$` is the total number of assets,
+ - `$x_i$` is the future outstanding amount for asset `$i$`.
+
+ For the QUBO formulation, see the docs of
+ :py:meth:`~portfolio_optimization.components.qubos.QuboFactory.calc_minimize_hhi`.
+
+ Returns:
+ Self.
+ """
+ self._to_compile.append(self._qubo_factory.calc_minimize_hhi)
+ returnself
+
+
[docs]defadd_maximize_roc(
+ self:QuboCompilerT,
+ formulation:int,
+ ancilla_variables:int=0,
+ )->QuboCompilerT:
+"""Adds the maximize ROC objective and based on the chosen formulation a
+ stabilize c constraint.
+
+ Args:
+ formulation: Integer representing which formulation to pick. If formulation
+ is ``1``, then one QUBO term will be added. If formulation is ``2``,
+ then 2 QUBO terms will be added as well, but the argument
+ `ancilla_variables` must be provided.
+ ancilla_variables: Number of ancilla variables to use for formulation ``2``.
+
+ Returns:
+ Self.
+ """
+ ifformulation==1:
+ self._to_compile.append(self._qubo_factory.calc_maximize_roc1)
+ elifformulation==2:
+ self._qubo_factory.n_vars+=ancilla_variables
+ self._to_compile.append(self._qubo_factory.calc_maximize_roc2)
+ self._to_compile.append(self._qubo_factory.calc_stabilize_c)
+
+ returnself
+
+
[docs]defadd_emission_constraint(
+ self:QuboCompilerT,
+ emission_now:str,
+ emission_future:str|None=None,
+ reduction_percentage_target:float=0.7,
+ )->QuboCompilerT:
+r"""Adds the emission constraint to the compile list.
+
+ The constraint is given by
+
+ .. math::
+
+ \frac{\sum_{i=1}^Nf_i \cdot x_i}{\sum_{i=1}^N x_i}
+ =
+ g_e \frac{\sum_{i=1}^Ne_i \cdot y_i}{\sum_{i=1}^N y_i},
+
+ where:
+
+ - `$x_i$` is the future outstanding amount for asset `$i$`,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - `$e_i$` is the current emission intensity for asset `$i$`,
+ - `$f_i$` is the expected emission intensity at the future for asset `$i$`,
+ - `$g_e$` is the target value for the relative emission reduction.
+
+ For the QUBO formulation, see the docs of
+ :py:meth:`~portfolio_optimization.components.qubos.QuboFactory.calc_emission_constraint`.
+
+ Args:
+ emission_now: Name of the column in the portfolio dataset corresponding to
+ the variables at current time.
+ emission_future: Name of the column in the portfolio dataset corresponding
+ to the variables at future time. If no value is provided, it is assumed
+ that the value is constant over time, i.e., the variable
+ ``emission_now`` will be used.
+ reduction_percentage_target: target value for reduction percentage amount.
+
+ Returns:
+ Self.
+ """
+ method=partial(
+ self._qubo_factory.calc_emission_constraint,
+ emission_now=emission_now,
+ emission_future=emission_future,
+ reduction_percentage_target=reduction_percentage_target,
+ )
+ self._to_compile.append(method)
+ returnself
+
+
[docs]defadd_growth_factor_constraint(
+ self:QuboCompilerT,growth_target:float
+ )->QuboCompilerT:
+ # pylint: disable=line-too-long
+r"""Adds the capital growth factor constraint to the compile list.
+
+ The constraint is given by
+
+ $$\frac{\sum_{i=1}^N x_i}{\sum_{i=1}^N y_i} = g_c,$$
+
+ where
+
+ - `$N$` is the total number of assets,
+ - `$x_i$` is the future outstanding amount for asset `$i$`,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - `$g_c$` is the target value for the total growth factor.
+
+ For the QUBO formulation, see the docs of
+ :py:meth:`~portfolio_optimization.components.qubos.QuboFactory.calc_growth_factor_constraint`.
+
+ Args:
+ growth_target: target value for growth factor total outstanding amount.
+
+ Returns:
+ Self.
+ """
+ # pylint: enable=line-too-long
+ method=partial(
+ self._qubo_factory.calc_growth_factor_constraint,
+ growth_target=growth_target,
+ )
+ self._to_compile.append(method)
+ returnself
+
+
[docs]defcompile(self:QuboCompilerT)->QuboCompilerT:
+"""Compiles all QUBOs in the compile list.
+
+ Returns:
+ Self."""
+ self._compiled_qubos=[]
+ forconstructorinself._to_compile:
+ qubo,_=constructor()
+ self._compiled_qubos.append(qubo)
+ returnself
+
+
[docs]defmake_qubo(self,*lambdas:float)->tuple[NDArray[np.float_],float]:
+"""Makes a QUBO of the entire problem with the given lambdas.
+
+ Args:
+ lambdas: Scaling parameters for each QUBO in the formulation.
+
+ Returns:
+ Tuple containing the QUBO matrix and offset.
+ """
+ iflen(lambdas)!=len(self._compiled_qubos):
+ raiseValueError(
+ "Number of lambdas does not correspond with the number of Hamiltonians."
+ )
+ qubo=sum(
+ (
+ lambda_i*qubo_i
+ forlambda_i,qubo_iinzip(lambdas,self._compiled_qubos)
+ ),
+ start=np.zeros_like(self._compiled_qubos[0]),
+ )
+
+ returnqubo,float("nan")
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/_modules/portfolio_optimization/components/qubos/_qubo_factory.html b/docs/_modules/portfolio_optimization/components/qubos/_qubo_factory.html
new file mode 100644
index 0000000..ab534d5
--- /dev/null
+++ b/docs/_modules/portfolio_optimization/components/qubos/_qubo_factory.html
@@ -0,0 +1,531 @@
+
+
+
+
+
+ portfolio_optimization.components.qubos._qubo_factory — tno.quantum.problems.portfolio_optimization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Source code for portfolio_optimization.components.qubos._qubo_factory
+"""This module contains the ``QuboFactory`` class.
+
+The ``QuboFactory`` class provides a convenient interface for constructing intermediate
+QUBO matrices for different objectives and constraints.
+"""
+from__future__importannotations
+
+importnumpyasnp
+fromnumpy.typingimportNDArray
+
+fromtno.quantum.problems.portfolio_optimization.components.ioimportPortfolioData
+
+# pylint: disable=too-many-instance-attributes
+
+
+
[docs]classQuboFactory:
+"""QuboFactory - A factory class for creating QUBO instances.
+
+ This class provides a convenient interface for constructing intermediate QUBO
+ matrices for different objectives and constraints.
+
+ Methods:
+
+ - `calc_minimize_hhi`: Calculates the to minimize HHI QUBO
+ - `calc_maximize_roc1`: Calculates the to maximize return on capital QUBO variant 1
+ - `calc_maximize_roc2`: Calculates the to maximize return on capital QUBO variant 2
+ - `calc_emission_constraint`: Calculates the emission constraint QUBO
+ - `calc_growth_factor_constraint`: Calculates the growth factor constraint QUBO
+ - `calc_stabilize_c`: Calculates the constraint QUBO that stabilizes growth factor.
+ """
+
+
[docs]def__init__(self,portfolio_data:PortfolioData,k:int)->None:
+"""Init of the ``QuboFactory``.
+
+ Args:
+ portfolio_data: A ``PortfolioData`` object containing the portfolio to
+ optimize.
+ k: The number of bits that are used to represent the outstanding amount for
+ each asset. A fixed point representation is used to represent `$2^k$`
+ different equidistant values in the range `$[LB_i, UB_i]$` for asset i.
+ """
+ self.portfolio_data=portfolio_data
+ self.number_of_assets=len(portfolio_data)
+ self.n_vars=self.number_of_assets*k
+ self.outstanding_now=portfolio_data.get_outstanding_now()
+ self.l_bound=portfolio_data.get_l_bound()
+ self.u_bound=portfolio_data.get_u_bound()
+ self.income=portfolio_data.get_income()
+ self.returns=portfolio_data.get_returns()
+ self.capital=portfolio_data.get_capital()
+ self.k=k
+
+
[docs]defcalc_minimize_hhi(self)->tuple[NDArray[np.float_],float]:
+r"""Calculates the to minimize HHI QUBO.
+
+ The QUBO formulation is given by
+
+ .. math::
+
+ QUBO(x)
+ =
+ \sum_{i=1}^N\left(LB_i + \frac{UB_i-LB_i}{2^k-1}\sum_{j=0}^{k-1}2^j\cdot x_{i,j}\right)^2,
+
+ where:
+
+ - `$LB_i$` is the lower bound for asset `$i$`,
+ - `$UB_i$` is the upper bound for asset `$i$`,
+ - `$k$` is the number of bits,
+ - and `$x_{i,j}$` are the $k$ binary variables for asset `$i$` with $j<k$.
+
+ Returns:
+ qubo matrix and its offset
+ """
+ qubo=np.zeros((self.n_vars,self.n_vars))
+ offset=np.sum(self.l_bound**2)
+ multiplier=(self.u_bound-self.l_bound)/(2**self.k-1)
+ forasset_i,(l_bound_i,multiplier_i)inenumerate(
+ zip(self.l_bound,multiplier)
+ ):
+ # For asset i: (LB + multiplier * sum_j 2**j x_j) ** 2
+ forbit_jinrange(self.k):
+ idx_1=asset_i*self.k+bit_j
+
+ # Diagonal elements: 2 * LB * multiplier * sum_j 2**j x_j
+ qubo[idx_1,idx_1]+=l_bound_i*multiplier_i*2**(bit_j+1)
+ qubo[idx_1,idx_1]+=multiplier_i**2*2**(2*bit_j)
+
+ # Elements: multiplier**2 * (sum_j 2**j x_j) * (sum_j' 2**j' x_j')
+ forbit_j_primeinrange(bit_j+1,self.k):
+ idx_2=asset_i*self.k+bit_j_prime
+ qubo[idx_1,idx_2]+=multiplier_i**2*2**(
+ bit_j+bit_j_prime+1
+ )
+
+ qubo=qubo
+ returnqubo,offset
+
+
[docs]defcalc_emission_constraint(
+ self,
+ emission_now:str,
+ emission_future:str|None=None,
+ reduction_percentage_target:float=0.7,
+ )->tuple[NDArray[np.float_],float]:
+r"""Calculates the emission constraint QUBO for arbitrary target reduction target
+
+ The QUBO formulation is given by
+
+ .. math::
+
+ QUBO(x)
+ &=
+ \left(
+ \sum_{i=1}^N f_i x_i
+ - g_e E
+ \sum_{i=1}^N x_i
+ \right)^2,
+
+ x_i & = LB_i+\frac{UB_i-LB_i}{2^k-1}\sum_{j=0}^{k-1}2^j\cdot x_{i,j},
+
+ E &= \frac{\sum_{i=1}^N e_i \cdot y_i}{\sum_{i=1}^N y_i},
+
+ where:
+
+ - `$LB_i$` is the lower bound for asset `$i$`,
+ - `$UB_i$` is the upper bound for asset `$i$`,
+ - `$k$` is the number of bits,
+ - `$e_i$` is the current emission intensity for asset `$i$`,
+ - `$f_i$` is the expected emission intensity at the future for asset `$i$`,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - `$g_e$` is the target value for the relative emission reduction,
+ - and `$x_{i,j}$` are the $k$ binary variables for asset `$i$` with $j<k$.
+
+ Args:
+ emission_now: Name of the column in the portfolio dataset corresponding to
+ the variables at current time.
+ emission_future: Name of the column in the portfolio dataset corresponding
+ to the variables at future time. If no value is provided, it is assumed
+ that the value is constant over time, i.e., the variable
+ ``emission_now`` will be used.
+ reduction_percentage_target: Target value for reduction percentage amount.
+
+ Raises:
+ KeyError: if the provided column names are not in the portfolio_data.
+
+ Returns:
+ qubo matrix and its offset
+ """
+ ifemission_futureisNone:
+ emission_future=emission_now
+
+ ifemission_nownotinself.portfolio_data:
+ raiseKeyError(
+ f"Column name {emission_now} not present in portfolio dataset."
+ )
+ ifemission_futurenotinself.portfolio_data:
+ raiseKeyError(
+ f"Column name {emission_future} not present in portfolio dataset."
+ )
+
+ emission_intensity_now=self.portfolio_data.get_column(emission_now)
+ emission_intensity_future=self.portfolio_data.get_column(emission_future)
+
+ total_emission_now=np.sum(emission_intensity_now*self.outstanding_now)
+ relelative_total_emission_now=total_emission_now/np.sum(
+ self.outstanding_now
+ )
+
+ alpha=np.sum(
+ (
+ emission_intensity_future
+ -reduction_percentage_target*relelative_total_emission_now
+ )
+ *self.l_bound
+ )
+
+ mantisse=np.power(2,np.arange(self.k))
+ multiplier=(
+ (
+ emission_intensity_future
+ -reduction_percentage_target*relelative_total_emission_now
+ )
+ *(self.u_bound-self.l_bound)
+ /(2**self.k-1)
+ )
+ beta=np.kron(multiplier,mantisse)
+ qubo=np.zeros((self.n_vars,self.n_vars))
+
+ offset=alpha**2
+ foridx1inrange(self.number_of_assets*self.k):
+ qubo[idx1,idx1]+=2*alpha*beta[idx1]+beta[idx1]**2
+ foridx2inrange(idx1+1,self.number_of_assets*self.k):
+ qubo[idx1,idx2]+=2*beta[idx1]*beta[idx2]
+
+ qubo=qubo
+ returnqubo,offset
+
+
[docs]defcalc_growth_factor_constraint(
+ self,growth_target:float
+ )->tuple[NDArray[np.float_],float]:
+r"""Calculates the growth factor constraint QUBO
+
+ The QUBO formulation is given by
+
+ .. math::
+
+ QUBO(x)
+ =
+ \left(
+ \frac{\sum_{i=1}^N LB_i + \frac{UB_i-LB_i}{2^k-1}\sum_{j=0}^{k-1} 2^j\cdot x_{i,j}}{\sum_{i=1}^N y_i}
+ - g_c
+ \right)^2
+
+ where:
+
+ - `$LB_i$` is the lower bound for asset `$i$`,
+ - `$UB_i$` is the upper bound for asset `$i$`,
+ - `$k$` is the number of bits,
+ - `$g_c$` is the target value for the total growth factor,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - and `$x_{i,j}$` are the $k$ binary variables for asset `$i$` with $j<k$.
+
+ Args:
+ growth_target: target value for growth factor total outstanding amount.
+
+ Returns:
+ qubo matrix and its offset
+ """
+ total_outstanding_now=np.sum(self.outstanding_now)
+ alpha=np.sum(self.l_bound)/total_outstanding_now-growth_target
+
+ mantisse=np.power(2,np.arange(self.k))
+ multiplier=(self.u_bound-self.l_bound)/(
+ (2**self.k-1)*total_outstanding_now
+ )
+ beta=np.kron(multiplier,mantisse)
+
+ qubo=np.zeros((self.n_vars,self.n_vars))
+ # We only fill the upper left part of the matrix, since we don't use ancilla
+ # variables
+ qubo_slice=qubo[
+ :self.k*self.number_of_assets,:self.k*self.number_of_assets
+ ]
+ # Add the off diagonal elements
+ qubo_slice+=np.triu(2*np.outer(beta,beta),k=1)
+ # Add the diagonal elements
+ np.fill_diagonal(qubo_slice,beta**2+2*alpha*beta)
+ offset=alpha**2
+ returnqubo,float(offset)
+
+
[docs]defcalc_maximize_roc1(self)->tuple[NDArray[np.float_],float]:
+r"""Calculates the to maximize ROC QUBO for variant 1.
+
+ The QUBO formulation is given by
+
+ .. math::
+
+ QUBO(x)
+ =
+ -\sum_{i=1}^N\frac{r_i}{c_i\cdot y_i}
+ \left(LB_i + \frac{UB_i-LB_i}{2^k-1}\sum_{j=0}^{k-1}2^j\cdot x_{i,j}\right),
+
+ where
+
+ - `$LB_i$` is the lower bound for asset `$i$`,
+ - `$UB_i$` is the upper bound for asset `$i$`,
+ - `$k$` is the number of bits,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - `$r_i$` is the current return for asset `$i$`,
+ - `$c_i$` is the regulatory capital for asset `$i$`,
+ - and `$x_{i,j}$` are the $k$ binary variables for asset `$i$` with $j<k$.
+
+ Returns:
+ qubo matrix and its offset
+ """
+ theta=self.returns/(self.outstanding_now*self.capital)
+ offset=np.sum(theta*self.l_bound)
+ mantisse=np.power(2,np.arange(self.k))
+ multiplier=theta*(self.u_bound-self.l_bound)/(2**self.k-1)
+ qubo_diag=np.kron(multiplier,mantisse)
+
+ qubo=np.diag(qubo_diag)
+ return-qubo,-offset
+
+
[docs]defcalc_maximize_roc2(self)->tuple[NDArray[np.float_],float]:
+r"""Calculates the to maximize ROC QUBO for variant 2.
+
+ The QUBO formulation is given by
+
+ .. math::
+
+ QUBO(x,g)
+ &=
+ -
+ G_{inv}(g) \cdot
+ \sum_{i=1}^N\frac{r_i}{y_i}
+ \left(LB_i + \frac{UB_i-LB_i}{2^k-1}\sum_{j=0}^{k-1}2^j\cdot x_{i,j}\right),
+
+ G_{inv}(g) &=
+ 1 + \sum_{j=0}^{k-1} 2^{-j-1}(2^{-j-1} - 1)\cdot g_{j},
+
+ where
+
+ - `$LB_i$` is the lower bound for asset `$i$`,
+ - `$UB_i$` is the upper bound for asset `$i$`,
+ - `$k$` is the number of bits,
+ - `$a$` is the number of ancilla variables,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - `$r_i$` is the return for asset `$i$`,
+ - `$c_i$` is the regulatory capital for asset `$i$`,
+ - `$x_{i,j}$` are the $k$ binary variables for asset `$i$` with $j<k$.
+ - `$g_{j}$` are the $a$ binary ancilla variables with $j<a$.
+
+ Returns:
+ qubo matrix and its offset
+ """
+ ancilla_variables=self.n_vars-self.k*self.number_of_assets
+
+ alpha=np.sum(self.l_bound*self.returns/self.outstanding_now)
+ mantisse=mantisse=np.power(2,np.arange(self.k))
+ multiplier=(
+ self.returns
+ *(self.u_bound-self.l_bound)
+ /(self.outstanding_now*(2**self.k-1))
+ )
+ beta=np.kron(multiplier,mantisse)
+
+ gamma=np.power(2.0,np.arange(-1,-ancilla_variables-1,-1))
+ gamma=gamma**2-gamma
+
+ qubo=np.zeros((self.n_vars,self.n_vars))
+ np.fill_diagonal(
+ qubo[:self.number_of_assets*self.k,:self.number_of_assets*self.k],
+ beta,
+ )
+ qubo[
+ :self.number_of_assets*self.k,self.number_of_assets*self.k:
+ ]+=np.outer(beta,gamma)
+ np.fill_diagonal(
+ qubo[self.number_of_assets*self.k:,self.number_of_assets*self.k:],
+ alpha*gamma,
+ )
+ offset=alpha
+ return-qubo,-offset
+
+
[docs]defcalc_stabilize_c(self)->tuple[NDArray[np.float_],float]:
+r"""Calculates the QUBO that stabilizes the growth factor in the second ROC
+ formulation.
+
+ The QUBO formulation is given by
+
+ .. math::
+
+ QUBO(x,g)
+ &=
+ \left(
+ \sum_{i=1}^N\frac{c_i}{y_i}
+ \left(LB_i + \frac{UB_i-LB_i}{2^k-1}\sum_{j=0}^{k-1}2^j\cdot x_{i,j}\right)
+ - G_C(g)\sum_{i=1}^N c_i
+ \right)^2,
+
+ G_C &= 1 + \sum_{j=0}^{k-1} 2^{-j - 1} \cdot g_j,
+
+ where
+
+ - `$LB_i$` is the lower bound for asset `$i$`,
+ - `$UB_i$` is the upper bound for asset `$i$`,
+ - `$k$` is the number of bits,
+ - `$a$` is the number of ancilla variables,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - `$c_i$` is the regulatory capital for asset `$i$`,
+ - `$x_{i,j}$` are the $k$ binary variables for asset `$i$` with $j<k$,
+ - `$g_j$` are the $a$ ancillary binary variables with $j<a$.
+
+ Returns:
+ qubo matrix and its offset
+ """
+ ancilla_variables=self.n_vars-self.k*self.number_of_assets
+ alpha=np.sum(self.capital*self.l_bound/self.outstanding_now)-np.sum(
+ self.capital
+ )
+
+ mantisse=mantisse=np.power(2,np.arange(self.k))
+ multiplier=(
+ self.capital
+ *(self.u_bound-self.l_bound)
+ /(self.outstanding_now*(2**self.k-1))
+ )
+ beta=np.kron(multiplier,mantisse)
+
+ gamma=-np.power(2.0,np.arange(-1,-ancilla_variables-1,-1))*np.sum(
+ self.capital
+ )
+
+ qubo=np.zeros((self.n_vars,self.n_vars))
+ qubo_upper_left=qubo[
+ :self.number_of_assets*self.k,:self.number_of_assets*self.k
+ ]
+ qubo_upper_left+=np.triu(2*np.outer(beta,beta),k=1)
+ np.fill_diagonal(qubo_upper_left,2*alpha*beta+beta**2)
+
+ qubo_upper_right=qubo[
+ :self.number_of_assets*self.k,self.number_of_assets*self.k:
+ ]
+ qubo_upper_right+=2*np.outer(beta,gamma)
+
+ qubo_lower_right=qubo[
+ self.number_of_assets*self.k:,self.number_of_assets*self.k:
+ ]
+ qubo_lower_right+=np.triu(2*np.outer(gamma,gamma),k=1)
+ np.fill_diagonal(qubo_lower_right,2*alpha*gamma+gamma**2)
+ offset=alpha**2
+
+ returnqubo,offset
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/_modules/portfolio_optimization/components/results.html b/docs/_modules/portfolio_optimization/components/results.html
new file mode 100644
index 0000000..b4d50c0
--- /dev/null
+++ b/docs/_modules/portfolio_optimization/components/results.html
@@ -0,0 +1,306 @@
+
+
+
+
+
+ portfolio_optimization.components.results — tno.quantum.problems.portfolio_optimization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[docs]def__init__(
+ self,
+ portfolio_data:PortfolioData,
+ provided_emission_constraints:list[tuple[str,str,float,str]]|None=None,
+ provided_growth_target:float|None=None,
+ )->None:
+"""Init of Results container.
+
+ Args:
+ portfolio_data: the portfolio data
+ provided_emission_constraints: list of all the emission constraints that are
+ provided. Each list element contains the ``emission_now``,
+ ``emission_future`` and ``reduction_percentage_target`` input.
+ provided_growth_target: target outstanding amount growth factor if the
+ growth factor constraint is set, otherwise None.
+ """
+ self.portfolio_data=portfolio_data
+ ifprovided_emission_constraintsisNone:
+ self.provided_emission_constraints=[]
+ else:
+ self.provided_emission_constraints=provided_emission_constraints
+ self.provided_growth_target=provided_growth_target
+
+ self._outstanding_now=portfolio_data.get_outstanding_now()
+ self._total_outstanding_now=np.sum(self._outstanding_now)
+
+ self._returns=portfolio_data.get_income()/self._outstanding_now
+ self._capital=portfolio_data.get_capital()
+ self._roc_now=np.sum(portfolio_data.get_income())/np.sum(self._capital)
+ self._hhi_now=(
+ np.sum(self._outstanding_now**2)/np.sum(self._outstanding_now)**2
+ )
+
+ self.columns=[
+ "outstanding amount",
+ "diff ROC",
+ "diff diversification",
+ "diff outstanding",
+ ]+[
+ "diff "+constraint[3]forconstraintinself.provided_emission_constraints
+ ]
+ self.results_df=pd.DataFrame(columns=self.columns)
+
+
[docs]def__len__(self)->int:
+"""Return the number of samples stored in the ``Results`` object."""
+ returnlen(self.results_df)
+
+
[docs]defadd_result(self,outstanding_future_samples:NDArray[np.float_])->None:
+"""Adds a new outstanding_future data point to results container.
+
+ Args:
+ outstanding_future_samples: outstanding amounts in the future for each
+ sample of the dataset.
+ """
+ foroustanding_futureinoutstanding_future_samples:
+ total_outstanding_future=np.sum(oustanding_future)
+ # Compute the ROC growth
+ roc=np.sum(oustanding_future*self._returns)/np.sum(
+ oustanding_future*self._capital/self._outstanding_now
+ )
+ roc_growth=100*(roc/self._roc_now-1)
+
+ # Compute the diversification.
+ hhi=np.sum(oustanding_future**2)/total_outstanding_future**2
+ diff_diversification=100*(1-(hhi/self._hhi_now))
+
+ # Compute the growth outstanding in outstanding amount
+ growth_outstanding=total_outstanding_future/self._total_outstanding_now
+
+ new_data=[
+ tuple(oustanding_future),
+ roc_growth,
+ diff_diversification,
+ growth_outstanding,
+ ]
+
+ # Compute the emission constraint growths
+ for(
+ column_name_now,
+ column_name_future,
+ _,
+ _,
+ )inself.provided_emission_constraints:
+ total_relative_emission_now=(
+ np.sum(
+ self._outstanding_now
+ *self.portfolio_data.get_column(column_name_now)
+ )
+ /self._total_outstanding_now
+ )
+ total_relative_emission_future=np.sum(
+ oustanding_future
+ *self.portfolio_data.get_column(column_name_future)
+ )/np.sum(oustanding_future)
+
+ new_data.append(
+ 100
+ *(total_relative_emission_future/total_relative_emission_now-1)
+ )
+
+ # Write results
+ self.results_df.loc[len(self.results_df)]=new_data
+
+
[docs]defhead(self,n:int=5)->pd.DataFrame:
+"""Returns first n rows of self.results_df DataFrame
+
+ Args:
+ selected_columns: By default all columns
+ n: number of results to return
+ """
+ selected_columns=[
+ columnforcolumninself.columnsifcolumn!="Outstanding amount"
+ ]
+ returnself.results_df[selected_columns].head(n)
+
+
[docs]defdrop_duplicates(self)->None:
+"""Drops duplicates in results DataFrame"""
+ self.results_df.drop_duplicates(subset=["outstanding amount"],inplace=True)
+
+
[docs]defslice_results(
+ self,tolerance:float=0.0
+ )->tuple[
+ tuple[NDArray[np.float_],NDArray[np.float_]],
+ tuple[NDArray[np.float_],NDArray[np.float_]],
+ ]:
+"""Helper function that slices the results in two groups, those results that
+ satisfy all constraints and those that violate at least one of the growth factor
+ or emission constraints.
+
+ Args:
+ tolerance: tolerance on how strict the constraints need to be satisfied (in
+ percentage point). Example: if the desired target growth rate is 1.2, if
+ the tolerance is set to 0.05 (5%). Solutions that increase outstanding
+ amount by a factor of 1.15 are considered to satisfy the constraints
+ given the tolerance.
+
+ Returns:
+ Relative difference (diversification, roc) coordinates for solutions that
+ satisfy all constraints, and for those that do not satisfy all constraints.
+
+ Raises:
+ ValueError: when there are no emission or growth factor constraints set.
+ """
+ if(
+ self.provided_growth_targetisNone
+ andlen(self.provided_emission_constraints)==0
+ ):
+ raiseValueError("There are no emission or growth constraints set.")
+
+ mask_growth_target=(
+ True
+ ifself.provided_growth_targetisNone
+ else(
+ self.results_df["diff outstanding"]
+ >=100*(self.provided_growth_target-tolerance-1)
+ )
+ )
+
+ mask_emission_constraint=True
+ for_,_,value,nameinself.provided_emission_constraints:
+ mask_emission_constraint&=self.results_df["diff "+name]<=100*(
+ (value+tolerance)-1
+ )
+
+ combined_mask=mask_growth_target&mask_emission_constraint
+
+ # Filter data based on masks
+ filtered_data_met=self.results_df[combined_mask]
+ filtered_data_violated=self.results_df[~combined_mask]
+
+ x_met=filtered_data_met["diff diversification"].to_numpy()
+ y_met=filtered_data_met["diff ROC"].to_numpy()
+ x_violated=filtered_data_violated["diff diversification"].to_numpy()
+ y_violated=filtered_data_violated["diff ROC"].to_numpy()
+ return(x_met,y_met),(x_violated,y_violated)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/_modules/portfolio_optimization/components/visualization.html b/docs/_modules/portfolio_optimization/components/visualization.html
new file mode 100644
index 0000000..2444ac7
--- /dev/null
+++ b/docs/_modules/portfolio_optimization/components/visualization.html
@@ -0,0 +1,251 @@
+
+
+
+
+
+ portfolio_optimization.components.visualization — tno.quantum.problems.portfolio_optimization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[docs]defplot_points(
+ diversification_values:ArrayLike,
+ roc_values:ArrayLike,
+ color:str|None=None,
+ label:str|None=None,
+ c:ArrayLike|Sequence[ColorType]|ColorType|None=None,
+ vmin:float|None=None,
+ vmax:float|None=None,
+ alpha:float|None=None,
+ cmap:str|Colormap|None=None,
+ ax:Axes|None=None,# pylint: disable=invalid-name
+)->PatchCollection|Any:
+"""Plots the given data-points in a Diversification-ROC plot.
+
+ Args:
+ diversification_values: 1-D ``ArrayLike`` containing the x values of the plot.
+ roc_values: 1-D ``ArrayLike`` containing the y values of the plot.
+ color: Optional color to use for the points. For an overview of allowed colors
+ see the `Matplotlib Documentation`_. If ``None`` is given, a default color
+ will be assigned by ``matplotlib``. Default is ``None``.
+ label: Label to use in the legend. If ``None`` is given, no label will be used.
+ Default is ``None``.
+ c: The marker colors as used by ``matplotlib``.
+ vmin: min value of data range that colormap covers as used by ``matplotlib``.
+ vmax: max value of data range that colormap covers as used by ``matplotlib``.
+ alpha: The alpha blending value as used by ``matplotlib``.
+ cmap: The Colormap instance or registered colormap name as used by ``matplotlib``.
+ ax: ``Axes`` to plot on. If ``None``, a new figure with one ``Axes`` will be
+ created.
+
+ Returns:
+ The ``matplotlib`` PathCollection object created by scatter.
+
+ .. _Matplotlib Documentation: https://matplotlib.org/stable/gallery/color/named_colors.html
+ """
+ ifaxisNone:
+ _,ax=plt.subplots()
+ collection=ax.scatter(
+ diversification_values,
+ roc_values,
+ color=color,
+ c=c,
+ alpha=alpha,
+ vmin=vmin,
+ vmax=vmax,
+ cmap=cmap,
+ label=label,
+ )
+ ax.set_xlabel("Diversification Change (%)")
+ ax.set_ylabel("ROC Change (%)")
+ ax.grid()
+ iflabelisnotNone:
+ ax.legend()
+
+ xlim=ax.get_xlim()
+ ylim=ax.get_ylim()
+ ax.axhline(0,color="black",linewidth=1)
+ ax.axvline(0,color="black",linewidth=1)
+ ax.set_xlim(*xlim,auto=True)
+ ax.set_ylim(*ylim,auto=True)
+ returncollection
+
+
+
[docs]defplot_front(
+ diversification_values:ArrayLike,
+ roc_values:ArrayLike,
+ color:str|None=None,
+ label:str|None=None,
+ c:ArrayLike|Sequence[ColorType]|ColorType|None=None,
+ vmin:float|None=None,
+ vmax:float|None=None,
+ alpha:float|None=None,
+ cmap:str|Colormap|None=None,
+ ax:Axes|None=None,# pylint: disable=invalid-name
+)->PatchCollection:
+"""Plots a pareto front of the given data-points in a Diversification-ROC plot.
+
+ Args:
+ diversification_values: 1-D ``ArrayLike`` containing the x values of the plot.
+ roc_values: 1-D ``ArrayLike`` containing the y values of the plot.
+ color: Optional color to use for the points. For an overview of allowed colors
+ see the `Matplotlib Documentation`_. If ``None`` is given, a default color
+ will be assigned by ``matplotlib``. Default is ``None``.
+ label: Label to use in the legend. If ``None`` is given, no label will be used.
+ Default is ``None``.
+ c: The marker colors as used by ``matplotlib``.
+ vmin: min value of data range that colormap covers as used by ``matplotlib``.
+ vmax: max value of data range that colormap covers as used by ``matplotlib``.
+ alpha: The alpha blending value as used by ``matplotlib``.
+ cmap: The Colormap instance or registered colormap name as used by ``matplotlib``.
+ ax: ``Axes`` to plot on. If ``None``, a new figure with one ``Axes`` will be
+ created.
+
+ Returns:
+ The ``matplotlib`` PathCollection object created by scatter.
+
+ .. _Matplotlib Documentation: https://matplotlib.org/stable/gallery/color/named_colors.html
+ """
+ x_values,y_values=pareto_front(diversification_values,roc_values)
+ returnplot_points(
+ x_values,
+ y_values,
+ color=color,
+ c=c,
+ alpha=alpha,
+ vmin=vmin,
+ vmax=vmax,
+ cmap=cmap,
+ label=label,
+ ax=ax,
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/_modules/tno/quantum/problems/portfolio_optimization/_portfolio_optimizer.html b/docs/_modules/tno/quantum/problems/portfolio_optimization/_portfolio_optimizer.html
new file mode 100644
index 0000000..5e9d3c9
--- /dev/null
+++ b/docs/_modules/tno/quantum/problems/portfolio_optimization/_portfolio_optimizer.html
@@ -0,0 +1,566 @@
+
+
+
+
+
+ tno.quantum.problems.portfolio_optimization._portfolio_optimizer — tno.quantum.problems.portfolio_optimization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[docs]classPortfolioOptimizer:
+"""The ``PortfolioOptimizer`` class is used to convert multi-objective portfolio
+ optimization problems into QUBO problems which can then be solved using QUBO solving
+ techniques such as simulated or quantum annealing.
+
+ The following objectives can be considered
+
+ - `return on capital`, indicated by ROC,
+ - `diversification`, indicated by the `Herfindahl-Hirschman Index`_ HHI.
+
+ The following constraints can be added
+
+ - `capital growth`, demand a minimum increase in outstanding assets.
+ - `emission reduction`, demand a minimum reduction for an arbitrary emission type.
+
+ Usage example:
+
+ .. code-block::
+
+ import numpy as np
+ from dwave.samplers import SimulatedAnnealingSampler
+
+ from tno.quantum.problems.portfolio_optimization import PortfolioOptimizer
+
+ # Choose sampler for solving qubo
+ sampler = SimulatedAnnealingSampler()
+ sampler_kwargs = {"num_reads": 20, "num_sweeps": 200}
+
+ # Set up penalty coefficients for the constraints
+ lambdas1 = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+ lambdas2 = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+ lambdas3 = np.array([1])
+
+ # Create portfolio optimization problem
+ portfolio_optimizer = PortfolioOptimizer("benchmark_dataset")
+ portfolio_optimizer.add_minimize_hhi(weights=lambdas1)
+ portfolio_optimizer.add_maximize_roc(formulation=1, weights_roc=lambdas1)
+ portfolio_optimizer.add_emission_constraint(
+ weights=lambdas3,
+ emission_now="emis_intens_now",
+ emission_future="emis_intens_future",
+ name="emission",
+ )
+
+ # Solve the portfolio optimization problem
+ results = portfolio_optimizer.run(sampler, sampler_kwargs)
+ print(results.head())
+
+ .. _Herfindahl-Hirschman Index: https://nl.wikipedia.org/wiki/Herfindahl-index
+ """
+
+
[docs]def__init__(
+ self,
+ portfolio_data:PortfolioData|DataFrame|str|Path,
+ k:int=2,
+ columns_rename:dict[str,str]|None=None,
+ )->None:
+"""Init ``PortfolioOptimizer``.
+
+ Args:
+ portfolio_data: Portfolio data represented by a ``PortfolioData`` object,
+ a pandas ``DataFrame`` or a path to where portfolio data is stored. See
+ the docstring of
+ :py:class:`~portfolio_optimization.components.io.PortfolioData` for data
+ input conventions.
+ k: The number of bits that are used to represent the outstanding amount for
+ each asset. A fixed point representation is used to represent `$2^k$`
+ different equidistant values in the range `$[LB_i, UB_i]$` for asset i.
+ column_rename: can be used to rename data columns. See the docstring of
+ :py:class:`~portfolio_optimization.components.io.PortfolioData` for
+ example.
+
+ Raises:
+ TypeError: If the provided ``portfolio_data`` input has the wrong type.
+ """
+ ifisinstance(portfolio_data,PortfolioData):
+ self.portfolio_data=portfolio_data
+ elifisinstance(portfolio_data,DataFrame):
+ self.portfolio_data=PortfolioData(portfolio_data,columns_rename)
+ elifisinstance(portfolio_data,(Path,str)):
+ self.portfolio_data=PortfolioData.from_file(
+ portfolio_data,columns_rename
+ )
+ else:
+ raiseTypeError(
+ "`portfolio_data` must be of type `PortfolioData`, `DataFrame`, `Path` "
+ f"or `str`, but was of type {type(portfolio_data)}"
+ )
+ self._qubo_compiler=QuboCompiler(self.portfolio_data,k)
+ self.decoder=Decoder(self.portfolio_data,k)
+ self._all_lambdas:list[NDArray[np.float_]]=[]
+ self._provided_emission_constraints:list[tuple[str,str,float,str]]=[]
+ self._provided_growth_target:float|None=None
+
+
[docs]defadd_minimize_hhi(self,weights:ArrayLike|None=None)->None:
+r"""Adds the minimize HHI objective to the portfolio optimization problem.
+
+ The HHI objective is given by
+
+ $$HHI(x) = \sum_{i=1}^N\left(\frac{x_i}{\sum_{j=1}^N x_j}\right)^2,$$
+
+ where
+
+ - `$N$` is the total number of assets,
+ - `$x_i$` is the future outstanding amount for asset `$i$`.
+
+ As the objective contains non-quadratic terms, a QUBO formulation requires
+ approximations. For the QUBO formulation, see the docs of
+ :py:class:`~portfolio_optimization.components.qubos.QuboFactory`.
+ :py:meth:`~portfolio_optimization.components.qubos.QuboFactory.calc_minimize_hhi`.
+
+ Usage example:
+
+ >>> from tno.quantum.problems.portfolio_optimization import PortfolioOptimizer
+ >>> import numpy as np
+ >>> portfolio_optimizer = PortfolioOptimizer(filename="benchmark_dataset")
+ >>> lambdas = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+ >>> portfolio_optimizer.add_minimize_hhi(weights=lambdas)
+
+ Args:
+ weights: The coefficients that are considered as penalty parameter.
+ """
+ self._all_lambdas.append(self._parse_weight(weights))
+ self._qubo_compiler.add_minimize_hhi()
+
+
[docs]defadd_maximize_roc(
+ self,
+ formulation:int,
+ weights_roc:ArrayLike|None=None,
+ ancilla_variables:int=0,
+ weights_stabilize:ArrayLike|None=None,
+ )->None:
+r"""Adds the maximize ROC objective to the portfolio optimization problem.
+
+ The ROC objective is given by
+
+ .. math::
+
+ ROC(x) =
+ \frac{\sum_{i=1}^N \frac{x_i \cdot r_i}{y_i}}
+ {\sum_{i=1}^N \frac{x_i \cdot c_i}{y_i}},
+
+ where
+
+ - `$N$` is the total number of assets,
+ - `$x_i$` is the future outstanding amount for asset `$i$`,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - `$r_i$` is the return for asset `$i$`,
+ - `$c_i$` is the regulatory capital for asset `$i$`.
+
+ As the ROC is not a quadratic function, it is approximated using two different
+ formulations:
+
+ formulation 1:
+ $$ROC_1(x)=\sum_{i=1}^N\frac{x_i\cdot r_i}{c_i\cdot y_i}$$
+
+ Adds 1 qubo term, use ``weights_roc`` to scale.
+
+ formulation 2:
+ $$ROC_2(x)=\frac{1}{G_C \cdot C_{21}}\sum_{i=1}^N x_i\frac{r_i}{y_i}$$
+
+ In this formulation, $G_C \cdot C_{21}$ approximates a fixed regulatory
+ capital growth which is equal for all assets, where
+
+ - `$1≤G_C<2$` is a growth factor to be estimated using ancilla variables,
+ - `$C_{21} = \sum_{i=1}^N c_{i}$` is the sum of all assets' regulatory capital.
+
+ This formulation adds 2 qubo terms, one for the ROC term, and one to stabilize the
+ capital growth. The stabilize qubo requires an extra argument ``ancilla_variables``.
+ Use ``weights_roc`` and ``weights_stabilize`` to scale both qubo's accordingly.
+
+ For the different QUBO formulations, see the docs of
+ :py:class:`~portfolio_optimization.components.qubos.QuboFactory`.
+
+ Usage example:
+
+ >>> from tno.quantum.problems.portfolio_optimization import PortfolioOptimizer
+ >>> import numpy as np
+ >>> portfolio_optimizer = PortfolioOptimizer(filename="benchmark_dataset")
+ >>> lambdas = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+ >>> portfolio_optimizer.add_maximize_roc(...)
+
+ Args:
+ formulation: the ROC QUBO formulation that is being used.
+ Possible options are: [1, 2].
+ weights_roc: The coefficients that are considered as penalty parameter for
+ maximizing the roc objective.
+ ancilla_variables: The number of ancillary variables that are used to
+ represent ``G_C`` using fixed point representation. Only relevant for
+ roc formulation ``2``.
+ weights_stabilize: The coefficients that are considered as penalty parameter
+ for the stabilizing constraint. Only relevant for roc formulation ``2``.
+
+ Raises:
+ ValueError: If invalid formulation is provided.
+ """
+ allowed_formulation_options=[1,2]
+ ifformulationnotinallowed_formulation_options:
+ raiseValueError(
+ "Invalid formulation input provided, "
+ f"choose from {allowed_formulation_options}."
+ )
+
+ self._all_lambdas.append(self._parse_weight(weights_roc))
+ ifformulation==2:
+ self._all_lambdas.append(self._parse_weight(weights_stabilize))
+ self._qubo_compiler.add_maximize_roc(formulation,ancilla_variables)
+
+
[docs]defadd_emission_constraint(
+ self,
+ emission_now:str,
+ emission_future:str|None=None,
+ reduction_percentage_target:float=0.7,
+ name:str|None=None,
+ weights:ArrayLike|None=None,
+ )->None:
+r"""Adds emission constraint to the portfolio optimization problem.
+
+ The constraint is given by
+
+ .. math::
+
+ \frac{\sum_{i=1}^Nf_i \cdot x_i}{\sum_{i=1}^N x_i}
+ =
+ g_e \frac{\sum_{i=1}^Ne_i \cdot y_i}{\sum_{i=1}^N y_i},
+
+ where:
+
+ - `$N$` is the total number of assets,
+ - `$x_i$` is the future outstanding amount for asset `$i$`,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - `$e_i$` is the current emission intensity for asset `$i$`,
+ - `$f_i$` is the expected emission intensity at the future for asset `$i$`,
+ - `$g_e$` is the target value for the relative emission reduction.
+
+ Usage example:
+
+ >>> from tno.quantum.problems.portfolio_optimization import PortfolioOptimizer
+ >>> import numpy as np
+ >>> portfolio_optimizer = PortfolioOptimizer(filename="benchmark_dataset")
+ >>> lambdas = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+ >>> portfolio_optimizer.add_emission_constraint(
+ ... emission_now="emis_intens_now", weights=lambdas
+ ... )
+
+ For the QUBO formulation, see the docs of
+ :py:class:`~portfolio_optimization.components.qubos.QuboFactory`.
+ :py:meth:`~portfolio_optimization.components.qubos.QuboFactory.calc_emission_constraint`.
+
+ Args:
+ emission_now: Name of the column in the portfolio dataset corresponding to
+ the variables emission intensity at current time.
+ emission_future: Name of the column in the portfolio dataset corresponding
+ to the variables emission intensity at future time. If no value is
+ provided, it is assumed that the emission intensity is constant over
+ time, i.e., the variable ``emission_now`` will be used.
+ reduction_percentage_target: target value for reduction percentage amount.
+ name: Name that will be used for emission constraint in the results df.
+ weights: The coefficients that are considered as penalty parameter.
+ """
+ # Store emission constraint information
+ ifnameisNone:
+ name=emission_now
+ ifemission_futureisNone:
+ emission_future=emission_now
+ self._provided_emission_constraints.append(
+ (emission_now,emission_future,reduction_percentage_target,name)
+ )
+ self._all_lambdas.append(self._parse_weight(weights))
+
+ self._qubo_compiler.add_emission_constraint(
+ emission_now=emission_now,
+ emission_future=emission_future,
+ reduction_percentage_target=reduction_percentage_target,
+ )
+
+
[docs]defadd_growth_factor_constraint(
+ self,growth_target:float,weights:ArrayLike|None=None
+ )->None:
+ # pylint: disable=line-too-long
+r"""Adds an outstanding amount growth factor constraint to the portfolio
+ optimization problem.
+
+ The constraint is given by
+
+ $$\frac{\sum_{i=1}^N x_i}{\sum_{i=1}^N y_i} = g_c,$$
+
+ where
+
+ - `$N$` is the total number of assets,
+ - `$x_i$` is the future outstanding amount for asset `$i$`,
+ - `$y_i$` is the current outstanding amount for asset `$i$`,
+ - `$g_c$` is the target value for the total growth factor.
+
+ This constraint can only be added once.
+
+ Usage example:
+
+ >>> from tno.quantum.problems.portfolio_optimization import PortfolioOptimizer
+ >>> import numpy as np
+ >>> portfolio_optimizer = PortfolioOptimizer(filename="benchmark_dataset")
+ >>> lambdas = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+ >>> portfolio_optimizer.add_emission_constraint(growth_target=1.2, weights=lambdas)
+
+ For the QUBO formulation, see the docs of
+ :py:class:`~portfolio_optimization.components.qubos.QuboFactory`.
+ :py:meth:`~portfolio_optimization.components.qubos.QuboFactory.calc_growth_factor_constraint`.
+
+ Args:
+ growth_target: target value for growth factor total outstanding amount.
+ weights: The coefficients that are considered as penalty parameter.
+
+ Raises:
+ ValueError: If constraint has been added before.
+ """
+ # pylint: enable=line-too-long
+ ifself._provided_growth_targetisnotNone:
+ raiseValueError("Growth factor constraint has been set before.")
+
+ self._all_lambdas.append(self._parse_weight(weights))
+ self._provided_growth_target=growth_target
+ self._qubo_compiler.add_growth_factor_constraint(growth_target)
+
+
[docs]defrun(
+ self,
+ sampler:Sampler|None=None,
+ sampler_kwargs:dict[str,Any]|None=None,
+ verbose:bool=True,
+ )->Results:
+ # pylint: disable=line-too-long
+"""
+ Optimizes a portfolio given the set of provided constraints.
+
+ Usage example:
+
+ >>> from tno.quantum.problems.portfolio_optimization import PortfolioOptimizer
+ >>> from dwave.samplers import SimulatedAnnealingSampler
+ >>> portfolio_optimizer = PortfolioOptimizer(filename="benchmark_dataset")
+ >>> portfolio_optimizer.add_minimize_HHI()
+ >>> portfolio_optimizer.run(sampler=SimulatedAnnealingSampler(), verbose=False)
+
+ Args:
+ sampler: Instance of a D-Wave Sampler that can be used to solve the QUBO.
+ More information can be found in the `D-Wave Ocean Documentation`_.
+ By default the ``SimulatedAnnealingSampler`` is being used.
+ sampler_kwargs: The sampler specific key-word arguments.
+ verbose: If True, print detailed information during execution
+
+ Returns:
+ results
+
+ Raises:
+ ValueError: if constraints are not set
+
+ .. _D-Wave Ocean Documentation: https://docs.ocean.dwavesys.com/projects/system/en/stable/reference/samplers.html
+
+ """
+ # pylint: enable=line-too-long
+ ifverbose:
+ self.portfolio_data.print_portfolio_info()
+
+ sampler=SimulatedAnnealingSampler()ifsamplerisNoneelsesampler
+ sampler_kwargs={}ifsampler_kwargsisNoneelsesampler_kwargs
+
+ ifverbose:
+ print("Status: creating model")
+ ifself._provided_growth_targetisnotNone:
+ print(f"Growth target: {self._provided_growth_target-1:.1%}")
+
+ for_,_,target_value,nameinself._provided_emission_constraints:
+ print(
+ f"Emission constraint: {name}, "
+ f"target reduction percentage: {target_value-1:.1%}"
+ )
+
+ self._qubo_compiler.compile()
+
+ results=Results(
+ portfolio_data=self.portfolio_data,
+ provided_emission_constraints=self._provided_emission_constraints,
+ provided_growth_target=self._provided_growth_target,
+ )
+
+ ifverbose:
+ print("Status: calculating")
+ starttime=datetime.now()
+
+ total_steps=math.prod(map(len,self._all_lambdas))
+ lambdas_iterator=tqdm(
+ itertools.product(*self._all_lambdas),total=total_steps
+ )
+
+ forlambdasinlambdas_iterator:
+ # Compile the model and generate QUBO
+ qubo,_=self._qubo_compiler.make_qubo(*lambdas)
+ # Solve the QUBO
+ response=sampler.sample_qubo(qubo,**sampler_kwargs)
+ # Postprocess solution. Iterate over all found solutions. (Compute future portfolios)
+ outstanding_future_samples=self.decoder.decode_sampleset(response)
+ results.add_result(outstanding_future_samples)
+
+ ifverbose:
+ print("Drop duplicate samples in results.")
+ results.drop_duplicates()
+
+ ifverbose:
+ print("Number of unique samples: ",len(results))
+ print("Time consumed:",datetime.now()-starttime)
+
+ returnresults
+
+ @staticmethod
+ def_parse_weight(weights:ArrayLike|None=None)->NDArray[np.float_]:
+"""Converts weights into NumPy array and if needed set default weights to [1.0]
+
+ Args:
+ weights: penalty coefficients.
+
+ Returns:
+ Numpy array of weights
+ """
+ ifweightsisNone:
+ returnnp.array([1.0])
+ returnnp.asarray(weights,dtype=np.float_)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/_modules/tno/quantum/problems/portfolio_optimization/components/visualization.html b/docs/_modules/tno/quantum/problems/portfolio_optimization/components/visualization.html
new file mode 100644
index 0000000..1fbef1b
--- /dev/null
+++ b/docs/_modules/tno/quantum/problems/portfolio_optimization/components/visualization.html
@@ -0,0 +1,251 @@
+
+
+
+
+
+ tno.quantum.problems.portfolio_optimization.components.visualization — tno.quantum.problems.portfolio_optimization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[docs]defplot_points(
+ diversification_values:ArrayLike,
+ roc_values:ArrayLike,
+ color:str|None=None,
+ label:str|None=None,
+ c:ArrayLike|Sequence[ColorType]|ColorType|None=None,
+ vmin:float|None=None,
+ vmax:float|None=None,
+ alpha:float|None=None,
+ cmap:str|Colormap|None=None,
+ ax:Axes|None=None,# pylint: disable=invalid-name
+)->PatchCollection|Any:
+"""Plots the given data-points in a Diversification-ROC plot.
+
+ Args:
+ diversification_values: 1-D ``ArrayLike`` containing the x values of the plot.
+ roc_values: 1-D ``ArrayLike`` containing the y values of the plot.
+ color: Optional color to use for the points. For an overview of allowed colors
+ see the `Matplotlib Documentation`_. If ``None`` is given, a default color
+ will be assigned by ``matplotlib``. Default is ``None``.
+ label: Label to use in the legend. If ``None`` is given, no label will be used.
+ Default is ``None``.
+ c: The marker colors as used by ``matplotlib``.
+ vmin: min value of data range that colormap covers as used by ``matplotlib``.
+ vmax: max value of data range that colormap covers as used by ``matplotlib``.
+ alpha: The alpha blending value as used by ``matplotlib``.
+ cmap: The Colormap instance or registered colormap name as used by ``matplotlib``.
+ ax: ``Axes`` to plot on. If ``None``, a new figure with one ``Axes`` will be
+ created.
+
+ Returns:
+ The ``matplotlib`` PathCollection object created by scatter.
+
+ .. _Matplotlib Documentation: https://matplotlib.org/stable/gallery/color/named_colors.html
+ """
+ ifaxisNone:
+ _,ax=plt.subplots()
+ collection=ax.scatter(
+ diversification_values,
+ roc_values,
+ color=color,
+ c=c,
+ alpha=alpha,
+ vmin=vmin,
+ vmax=vmax,
+ cmap=cmap,
+ label=label,
+ )
+ ax.set_xlabel("Diversification Change (%)")
+ ax.set_ylabel("ROC Change (%)")
+ ax.grid()
+ iflabelisnotNone:
+ ax.legend()
+
+ xlim=ax.get_xlim()
+ ylim=ax.get_ylim()
+ ax.axhline(0,color="black",linewidth=1)
+ ax.axvline(0,color="black",linewidth=1)
+ ax.set_xlim(*xlim,auto=True)
+ ax.set_ylim(*ylim,auto=True)
+ returncollection
+
+
+
[docs]defplot_front(
+ diversification_values:ArrayLike,
+ roc_values:ArrayLike,
+ color:str|None=None,
+ label:str|None=None,
+ c:ArrayLike|Sequence[ColorType]|ColorType|None=None,
+ vmin:float|None=None,
+ vmax:float|None=None,
+ alpha:float|None=None,
+ cmap:str|Colormap|None=None,
+ ax:Axes|None=None,# pylint: disable=invalid-name
+)->PatchCollection:
+"""Plots a pareto front of the given data-points in a Diversification-ROC plot.
+
+ Args:
+ diversification_values: 1-D ``ArrayLike`` containing the x values of the plot.
+ roc_values: 1-D ``ArrayLike`` containing the y values of the plot.
+ color: Optional color to use for the points. For an overview of allowed colors
+ see the `Matplotlib Documentation`_. If ``None`` is given, a default color
+ will be assigned by ``matplotlib``. Default is ``None``.
+ label: Label to use in the legend. If ``None`` is given, no label will be used.
+ Default is ``None``.
+ c: The marker colors as used by ``matplotlib``.
+ vmin: min value of data range that colormap covers as used by ``matplotlib``.
+ vmax: max value of data range that colormap covers as used by ``matplotlib``.
+ alpha: The alpha blending value as used by ``matplotlib``.
+ cmap: The Colormap instance or registered colormap name as used by ``matplotlib``.
+ ax: ``Axes`` to plot on. If ``None``, a new figure with one ``Axes`` will be
+ created.
+
+ Returns:
+ The ``matplotlib`` PathCollection object created by scatter.
+
+ .. _Matplotlib Documentation: https://matplotlib.org/stable/gallery/color/named_colors.html
+ """
+ x_values,y_values=pareto_front(diversification_values,roc_values)
+ returnplot_points(
+ x_values,
+ y_values,
+ color=color,
+ c=c,
+ alpha=alpha,
+ vmin=vmin,
+ vmax=vmax,
+ cmap=cmap,
+ label=label,
+ ax=ax,
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt
new file mode 100644
index 0000000..49e58d4
--- /dev/null
+++ b/docs/_sources/index.rst.txt
@@ -0,0 +1,248 @@
+.. tno.quantum.problems.portfolio_optimization documentation master file, created by
+ sphinx-quickstart on Wed May 1 16:21:09 2024.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+
+TNO Quantum
+===========
+TNO Quantum provides generic software components aimed at facilitating the development
+of quantum applications.
+
+Portfolio optimization
+======================
+
+Real-world investment decisions involve multiple, often conflicting, objectives that needs to be balanced.
+Primary goals typically revolve around maximizing returns while minimizing risks.
+At the same time, one might want to require additional constraints such as demanding a minimum carbon footprint reduction.
+Finding a portfolio that balances these objectives is a challenging task and can be solved using multi-objective portfolio optimization.
+
+
+This repository provides Python code that converts the multi-objective portfolio optimization problem
+into a `QUBO`_ problem. The transformed problem can then be solved using quantum annealing techniques.
+
+The following objectives can be considered
+
+- `return on capital`, indicated by ROC,
+- `diversification`, indicated by the `Herfindahl-Hirschman Index`_ HHI.
+
+Additionally, we allow for a capital growth factor and arbitrary emission reduction constraints to be considered.
+
+The `Pareto front`_, the set of solutions where one objective can't be improved without worsening the other objective,
+can be computed for the objectives return on capital and diversification.
+
+The codebase is based on the following paper:
+
+- `Aguilera et al., - Multi-objective Portfolio Optimisation Using the Quantum Annealer (2024)`_
+
+.. _Aguilera et al., - Multi-objective Portfolio Optimisation Using the Quantum Annealer (2024): https://www.mdpi.com/2227-7390/12/9/1291
+.. _Herfindahl-Hirschman Index: https://en.wikipedia.org/wiki/Herfindahl%E2%80%93Hirschman_index
+.. _Pareto front: https://en.wikipedia.org/wiki/Pareto_front
+.. _QUBO: https://en.wikipedia.org/wiki/Quadratic_unconstrained_binary_optimization
+
+
+**Funding:** This research was funded by Rabobank and Stichting TKI High Tech Systems
+and Materials, under a program by Brightland's Techruption.
+
+Quick Install
+-------------
+The portfolio optimization module can be installed using pip as follows::
+
+ pip install tno.quantum.problems.portfolio_optimization
+
+Examples
+--------
+
+Here's an example of how the :py:class:`~portfolio_optimization.PortfolioOptimizer` class
+can be used to define an portfolio optimization problem, and subsequently, how the Pareto front can be computed
+using the simulated annealing sampler from D-Wave.
+
+
+.. code-block:: python
+
+ import numpy as np
+ from dwave.samplers import SimulatedAnnealingSampler
+
+ from tno.quantum.problems.portfolio_optimization import PortfolioOptimizer
+
+ # Choose sampler for solving qubo
+ sampler = SimulatedAnnealingSampler()
+ sampler_kwargs = {"num_reads": 20, "num_sweeps": 200}
+
+ # Set up penalty coefficients for the constraints
+ lambdas1 = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+ lambdas2 = np.logspace(-16, 1, 25, endpoint=False, base=10.0)
+ lambdas3 = np.array([1])
+
+ # Create portfolio optimization problem
+ portfolio_optimizer = PortfolioOptimizer("benchmark_dataset")
+ portfolio_optimizer.add_minimize_hhi(weights=lambdas1)
+ portfolio_optimizer.add_maximize_roc(formulation=1, weights_roc=lambdas2)
+ portfolio_optimizer.add_emission_constraint(
+ weights=lambdas3,
+ emission_now="emis_intens_now",
+ emission_future="emis_intens_future",
+ name="emission"
+ )
+
+ # Solve the portfolio optimization problem
+ results = portfolio_optimizer.run(sampler, sampler_kwargs)
+ print(results.head())
+
+The results can be inspected in more detail by looking at the Pandas results DataFrame
+`results.results_df`.
+
+Alternatively, the results can be plotted in a `(Diversification, ROC)`-graph. The
+following example first slices the results in data points that do and do not satisfy the
+constraints using the method :py:meth:`~portfolio_optimization.components.results.Results.slice_results()`.
+
+Note that:
+
+- Individual data points can subsequently be plotted using :py:func:`~portfolio_optimization.components.visualization.plot_points()`
+- The Pareto front can be plotted using :py:func:`~portfolio_optimization.components.visualization.plot_front()`
+
+.. code-block:: python
+
+ import matplotlib.pyplot as plt
+
+ from tno.quantum.problems.portfolio_optimization import plot_front, plot_points
+
+ (x1, y1), (x2, y2) = results.slice_results()
+ fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 5))
+
+ # Plot data points
+ plot_points(x2, y2, color="orange", label="QUBO constraint not met", ax=ax1)
+ plot_points(x1, y1, color="green", label="QUBO constraint met", ax=ax1)
+ ax1.set_title("Points")
+
+ # Plot Pareto front
+ plot_front(x2, y2, color="orange", label="QUBO constraint not met", ax=ax2)
+ plot_front(x1, y1, color="green", label="QUBO constraint met", ax=ax2)
+ ax2.set_title("Pareto Front")
+ fig.tight_layout()
+ plt.show()
+
+.. image:: ../images_for_docs/example.png
+ :width: 1200
+ :align: center
+ :alt: (Diversification, ROC)-Graph
+
+More elaborate examples can be found in our `examples repository`_.
+
+.. _examples repository: https://github.com/TNO-Quantum/examples
+
+Data input
+----------
+
+The data used for the portfolio optimization can be imported via an excel file, csv file,
+json file or as a Pandas DataFrame.
+The data needs to contain at least the following columns:
+
+ - ``asset``: The name of the asset.
+ - ``outstanding_now``: Current outstanding amount per asset.
+ - ``min_outstanding_future``: Lower bound outstanding amount in the future per asset.
+ - ``max_outstanding_future``: Upper bound outstanding amount in the future per asset.
+ - ``income_now``: Current income per asset, corresponds to return multiplied by the current outstanding amount.
+ - ``regcap_now``: Current regulatory capital per asset.
+
+The table below shows an example dataset with the correct structure.
+Note that this is the least amount of columns that need to be present.
+More columns are allowed and required for some functionalities.
+
+.. list-table:: Example Dataset
+ :widths: 25 25 25 25 25 25
+ :header-rows: 1
+
+ * - asset
+ - outstanding_now
+ - min_outstanding_future
+ - max_outstanding_future
+ - income_now
+ - regcap_now
+ * - Sector 1 COUNTRY 1
+ - 10
+ - 14
+ - 19
+ - 5
+ - 5
+ * - Sector 2 COUNTRY 1
+ - 600
+ - 473
+ - 528
+ - 70
+ - 40
+ * - Sector 3 COUNTRY 1
+ - 20
+ - 24
+ - 28
+ - 5
+ - 10
+ * - Sector 4 COUNTRY 1
+ - 800
+ - 1090
+ - 1410
+ - 1
+ - 2
+ * - Sector 1 COUNTRY 2
+ - 40
+ - 56
+ - 74
+ - 10
+ - 5
+ * - Sector 2 COUNTRY 2
+ - 200
+ - 291
+ - 397
+ - 40
+ - 20
+ * - ...
+ - ...
+ - ...
+ - ...
+ - ...
+ - ...
+
+If the input datafile contains all the correct information, but has different column
+names, it is possible to rename the columns without altering the input file.
+Details and examples can be found in the documentation of
+:py:class:`~portfolio_optimization.components.io.PortfolioData`.
+
+
+Using Quantum Annealing Solvers
+-------------------------------
+
+By default, the portfolio optimization QUBO is solved using simulated annealing.
+Any D-Wave ``Sampler`` is however supported and can be provided to the
+:py:meth:`~portfolio_optimization.PortfolioOptimizer.run` method.
+
+
+Below is an example how to initialise a quantum annealing sampler that uses `100` micro seconds annealing time per sample.
+The example assumes a proper `configuration setup`_ to the D-Wave's Solver API.
+
+.. code-block:: python
+
+ from dwave.system import DWaveSampler, LazyFixedEmbeddingComposite
+
+ # Define QPU D-Wave Sampler
+ qpu = DWaveSampler()
+ sampler = LazyFixedEmbeddingComposite(qpu)
+ sampler_kwargs = {"annealing_time": 100}
+
+
+We refer to the `D-Wave Sampler documentation`_ for information on usage of different samplers and their sampler arguments.
+
+.. _configuration setup: https://docs.ocean.dwavesys.com/en/stable/overview/sapi.html
+.. _D-Wave Sampler documentation: https://docs.ocean.dwavesys.com/projects/system/en/stable/reference/samplers.html
+
+.. toctree::
+ :maxdepth: 4
+ :caption: Contents:
+ :hidden:
+
+ portfolio_optimization
+
+
+
+(End)use Limitations
+--------------------
+The content of this software may solely be used for applications that comply with international export control laws.
diff --git a/docs/_sources/portfolio_optimization.components.io.rst.txt b/docs/_sources/portfolio_optimization.components.io.rst.txt
new file mode 100644
index 0000000..6f3ab28
--- /dev/null
+++ b/docs/_sources/portfolio_optimization.components.io.rst.txt
@@ -0,0 +1,7 @@
+portfolio\_optimization.components.io module
+============================================
+
+.. automodule:: portfolio_optimization.components.io
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/_sources/portfolio_optimization.components.postprocess.rst.txt b/docs/_sources/portfolio_optimization.components.postprocess.rst.txt
new file mode 100644
index 0000000..35f91ca
--- /dev/null
+++ b/docs/_sources/portfolio_optimization.components.postprocess.rst.txt
@@ -0,0 +1,7 @@
+portfolio\_optimization.components.postprocess module
+=====================================================
+
+.. automodule:: portfolio_optimization.components.postprocess
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/_sources/portfolio_optimization.components.qubos.rst.txt b/docs/_sources/portfolio_optimization.components.qubos.rst.txt
new file mode 100644
index 0000000..e95c07c
--- /dev/null
+++ b/docs/_sources/portfolio_optimization.components.qubos.rst.txt
@@ -0,0 +1,7 @@
+portfolio\_optimization.components.qubos package
+================================================
+
+.. automodule:: portfolio_optimization.components.qubos
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/_sources/portfolio_optimization.components.results.rst.txt b/docs/_sources/portfolio_optimization.components.results.rst.txt
new file mode 100644
index 0000000..d1d9b3d
--- /dev/null
+++ b/docs/_sources/portfolio_optimization.components.results.rst.txt
@@ -0,0 +1,7 @@
+portfolio\_optimization.components.results module
+=================================================
+
+.. automodule:: portfolio_optimization.components.results
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/_sources/portfolio_optimization.components.rst.txt b/docs/_sources/portfolio_optimization.components.rst.txt
new file mode 100644
index 0000000..5033955
--- /dev/null
+++ b/docs/_sources/portfolio_optimization.components.rst.txt
@@ -0,0 +1,25 @@
+portfolio\_optimization.components package
+==========================================
+
+.. automodule:: portfolio_optimization.components
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Subpackages
+-----------
+.. toctree::
+ :maxdepth: 4
+
+
+ portfolio_optimization.components.qubos
+
+
+.. toctree::
+ :maxdepth: 4
+
+
+ portfolio_optimization.components.io
+ portfolio_optimization.components.postprocess
+ portfolio_optimization.components.results
+ portfolio_optimization.components.visualization
diff --git a/docs/_sources/portfolio_optimization.components.visualization.rst.txt b/docs/_sources/portfolio_optimization.components.visualization.rst.txt
new file mode 100644
index 0000000..d46ba55
--- /dev/null
+++ b/docs/_sources/portfolio_optimization.components.visualization.rst.txt
@@ -0,0 +1,7 @@
+portfolio\_optimization.components.visualization module
+=======================================================
+
+.. automodule:: portfolio_optimization.components.visualization
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/_sources/portfolio_optimization.rst.txt b/docs/_sources/portfolio_optimization.rst.txt
new file mode 100644
index 0000000..1c08254
--- /dev/null
+++ b/docs/_sources/portfolio_optimization.rst.txt
@@ -0,0 +1,15 @@
+portfolio\_optimization package
+===============================
+
+.. automodule:: portfolio_optimization
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Subpackages
+-----------
+.. toctree::
+ :maxdepth: 4
+
+
+ portfolio_optimization.components
diff --git a/docs/_static/TNO_blue.ico b/docs/_static/TNO_blue.ico
new file mode 100644
index 0000000..f00e3e8
Binary files /dev/null and b/docs/_static/TNO_blue.ico differ
diff --git a/docs/_static/TNO_wit.svg b/docs/_static/TNO_wit.svg
new file mode 100644
index 0000000..b5e61c2
--- /dev/null
+++ b/docs/_static/TNO_wit.svg
@@ -0,0 +1,32 @@
+
+
+
+
diff --git a/docs/_static/_sphinx_javascript_frameworks_compat.js b/docs/_static/_sphinx_javascript_frameworks_compat.js
new file mode 100644
index 0000000..8549469
--- /dev/null
+++ b/docs/_static/_sphinx_javascript_frameworks_compat.js
@@ -0,0 +1,134 @@
+/*
+ * _sphinx_javascript_frameworks_compat.js
+ * ~~~~~~~~~~
+ *
+ * Compatability shim for jQuery and underscores.js.
+ *
+ * WILL BE REMOVED IN Sphinx 6.0
+ * xref RemovedInSphinx60Warning
+ *
+ */
+
+/**
+ * select a different prefix for underscore
+ */
+$u = _.noConflict();
+
+
+/**
+ * small helper function to urldecode strings
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
+ */
+jQuery.urldecode = function(x) {
+ if (!x) {
+ return x
+ }
+ return decodeURIComponent(x.replace(/\+/g, ' '));
+};
+
+/**
+ * small helper function to urlencode strings
+ */
+jQuery.urlencode = encodeURIComponent;
+
+/**
+ * This function returns the parsed url parameters of the
+ * current request. Multiple values per key are supported,
+ * it will always return arrays of strings for the value parts.
+ */
+jQuery.getQueryParameters = function(s) {
+ if (typeof s === 'undefined')
+ s = document.location.search;
+ var parts = s.substr(s.indexOf('?') + 1).split('&');
+ var result = {};
+ for (var i = 0; i < parts.length; i++) {
+ var tmp = parts[i].split('=', 2);
+ var key = jQuery.urldecode(tmp[0]);
+ var value = jQuery.urldecode(tmp[1]);
+ if (key in result)
+ result[key].push(value);
+ else
+ result[key] = [value];
+ }
+ return result;
+};
+
+/**
+ * highlight a given string on a jquery object by wrapping it in
+ * span elements with the given class name.
+ */
+jQuery.fn.highlightText = function(text, className) {
+ function highlight(node, addItems) {
+ if (node.nodeType === 3) {
+ var val = node.nodeValue;
+ var pos = val.toLowerCase().indexOf(text);
+ if (pos >= 0 &&
+ !jQuery(node.parentNode).hasClass(className) &&
+ !jQuery(node.parentNode).hasClass("nohighlight")) {
+ var span;
+ var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
+ if (isInSVG) {
+ span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
+ } else {
+ span = document.createElement("span");
+ span.className = className;
+ }
+ span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+ node.parentNode.insertBefore(span, node.parentNode.insertBefore(
+ document.createTextNode(val.substr(pos + text.length)),
+ node.nextSibling));
+ node.nodeValue = val.substr(0, pos);
+ if (isInSVG) {
+ var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
+ var bbox = node.parentElement.getBBox();
+ rect.x.baseVal.value = bbox.x;
+ rect.y.baseVal.value = bbox.y;
+ rect.width.baseVal.value = bbox.width;
+ rect.height.baseVal.value = bbox.height;
+ rect.setAttribute('class', className);
+ addItems.push({
+ "parent": node.parentNode,
+ "target": rect});
+ }
+ }
+ }
+ else if (!jQuery(node).is("button, select, textarea")) {
+ jQuery.each(node.childNodes, function() {
+ highlight(this, addItems);
+ });
+ }
+ }
+ var addItems = [];
+ var result = this.each(function() {
+ highlight(this, addItems);
+ });
+ for (var i = 0; i < addItems.length; ++i) {
+ jQuery(addItems[i].parent).before(addItems[i].target);
+ }
+ return result;
+};
+
+/*
+ * backward compatibility for jQuery.browser
+ * This will be supported until firefox bug is fixed.
+ */
+if (!jQuery.browser) {
+ jQuery.uaMatch = function(ua) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
+ /(webkit)[ \/]([\w.]+)/.exec(ua) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
+ /(msie) ([\w.]+)/.exec(ua) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+ };
+ jQuery.browser = {};
+ jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
+}
diff --git a/docs/_static/basic.css b/docs/_static/basic.css
new file mode 100644
index 0000000..4e9a9f1
--- /dev/null
+++ b/docs/_static/basic.css
@@ -0,0 +1,900 @@
+/*
+ * basic.css
+ * ~~~~~~~~~
+ *
+ * Sphinx stylesheet -- basic theme.
+ *
+ * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+ clear: both;
+}
+
+div.section::after {
+ display: block;
+ content: '';
+ clear: left;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+ width: 100%;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+ word-wrap: break-word;
+ overflow-wrap : break-word;
+}
+
+div.sphinxsidebar ul {
+ list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+div.sphinxsidebar #searchbox form.search {
+ overflow: hidden;
+}
+
+div.sphinxsidebar #searchbox input[type="text"] {
+ float: left;
+ width: 80%;
+ padding: 0.25em;
+ box-sizing: border-box;
+}
+
+div.sphinxsidebar #searchbox input[type="submit"] {
+ float: left;
+ width: 20%;
+ border-left: none;
+ padding: 0.25em;
+ box-sizing: border-box;
+}
+
+
+img {
+ border: 0;
+ max-width: 100%;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li p.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ width: 90%;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable {
+ width: 100%;
+}
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable ul {
+ margin-top: 0;
+ margin-bottom: 0;
+ list-style-type: none;
+}
+
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+div.modindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+div.genindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+/* -- domain module index --------------------------------------------------- */
+
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+div.body {
+ min-width: 360px;
+ max-width: 800px;
+}
+
+div.body p, div.body dd, div.body li, div.body blockquote {
+ -moz-hyphens: auto;
+ -ms-hyphens: auto;
+ -webkit-hyphens: auto;
+ hyphens: auto;
+}
+
+a.headerlink {
+ visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink,
+caption:hover > a.headerlink,
+p.caption:hover > a.headerlink,
+div.code-block-caption:hover > a.headerlink {
+ visibility: visible;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+img.align-left, figure.align-left, .figure.align-left, object.align-left {
+ clear: left;
+ float: left;
+ margin-right: 1em;
+}
+
+img.align-right, figure.align-right, .figure.align-right, object.align-right {
+ clear: right;
+ float: right;
+ margin-left: 1em;
+}
+
+img.align-center, figure.align-center, .figure.align-center, object.align-center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+img.align-default, figure.align-default, .figure.align-default {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.align-left {
+ text-align: left;
+}
+
+.align-center {
+ text-align: center;
+}
+
+.align-default {
+ text-align: center;
+}
+
+.align-right {
+ text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar,
+aside.sidebar {
+ margin: 0 0 0.5em 1em;
+ border: 1px solid #ddb;
+ padding: 7px;
+ background-color: #ffe;
+ width: 40%;
+ float: right;
+ clear: right;
+ overflow-x: auto;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+}
+nav.contents,
+aside.topic,
+div.admonition, div.topic, blockquote {
+ clear: left;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+nav.contents,
+aside.topic,
+div.topic {
+ border: 1px solid #ccc;
+ padding: 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+/* -- content of sidebars/topics/admonitions -------------------------------- */
+
+div.sidebar > :last-child,
+aside.sidebar > :last-child,
+nav.contents > :last-child,
+aside.topic > :last-child,
+div.topic > :last-child,
+div.admonition > :last-child {
+ margin-bottom: 0;
+}
+
+div.sidebar::after,
+aside.sidebar::after,
+nav.contents::after,
+aside.topic::after,
+div.topic::after,
+div.admonition::after,
+blockquote::after {
+ display: block;
+ content: '';
+ clear: both;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ border: 0;
+ border-collapse: collapse;
+}
+
+table.align-center {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table.align-default {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table caption span.caption-number {
+ font-style: italic;
+}
+
+table caption span.caption-text {
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 5px;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px;
+}
+
+table.citation td {
+ border-bottom: none;
+}
+
+th > :first-child,
+td > :first-child {
+ margin-top: 0px;
+}
+
+th > :last-child,
+td > :last-child {
+ margin-bottom: 0px;
+}
+
+/* -- figures --------------------------------------------------------------- */
+
+div.figure, figure {
+ margin: 0.5em;
+ padding: 0.5em;
+}
+
+div.figure p.caption, figcaption {
+ padding: 0.3em;
+}
+
+div.figure p.caption span.caption-number,
+figcaption span.caption-number {
+ font-style: italic;
+}
+
+div.figure p.caption span.caption-text,
+figcaption span.caption-text {
+}
+
+/* -- field list styles ----------------------------------------------------- */
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+.field-name {
+ -moz-hyphens: manual;
+ -ms-hyphens: manual;
+ -webkit-hyphens: manual;
+ hyphens: manual;
+}
+
+/* -- hlist styles ---------------------------------------------------------- */
+
+table.hlist {
+ margin: 1em 0;
+}
+
+table.hlist td {
+ vertical-align: top;
+}
+
+/* -- object description styles --------------------------------------------- */
+
+.sig {
+ font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
+}
+
+.sig-name, code.descname {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+.sig-name {
+ font-size: 1.1em;
+}
+
+code.descname {
+ font-size: 1.2em;
+}
+
+.sig-prename, code.descclassname {
+ background-color: transparent;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.sig-paren {
+ font-size: larger;
+}
+
+.sig-param.n {
+ font-style: italic;
+}
+
+/* C++ specific styling */
+
+.sig-inline.c-texpr,
+.sig-inline.cpp-texpr {
+ font-family: unset;
+}
+
+.sig.c .k, .sig.c .kt,
+.sig.cpp .k, .sig.cpp .kt {
+ color: #0033B3;
+}
+
+.sig.c .m,
+.sig.cpp .m {
+ color: #1750EB;
+}
+
+.sig.c .s, .sig.c .sc,
+.sig.cpp .s, .sig.cpp .sc {
+ color: #067D17;
+}
+
+
+/* -- other body styles ----------------------------------------------------- */
+
+ol.arabic {
+ list-style: decimal;
+}
+
+ol.loweralpha {
+ list-style: lower-alpha;
+}
+
+ol.upperalpha {
+ list-style: upper-alpha;
+}
+
+ol.lowerroman {
+ list-style: lower-roman;
+}
+
+ol.upperroman {
+ list-style: upper-roman;
+}
+
+:not(li) > ol > li:first-child > :first-child,
+:not(li) > ul > li:first-child > :first-child {
+ margin-top: 0px;
+}
+
+:not(li) > ol > li:last-child > :last-child,
+:not(li) > ul > li:last-child > :last-child {
+ margin-bottom: 0px;
+}
+
+ol.simple ol p,
+ol.simple ul p,
+ul.simple ol p,
+ul.simple ul p {
+ margin-top: 0;
+}
+
+ol.simple > li:not(:first-child) > p,
+ul.simple > li:not(:first-child) > p {
+ margin-top: 0;
+}
+
+ol.simple p,
+ul.simple p {
+ margin-bottom: 0;
+}
+aside.footnote > span,
+div.citation > span {
+ float: left;
+}
+aside.footnote > span:last-of-type,
+div.citation > span:last-of-type {
+ padding-right: 0.5em;
+}
+aside.footnote > p {
+ margin-left: 2em;
+}
+div.citation > p {
+ margin-left: 4em;
+}
+aside.footnote > p:last-of-type,
+div.citation > p:last-of-type {
+ margin-bottom: 0em;
+}
+aside.footnote > p:last-of-type:after,
+div.citation > p:last-of-type:after {
+ content: "";
+ clear: both;
+}
+
+dl.field-list {
+ display: grid;
+ grid-template-columns: fit-content(30%) auto;
+}
+
+dl.field-list > dt {
+ font-weight: bold;
+ word-break: break-word;
+ padding-left: 0.5em;
+ padding-right: 5px;
+}
+
+dl.field-list > dd {
+ padding-left: 0.5em;
+ margin-top: 0em;
+ margin-left: 0em;
+ margin-bottom: 0em;
+}
+
+dl {
+ margin-bottom: 15px;
+}
+
+dd > :first-child {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+dl > dd:last-child,
+dl > dd:last-child > :last-child {
+ margin-bottom: 0;
+}
+
+dt:target, span.highlighted {
+ background-color: #fbe54e;
+}
+
+rect.highlighted {
+ fill: #fbe54e;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+.footnote:target {
+ background-color: #ffa;
+}
+
+.line-block {
+ display: block;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.line-block .line-block {
+ margin-top: 0;
+ margin-bottom: 0;
+ margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+ font-family: sans-serif;
+}
+
+.accelerator {
+ text-decoration: underline;
+}
+
+.classifier {
+ font-style: oblique;
+}
+
+.classifier:before {
+ font-style: normal;
+ margin: 0 0.5em;
+ content: ":";
+ display: inline-block;
+}
+
+abbr, acronym {
+ border-bottom: dotted 1px;
+ cursor: help;
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+ overflow: auto;
+ overflow-y: hidden; /* fixes display issues on Chrome browsers */
+}
+
+pre, div[class*="highlight-"] {
+ clear: both;
+}
+
+span.pre {
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ -webkit-hyphens: none;
+ hyphens: none;
+ white-space: nowrap;
+}
+
+div[class*="highlight-"] {
+ margin: 1em 0;
+}
+
+td.linenos pre {
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ display: block;
+}
+
+table.highlighttable tbody {
+ display: block;
+}
+
+table.highlighttable tr {
+ display: flex;
+}
+
+table.highlighttable td {
+ margin: 0;
+ padding: 0;
+}
+
+table.highlighttable td.linenos {
+ padding-right: 0.5em;
+}
+
+table.highlighttable td.code {
+ flex: 1;
+ overflow: hidden;
+}
+
+.highlight .hll {
+ display: block;
+}
+
+div.highlight pre,
+table.highlighttable pre {
+ margin: 0;
+}
+
+div.code-block-caption + div {
+ margin-top: 0;
+}
+
+div.code-block-caption {
+ margin-top: 1em;
+ padding: 2px 5px;
+ font-size: small;
+}
+
+div.code-block-caption code {
+ background-color: transparent;
+}
+
+table.highlighttable td.linenos,
+span.linenos,
+div.highlight span.gp { /* gp: Generic.Prompt */
+ user-select: none;
+ -webkit-user-select: text; /* Safari fallback only */
+ -webkit-user-select: none; /* Chrome/Safari */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* IE10+ */
+}
+
+div.code-block-caption span.caption-number {
+ padding: 0.1em 0.3em;
+ font-style: italic;
+}
+
+div.code-block-caption span.caption-text {
+}
+
+div.literal-block-wrapper {
+ margin: 1em 0;
+}
+
+code.xref, a code {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
+ background-color: transparent;
+}
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+ margin: -1px -10px;
+ padding: 0 10px;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+ vertical-align: middle;
+}
+
+div.body div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+span.eqno a.headerlink {
+ position: absolute;
+ z-index: 1;
+}
+
+div.math:hover a.headerlink {
+ visibility: visible;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0 !important;
+ width: 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ #top-link {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/docs/_static/css/badge_only.css b/docs/_static/css/badge_only.css
new file mode 100644
index 0000000..c718cee
--- /dev/null
+++ b/docs/_static/css/badge_only.css
@@ -0,0 +1 @@
+.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
\ No newline at end of file
diff --git a/docs/_static/css/fonts/Roboto-Slab-Bold.woff b/docs/_static/css/fonts/Roboto-Slab-Bold.woff
new file mode 100644
index 0000000..6cb6000
Binary files /dev/null and b/docs/_static/css/fonts/Roboto-Slab-Bold.woff differ
diff --git a/docs/_static/css/fonts/Roboto-Slab-Bold.woff2 b/docs/_static/css/fonts/Roboto-Slab-Bold.woff2
new file mode 100644
index 0000000..7059e23
Binary files /dev/null and b/docs/_static/css/fonts/Roboto-Slab-Bold.woff2 differ
diff --git a/docs/_static/css/fonts/Roboto-Slab-Regular.woff b/docs/_static/css/fonts/Roboto-Slab-Regular.woff
new file mode 100644
index 0000000..f815f63
Binary files /dev/null and b/docs/_static/css/fonts/Roboto-Slab-Regular.woff differ
diff --git a/docs/_static/css/fonts/Roboto-Slab-Regular.woff2 b/docs/_static/css/fonts/Roboto-Slab-Regular.woff2
new file mode 100644
index 0000000..f2c76e5
Binary files /dev/null and b/docs/_static/css/fonts/Roboto-Slab-Regular.woff2 differ
diff --git a/docs/_static/css/fonts/fontawesome-webfont.eot b/docs/_static/css/fonts/fontawesome-webfont.eot
new file mode 100644
index 0000000..e9f60ca
Binary files /dev/null and b/docs/_static/css/fonts/fontawesome-webfont.eot differ
diff --git a/docs/_static/css/fonts/fontawesome-webfont.svg b/docs/_static/css/fonts/fontawesome-webfont.svg
new file mode 100644
index 0000000..855c845
--- /dev/null
+++ b/docs/_static/css/fonts/fontawesome-webfont.svg
@@ -0,0 +1,2671 @@
+
+
+
diff --git a/docs/_static/css/fonts/fontawesome-webfont.ttf b/docs/_static/css/fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000..35acda2
Binary files /dev/null and b/docs/_static/css/fonts/fontawesome-webfont.ttf differ
diff --git a/docs/_static/css/fonts/fontawesome-webfont.woff b/docs/_static/css/fonts/fontawesome-webfont.woff
new file mode 100644
index 0000000..400014a
Binary files /dev/null and b/docs/_static/css/fonts/fontawesome-webfont.woff differ
diff --git a/docs/_static/css/fonts/fontawesome-webfont.woff2 b/docs/_static/css/fonts/fontawesome-webfont.woff2
new file mode 100644
index 0000000..4d13fc6
Binary files /dev/null and b/docs/_static/css/fonts/fontawesome-webfont.woff2 differ
diff --git a/docs/_static/css/fonts/lato-bold-italic.woff b/docs/_static/css/fonts/lato-bold-italic.woff
new file mode 100644
index 0000000..88ad05b
Binary files /dev/null and b/docs/_static/css/fonts/lato-bold-italic.woff differ
diff --git a/docs/_static/css/fonts/lato-bold-italic.woff2 b/docs/_static/css/fonts/lato-bold-italic.woff2
new file mode 100644
index 0000000..c4e3d80
Binary files /dev/null and b/docs/_static/css/fonts/lato-bold-italic.woff2 differ
diff --git a/docs/_static/css/fonts/lato-bold.woff b/docs/_static/css/fonts/lato-bold.woff
new file mode 100644
index 0000000..c6dff51
Binary files /dev/null and b/docs/_static/css/fonts/lato-bold.woff differ
diff --git a/docs/_static/css/fonts/lato-bold.woff2 b/docs/_static/css/fonts/lato-bold.woff2
new file mode 100644
index 0000000..bb19504
Binary files /dev/null and b/docs/_static/css/fonts/lato-bold.woff2 differ
diff --git a/docs/_static/css/fonts/lato-normal-italic.woff b/docs/_static/css/fonts/lato-normal-italic.woff
new file mode 100644
index 0000000..76114bc
Binary files /dev/null and b/docs/_static/css/fonts/lato-normal-italic.woff differ
diff --git a/docs/_static/css/fonts/lato-normal-italic.woff2 b/docs/_static/css/fonts/lato-normal-italic.woff2
new file mode 100644
index 0000000..3404f37
Binary files /dev/null and b/docs/_static/css/fonts/lato-normal-italic.woff2 differ
diff --git a/docs/_static/css/fonts/lato-normal.woff b/docs/_static/css/fonts/lato-normal.woff
new file mode 100644
index 0000000..ae1307f
Binary files /dev/null and b/docs/_static/css/fonts/lato-normal.woff differ
diff --git a/docs/_static/css/fonts/lato-normal.woff2 b/docs/_static/css/fonts/lato-normal.woff2
new file mode 100644
index 0000000..3bf9843
Binary files /dev/null and b/docs/_static/css/fonts/lato-normal.woff2 differ
diff --git a/docs/_static/css/theme.css b/docs/_static/css/theme.css
new file mode 100644
index 0000000..19a446a
--- /dev/null
+++ b/docs/_static/css/theme.css
@@ -0,0 +1,4 @@
+html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*!
+ * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block}
\ No newline at end of file
diff --git a/docs/_static/custom.css b/docs/_static/custom.css
new file mode 100644
index 0000000..ade5d6e
--- /dev/null
+++ b/docs/_static/custom.css
@@ -0,0 +1,11 @@
+.wy-side-nav-search {
+ background-color: #082484;
+}
+
+.wy-side-nav-search>div.version {
+ color: #ffffff
+}
+
+.wy-nav-top {
+ background-color: #082484;
+}
\ No newline at end of file
diff --git a/docs/_static/doctools.js b/docs/_static/doctools.js
new file mode 100644
index 0000000..527b876
--- /dev/null
+++ b/docs/_static/doctools.js
@@ -0,0 +1,156 @@
+/*
+ * doctools.js
+ * ~~~~~~~~~~~
+ *
+ * Base JavaScript utilities for all Sphinx HTML documentation.
+ *
+ * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+"use strict";
+
+const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([
+ "TEXTAREA",
+ "INPUT",
+ "SELECT",
+ "BUTTON",
+]);
+
+const _ready = (callback) => {
+ if (document.readyState !== "loading") {
+ callback();
+ } else {
+ document.addEventListener("DOMContentLoaded", callback);
+ }
+};
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+const Documentation = {
+ init: () => {
+ Documentation.initDomainIndexTable();
+ Documentation.initOnKeyListeners();
+ },
+
+ /**
+ * i18n support
+ */
+ TRANSLATIONS: {},
+ PLURAL_EXPR: (n) => (n === 1 ? 0 : 1),
+ LOCALE: "unknown",
+
+ // gettext and ngettext don't access this so that the functions
+ // can safely bound to a different name (_ = Documentation.gettext)
+ gettext: (string) => {
+ const translated = Documentation.TRANSLATIONS[string];
+ switch (typeof translated) {
+ case "undefined":
+ return string; // no translation
+ case "string":
+ return translated; // translation exists
+ default:
+ return translated[0]; // (singular, plural) translation tuple exists
+ }
+ },
+
+ ngettext: (singular, plural, n) => {
+ const translated = Documentation.TRANSLATIONS[singular];
+ if (typeof translated !== "undefined")
+ return translated[Documentation.PLURAL_EXPR(n)];
+ return n === 1 ? singular : plural;
+ },
+
+ addTranslations: (catalog) => {
+ Object.assign(Documentation.TRANSLATIONS, catalog.messages);
+ Documentation.PLURAL_EXPR = new Function(
+ "n",
+ `return (${catalog.plural_expr})`
+ );
+ Documentation.LOCALE = catalog.locale;
+ },
+
+ /**
+ * helper function to focus on search bar
+ */
+ focusSearchBar: () => {
+ document.querySelectorAll("input[name=q]")[0]?.focus();
+ },
+
+ /**
+ * Initialise the domain index toggle buttons
+ */
+ initDomainIndexTable: () => {
+ const toggler = (el) => {
+ const idNumber = el.id.substr(7);
+ const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`);
+ if (el.src.substr(-9) === "minus.png") {
+ el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`;
+ toggledRows.forEach((el) => (el.style.display = "none"));
+ } else {
+ el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`;
+ toggledRows.forEach((el) => (el.style.display = ""));
+ }
+ };
+
+ const togglerElements = document.querySelectorAll("img.toggler");
+ togglerElements.forEach((el) =>
+ el.addEventListener("click", (event) => toggler(event.currentTarget))
+ );
+ togglerElements.forEach((el) => (el.style.display = ""));
+ if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler);
+ },
+
+ initOnKeyListeners: () => {
+ // only install a listener if it is really needed
+ if (
+ !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
+ !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS
+ )
+ return;
+
+ document.addEventListener("keydown", (event) => {
+ // bail for input elements
+ if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
+ // bail with special keys
+ if (event.altKey || event.ctrlKey || event.metaKey) return;
+
+ if (!event.shiftKey) {
+ switch (event.key) {
+ case "ArrowLeft":
+ if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
+
+ const prevLink = document.querySelector('link[rel="prev"]');
+ if (prevLink && prevLink.href) {
+ window.location.href = prevLink.href;
+ event.preventDefault();
+ }
+ break;
+ case "ArrowRight":
+ if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
+
+ const nextLink = document.querySelector('link[rel="next"]');
+ if (nextLink && nextLink.href) {
+ window.location.href = nextLink.href;
+ event.preventDefault();
+ }
+ break;
+ }
+ }
+
+ // some keyboard layouts may need Shift to get /
+ switch (event.key) {
+ case "/":
+ if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
+ Documentation.focusSearchBar();
+ event.preventDefault();
+ }
+ });
+ },
+};
+
+// quick alias for translations
+const _ = Documentation.gettext;
+
+_ready(Documentation.init);
diff --git a/docs/_static/documentation_options.js b/docs/_static/documentation_options.js
new file mode 100644
index 0000000..b57ae3b
--- /dev/null
+++ b/docs/_static/documentation_options.js
@@ -0,0 +1,14 @@
+var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
+ VERSION: '',
+ LANGUAGE: 'en',
+ COLLAPSE_INDEX: false,
+ BUILDER: 'html',
+ FILE_SUFFIX: '.html',
+ LINK_SUFFIX: '.html',
+ HAS_SOURCE: true,
+ SOURCELINK_SUFFIX: '.txt',
+ NAVIGATION_WITH_KEYS: false,
+ SHOW_SEARCH_SUMMARY: true,
+ ENABLE_SEARCH_SHORTCUTS: true,
+};
\ No newline at end of file
diff --git a/docs/_static/file.png b/docs/_static/file.png
new file mode 100644
index 0000000..a858a41
Binary files /dev/null and b/docs/_static/file.png differ
diff --git a/docs/_static/jquery-3.6.0.js b/docs/_static/jquery-3.6.0.js
new file mode 100644
index 0000000..fc6c299
--- /dev/null
+++ b/docs/_static/jquery-3.6.0.js
@@ -0,0 +1,10881 @@
+/*!
+ * jQuery JavaScript Library v3.6.0
+ * https://jquery.com/
+ *
+ * Includes Sizzle.js
+ * https://sizzlejs.com/
+ *
+ * Copyright OpenJS Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2021-03-02T17:08Z
+ */
+( function( global, factory ) {
+
+ "use strict";
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info.
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
+// enough that all such attempts are guarded in a try block.
+"use strict";
+
+var arr = [];
+
+var getProto = Object.getPrototypeOf;
+
+var slice = arr.slice;
+
+var flat = arr.flat ? function( array ) {
+ return arr.flat.call( array );
+} : function( array ) {
+ return arr.concat.apply( [], array );
+};
+
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var fnToString = hasOwn.toString;
+
+var ObjectFunctionString = fnToString.call( Object );
+
+var support = {};
+
+var isFunction = function isFunction( obj ) {
+
+ // Support: Chrome <=57, Firefox <=52
+ // In some browsers, typeof returns "function" for HTML