From a7dec60ec18dcf692e01976ebcf20696cf33335d Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Fri, 27 Dec 2024 11:35:51 +0000 Subject: [PATCH] build based on 0a96a40 --- previews/PR539/advanced/index.html | 79 +++ previews/PR539/assets/documenter.js | 331 +++++++++++ previews/PR539/assets/search.js | 267 +++++++++ .../PR539/assets/themes/documenter-dark.css | 7 + .../PR539/assets/themes/documenter-light.css | 9 + previews/PR539/assets/themeswap.js | 66 +++ previews/PR539/assets/warner.js | 49 ++ previews/PR539/basics/index.html | 2 + previews/PR539/contributing/index.html | 7 + previews/PR539/examples/.gitkeep | 0 .../examples/docs_00_fw_visualized/index.html | 368 +++++++++++++ .../examples/docs_01_mathopt_lmo/index.html | 320 +++++++++++ .../docs_02_polynomial_regression/index.html | 505 +++++++++++++++++ .../docs_03_matrix_completion/index.html | 512 ++++++++++++++++++ .../examples/docs_04_rational_opt/index.html | 82 +++ .../examples/docs_05_blended_cg/index.html | 269 +++++++++ .../examples/docs_06_spectrahedron/index.html | 192 +++++++ .../docs_07_shifted_norm_polytopes/index.html | 210 +++++++ .../docs_08_callback_and_tracking/index.html | 82 +++ .../docs_09_extra_vertex_storage/index.html | 69 +++ .../docs_10_alternating_methods/index.html | 245 +++++++++ .../docs_11_block_coordinate_fw/index.html | 421 ++++++++++++++ .../docs_12_quadratic_symmetric/index.html | 310 +++++++++++ previews/PR539/examples/plot_utils.jl | 422 +++++++++++++++ previews/PR539/fw_vs_afw.PNG | Bin 0 -> 54399 bytes previews/PR539/index.html | 43 ++ .../PR539/reference/0_reference/index.html | 2 + .../PR539/reference/1_algorithms/index.html | 2 + previews/PR539/reference/2_lmo/index.html | 2 + previews/PR539/reference/3_backend/index.html | 28 + .../PR539/reference/4_linesearch/index.html | 2 + previews/PR539/search/index.html | 2 + previews/PR539/search_index.js | 3 + previews/PR539/siteinfo.js | 1 + 34 files changed, 4909 insertions(+) create mode 100644 previews/PR539/advanced/index.html create mode 100644 previews/PR539/assets/documenter.js create mode 100644 previews/PR539/assets/search.js create mode 100644 previews/PR539/assets/themes/documenter-dark.css create mode 100644 previews/PR539/assets/themes/documenter-light.css create mode 100644 previews/PR539/assets/themeswap.js create mode 100644 previews/PR539/assets/warner.js create mode 100644 previews/PR539/basics/index.html create mode 100644 previews/PR539/contributing/index.html create mode 100644 previews/PR539/examples/.gitkeep create mode 100644 previews/PR539/examples/docs_00_fw_visualized/index.html create mode 100644 previews/PR539/examples/docs_01_mathopt_lmo/index.html create mode 100644 previews/PR539/examples/docs_02_polynomial_regression/index.html create mode 100644 previews/PR539/examples/docs_03_matrix_completion/index.html create mode 100644 previews/PR539/examples/docs_04_rational_opt/index.html create mode 100644 previews/PR539/examples/docs_05_blended_cg/index.html create mode 100644 previews/PR539/examples/docs_06_spectrahedron/index.html create mode 100644 previews/PR539/examples/docs_07_shifted_norm_polytopes/index.html create mode 100644 previews/PR539/examples/docs_08_callback_and_tracking/index.html create mode 100644 previews/PR539/examples/docs_09_extra_vertex_storage/index.html create mode 100644 previews/PR539/examples/docs_10_alternating_methods/index.html create mode 100644 previews/PR539/examples/docs_11_block_coordinate_fw/index.html create mode 100644 previews/PR539/examples/docs_12_quadratic_symmetric/index.html create mode 100644 previews/PR539/examples/plot_utils.jl create mode 100644 previews/PR539/fw_vs_afw.PNG create mode 100644 previews/PR539/index.html create mode 100644 previews/PR539/reference/0_reference/index.html create mode 100644 previews/PR539/reference/1_algorithms/index.html create mode 100644 previews/PR539/reference/2_lmo/index.html create mode 100644 previews/PR539/reference/3_backend/index.html create mode 100644 previews/PR539/reference/4_linesearch/index.html create mode 100644 previews/PR539/search/index.html create mode 100644 previews/PR539/search_index.js create mode 100644 previews/PR539/siteinfo.js diff --git a/previews/PR539/advanced/index.html b/previews/PR539/advanced/index.html new file mode 100644 index 000000000..2f7ccc565 --- /dev/null +++ b/previews/PR539/advanced/index.html @@ -0,0 +1,79 @@ + +Advanced features · FrankWolfe.jl

Advanced features

Multi-precision

All algorithms can run in various precisions modes: Float16, Float32, Float64, BigFloat and also for rationals based on various integer types Int32, Int64, BigInt (see e.g., the approximate Carathéodory example)

Step size computation

For all Frank-Wolfe algorithms, a step size must be determined to move from the current iterate to the next one. This step size can be determined by exact line search or any other rule represented by a subtype of FrankWolfe.LineSearchMethod, which must implement FrankWolfe.perform_line_search.

Multiple line search and step size determination rules are already available. See Pedregosa, Negiar, Askari, Jaggi (2020) and Pokutta (2023) for the adaptive step size and Carderera, Besançon, Pokutta (2021) for the monotonic step size.

Callbacks

All top-level algorithms can take an optional callback argument, which must be a function taking a FrankWolfe.CallbackState struct and additional arguments:

callback(state::FrankWolfe.CallbackState, args...)

The callback can be used to log additional information or store some values of interest in an external array. If a callback is passed, the trajectory keyword is ignored since it is a special case of callback pushing the 5 first elements of the state to an array returned from the algorithm.

Custom extreme point types

For some feasible sets, the extreme points of the feasible set returned by the LMO possess a specific structure that can be represented in an efficient manner both for storage and for common operations like scaling and addition with an iterate. See for example FrankWolfe.ScaledHotVector and FrankWolfe.RankOneMatrix.

Active set

The active set represents an iterate as a convex combination of atoms (also referred to as extreme points or vertices). It maintains a vector of atoms, the corresponding weights, and the current iterate.

Note: the weights in the active set are currently defined as Float64 in the algorithm. This means that even with vertices using a lower precision, the iterate sum_i(lambda_i * v_i) will be upcast to Float64. One reason for keeping this as-is for now is the higher precision required by the computation of iterates from their barycentric decomposition.

Extra-lazification with a vertex storage

One can pass the following keyword arguments to some active set-based Frank-Wolfe algorithms:

add_dropped_vertices=true,
+use_extra_vertex_storage=true,
+extra_vertex_storage=vertex_storage,

add_dropped_vertices activates feeding discarded vertices to the storage while use_extra_vertex_storage determines whether vertices from the storage are used in the algorithm. See Extra-lazification for a complete example.

Specialized active set for quadratic functions

If the objective function is quadratic, a considerable speedup can be obtained by using the structure ActiveSetQuadraticProductCaching. It relies on the storage of various scalar products to efficiently determine the best (and worst for blended_pairwise_conditional_gradient) atom in the active set without the need of computing many scalar products in each iteration. The user should provide the Hessian matrix A as well as the linear part b of the function, such that:

\[\nabla f(x)=Ax+b.\]

If the Hessian matrix A is simply a scaled identity (for a distance function for instance), LinearAlgebra.I or any LinearAlgebra.UniformScaling can be given. Note that these parameters can also be automatically detected, but the precision of this detection (which basically requires solving a linear system) soon becomes insufficient for practical purposes when the dimension increases.

See the examples quadratic.jl and quadratic_A.jl for the exact syntax.

Miscellaneous

  • Emphasis: All solvers support emphasis (parameter Emphasis) to either exploit vectorized linear algebra or be memory efficient, e.g., for large-scale instances
  • Various caching strategies for the lazy implementations. Unbounded cache sizes (can get slow), bounded cache sizes as well as early returns once any sufficient vertex is found in the cache.
  • Optionally all algorithms can be endowed with gradient momentum. This might help convergence especially in the stochastic context.

Coming soon: when the LMO can compute dual prices, then the Frank-Wolfe algorithms will return dual prices for the (approximately) optimal solutions (see Braun, Pokutta (2021)).

Rational arithmetic

Example: examples/approximateCaratheodory.jl

We can solve the approximate Carathéodory problem with rational arithmetic to obtain rational approximations; see Combettes, Pokutta 2019 for some background about approximate Carathéodory and Conditioanl Gradients. We consider the simple instance of approximating the 0 over the probability simplex here:

\[\min_{x \in \Delta(n)} \|x\|^2\]

with n = 100.

Vanilla Frank-Wolfe Algorithm.
+EMPHASIS: blas STEPSIZE: rationalshortstep EPSILON: 1.0e-7 max_iteration: 100 TYPE: Rational{BigInt}
+
+───────────────────────────────────────────────────────────────────────────────────
+  Type     Iteration         Primal           Dual       Dual Gap           Time
+───────────────────────────────────────────────────────────────────────────────────
+     I             0   1.000000e+00  -1.000000e+00   2.000000e+00   1.540385e-01
+    FW            10   9.090909e-02  -9.090909e-02   1.818182e-01   2.821186e-01
+    FW            20   4.761905e-02  -4.761905e-02   9.523810e-02   3.027964e-01
+    FW            30   3.225806e-02  -3.225806e-02   6.451613e-02   3.100331e-01
+    FW            40   2.439024e-02  -2.439024e-02   4.878049e-02   3.171654e-01
+    FW            50   1.960784e-02  -1.960784e-02   3.921569e-02   3.244207e-01
+    FW            60   1.639344e-02  -1.639344e-02   3.278689e-02   3.326185e-01
+    FW            70   1.408451e-02  -1.408451e-02   2.816901e-02   3.418239e-01
+    FW            80   1.234568e-02  -1.234568e-02   2.469136e-02   3.518750e-01
+    FW            90   1.098901e-02  -1.098901e-02   2.197802e-02   3.620287e-01
+  Last                 1.000000e-02   1.000000e-02   0.000000e+00   4.392171e-01
+───────────────────────────────────────────────────────────────────────────────────
+
+  0.600608 seconds (3.83 M allocations: 111.274 MiB, 12.97% gc time)
+
+Output type of solution: Rational{BigInt}

The solution returned is rational as we can see and in fact the exactly optimal solution:

x = Rational{BigInt}[1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100]

Large-scale problems

Example: examples/large_scale.jl

The package is built to scale well, for those conditional gradients variants that can scale well. For example, Away-Step Frank-Wolfe and Pairwise Conditional Gradients do in most cases not scale well because they need to maintain active sets and maintaining them can be very expensive. Similarly, line search methods might become prohibitive at large sizes. However if we consider scale-friendly variants, e.g., the vanilla Frank-Wolfe algorithm with the agnostic step size rule or short step rule, then these algorithms can scale well to extreme sizes esentially only limited by the amount of memory available. However even for these methods that tend to scale well, allocation of memory itself can be very slow when you need to allocate gigabytes of memory for a single gradient computation.

The package is build to support extreme sizes with a special memory efficient emphasis emphasis=FrankWolfe.memory, which minimizes expensive memory allocations and performs as many operations in-place as possible.

Here is an example of a run with 1e9 variables. Each gradient is around 7.5 GB in size. Here is the output of the run broken down into pieces:

Size of single vector (Float64): 7629.39453125 MB
+Testing f... 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:23
+Testing grad... 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:23
+Testing lmo... 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:29
+Testing dual gap... 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:46
+Testing update... (Emphasis: blas) 100%|███████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:01:35
+Testing update... (Emphasis: memory) 100%|█████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:58
+ ──────────────────────────────────────────────────────────────────────────
+                                   Time                   Allocations
+                           ──────────────────────   ───────────────────────
+     Tot / % measured:           278s / 31.4%            969GiB / 30.8%
+
+ Section           ncalls     time   %tot     avg     alloc   %tot      avg
+ ──────────────────────────────────────────────────────────────────────────
+ update (blas)         10    36.1s  41.3%   3.61s    149GiB  50.0%  14.9GiB
+ lmo                   10    18.4s  21.1%   1.84s     0.00B  0.00%    0.00B
+ grad                  10    12.8s  14.6%   1.28s   74.5GiB  25.0%  7.45GiB
+ f                     10    12.7s  14.5%   1.27s   74.5GiB  25.0%  7.45GiB
+ update (memory)       10    5.00s  5.72%   500ms     0.00B  0.00%    0.00B
+ dual gap              10    2.40s  2.75%   240ms     0.00B  0.00%    0.00B
+ ──────────────────────────────────────────────────────────────────────────

The above is the optional benchmarking of the oracles that we provide to understand how fast crucial parts of the algorithms are, mostly notably oracle evaluations, the update of the iterate and the computation of the dual gap. As you can see if you compare update (blas) vs. update (memory), the normal update when we use BLAS requires an additional 14.9GB of memory on top of the gradient etc whereas the update (memory) (the memory emphasis mode) does not consume any extra memory. This is also reflected in the computational times: the BLAS version requires 3.61 seconds on average to update the iterate, while the memory emphasis version requires only 500ms. In fact none of the crucial components in the algorithm consume any memory when run in memory efficient mode. Now let us look at the actual footprint of the whole algorithm:

Vanilla Frank-Wolfe Algorithm.
+EMPHASIS: memory STEPSIZE: agnostic EPSILON: 1.0e-7 MAXITERATION: 1000 TYPE: Float64
+MOMENTUM: nothing GRADIENTTYPE: Nothing
+WARNING: In memory emphasis mode iterates are written back into x0!
+
+─────────────────────────────────────────────────────────────────────────────────────────────────
+  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
+─────────────────────────────────────────────────────────────────────────────────────────────────
+     I             0   1.000000e+00  -1.000000e+00   2.000000e+00   8.783523e+00   0.000000e+00
+    FW           100   1.326732e-02  -1.326733e-02   2.653465e-02   4.635923e+02   2.157068e-01
+    FW           200   6.650080e-03  -6.650086e-03   1.330017e-02   9.181294e+02   2.178342e-01
+    FW           300   4.437059e-03  -4.437064e-03   8.874123e-03   1.372615e+03   2.185609e-01
+    FW           400   3.329174e-03  -3.329180e-03   6.658354e-03   1.827260e+03   2.189070e-01
+    FW           500   2.664003e-03  -2.664008e-03   5.328011e-03   2.281865e+03   2.191190e-01
+    FW           600   2.220371e-03  -2.220376e-03   4.440747e-03   2.736387e+03   2.192672e-01
+    FW           700   1.903401e-03  -1.903406e-03   3.806807e-03   3.190951e+03   2.193703e-01
+    FW           800   1.665624e-03  -1.665629e-03   3.331253e-03   3.645425e+03   2.194532e-01
+    FW           900   1.480657e-03  -1.480662e-03   2.961319e-03   4.099931e+03   2.195159e-01
+    FW          1000   1.332665e-03  -1.332670e-03   2.665335e-03   4.554703e+03   2.195533e-01
+  Last          1000   1.331334e-03  -1.331339e-03   2.662673e-03   4.559822e+03   2.195261e-01
+─────────────────────────────────────────────────────────────────────────────────────────────────
+
+4560.661203 seconds (7.41 M allocations: 112.121 GiB, 0.01% gc time)

As you can see the algorithm ran for about 4600 secs (single-thread run) allocating 112.121 GiB of memory throughout. So how does this average out to the per-iteration cost in terms of memory: 112.121 / 7.45 / 1000 = 0.0151 so about 15.1MiB per iteration which is much less than the size of the gradient and in fact only stems from the reporting here.

NB. This example highlights also one of the great features of first-order methods and conditional gradients in particular: we have dimension-independent convergence rates. In fact, we contract the primal gap as 2LD^2 / (t+2) (for the simple agnostic rule) and, e.g., if the feasible region is the probability simplex with D = sqrt(2) and the function has bounded Lipschitzness, e.g., the function || x - xp ||^2 has L = 2, then the convergence rate is completely independent of the input size. The only thing that limits scaling is how much memory you have available and whether you can stomach the (linear) per-iteration cost.

Iterate and atom expected interface

Frank-Wolfe can work on iterate beyond plain vectors, for example with any array-like object. Broadly speaking, the iterate type is assumed to behave as the member of a Hilbert space and optionally be mutable. Assuming the iterate type is IT, some methods must be implemented, with their usual semantics:

Base.similar(::IT)
+Base.similar(::IT, ::Type{T})
+Base.collect(::IT)
+Base.size(::IT)
+Base.eltype(::IT)
+Base.copyto!(dest::IT, src::IT)
+
+Base.:+(x1::IT, x2::IT)
+Base.:*(scalar::Real, x::IT)
+Base.:-(x1::IT, x2::IT)
+LinearAlgebra.dot(x1::IT, x2::IT)
+LinearAlgebra.norm(::IT)

For methods using an FrankWolfe.ActiveSet, the atoms or individual extreme points of the feasible region are not necessarily of the same type as the iterate. They are assumed to be immutable, must implement LinearAlgebra.dot with a gradient object. See for example FrankWolfe.RankOneMatrix or FrankWolfe.ScaledHotVector.

The iterate type IT must be a broadcastable mutable object or implement FrankWolfe.compute_active_set_iterate!:

FrankWolfe.compute_active_set_iterate!(active_set::FrankWolfe.ActiveSet{AT, R, IT}) where {AT, R}

which recomputes the iterate from the current convex decomposition and the following methods FrankWolfe.active_set_update_scale! and FrankWolfe.active_set_update_iterate_pairwise!:

FrankWolfe.active_set_update_scale!(x::IT, lambda, atom)
+FrankWolfe.active_set_update_iterate_pairwise!(x::IT, lambda, fw_atom, away_atom)

Symmetry reduction

Example: examples/reynolds.jl

Suppose that there is a group $G$ acting on the underlying vector space and such that for all $x\in\mathcal{C}$ and $g\in G$

\[f(g\cdot x)=f(x)\quad\text{and}\quad g\cdot x\in\mathcal{C}.\]

Then, the computations can be performed in the subspace invariant under $G$. This subspace is the image of the Reynolds operator defined by

\[\mathcal{R}(x)=\frac{1}{|G|}\sum_{g\in G}g\cdot x.\]

In practice, the type SubspaceLMO allows the user to provide the Reynolds operator $\mathcal{R}$ as well as its adjoint $\mathcal{R}^\ast$. The gradient is symmetrised with $\mathcal{R}^\ast$, then passed to the non-symmetric LMO, and the resulting output is symmetrised with $\mathcal{R}$. In many cases, the gradient is already symmetric so that reynolds_adjoint(gradient, lmo) = gradient is a fast and valid choice.

diff --git a/previews/PR539/assets/documenter.js b/previews/PR539/assets/documenter.js new file mode 100644 index 000000000..6adfbbbf4 --- /dev/null +++ b/previews/PR539/assets/documenter.js @@ -0,0 +1,331 @@ +// Generated by Documenter.jl +requirejs.config({ + paths: { + 'highlight-julia': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/languages/julia.min', + 'headroom': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.12.0/headroom.min', + 'jqueryui': 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min', + 'katex-auto-render': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.13.24/contrib/auto-render.min', + 'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min', + 'headroom-jquery': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.12.0/jQuery.headroom.min', + 'katex': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.13.24/katex.min', + 'highlight': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min', + 'highlight-julia-repl': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/languages/julia-repl.min', + }, + shim: { + "highlight-julia": { + "deps": [ + "highlight" + ] + }, + "katex-auto-render": { + "deps": [ + "katex" + ] + }, + "headroom-jquery": { + "deps": [ + "jquery", + "headroom" + ] + }, + "highlight-julia-repl": { + "deps": [ + "highlight" + ] + } +} +}); +//////////////////////////////////////////////////////////////////////////////// +require(['jquery', 'katex', 'katex-auto-render'], function($, katex, renderMathInElement) { +$(document).ready(function() { + renderMathInElement( + document.body, + { + "delimiters": [ + { + "left": "$", + "right": "$", + "display": false + }, + { + "left": "$$", + "right": "$$", + "display": true + }, + { + "left": "\\[", + "right": "\\]", + "display": true + } + ] +} + + ); +}) + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery', 'highlight', 'highlight-julia', 'highlight-julia-repl'], function($) { +$(document).ready(function() { + hljs.highlightAll(); +}) + +}) +//////////////////////////////////////////////////////////////////////////////// +require([], function() { +function addCopyButtonCallbacks() { + for (const el of document.getElementsByTagName("pre")) { + const button = document.createElement("button"); + button.classList.add("copy-button", "fas", "fa-copy"); + el.appendChild(button); + + const success = function () { + button.classList.add("success", "fa-check"); + button.classList.remove("fa-copy"); + }; + + const failure = function () { + button.classList.add("error", "fa-times"); + button.classList.remove("fa-copy"); + }; + + button.addEventListener("click", function () { + copyToClipboard(el.innerText).then(success, failure); + + setTimeout(function () { + button.classList.add("fa-copy"); + button.classList.remove("success", "fa-check", "fa-times"); + }, 5000); + }); + } +} + +function copyToClipboard(text) { + // clipboard API is only available in secure contexts + if (window.navigator && window.navigator.clipboard) { + return window.navigator.clipboard.writeText(text); + } else { + return new Promise(function (resolve, reject) { + try { + const el = document.createElement("textarea"); + el.textContent = text; + el.style.position = "fixed"; + el.style.opacity = 0; + document.body.appendChild(el); + el.select(); + document.execCommand("copy"); + + resolve(); + } catch (err) { + reject(err); + } finally { + document.body.removeChild(el); + } + }); + } +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", addCopyButtonCallbacks); +} else { + addCopyButtonCallbacks(); +} + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery', 'headroom', 'headroom-jquery'], function($, Headroom) { + +// Manages the top navigation bar (hides it when the user starts scrolling down on the +// mobile). +window.Headroom = Headroom; // work around buggy module loading? +$(document).ready(function() { + $('#documenter .docs-navbar').headroom({ + "tolerance": {"up": 10, "down": 10}, + }); +}) + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// Modal settings dialog +$(document).ready(function() { + var settings = $('#documenter-settings'); + $('#documenter-settings-button').click(function(){ + settings.toggleClass('is-active'); + }); + // Close the dialog if X is clicked + $('#documenter-settings button.delete').click(function(){ + settings.removeClass('is-active'); + }); + // Close dialog if ESC is pressed + $(document).keyup(function(e) { + if (e.keyCode == 27) settings.removeClass('is-active'); + }); +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// Manages the showing and hiding of the sidebar. +$(document).ready(function() { + var sidebar = $("#documenter > .docs-sidebar"); + var sidebar_button = $("#documenter-sidebar-button") + sidebar_button.click(function(ev) { + ev.preventDefault(); + sidebar.toggleClass('visible'); + if (sidebar.hasClass('visible')) { + // Makes sure that the current menu item is visible in the sidebar. + $("#documenter .docs-menu a.is-active").focus(); + } + }); + $("#documenter > .docs-main").bind('click', function(ev) { + if ($(ev.target).is(sidebar_button)) { + return; + } + if (sidebar.hasClass('visible')) { + sidebar.removeClass('visible'); + } + }); +}) + +// Resizes the package name / sitename in the sidebar if it is too wide. +// Inspired by: https://github.com/davatron5000/FitText.js +$(document).ready(function() { + e = $("#documenter .docs-autofit"); + function resize() { + var L = parseInt(e.css('max-width'), 10); + var L0 = e.width(); + if(L0 > L) { + var h0 = parseInt(e.css('font-size'), 10); + e.css('font-size', L * h0 / L0); + // TODO: make sure it survives resizes? + } + } + // call once and then register events + resize(); + $(window).resize(resize); + $(window).on('orientationchange', resize); +}); + +// Scroll the navigation bar to the currently selected menu item +$(document).ready(function() { + var sidebar = $("#documenter .docs-menu").get(0); + var active = $("#documenter .docs-menu .is-active").get(0); + if(typeof active !== 'undefined') { + sidebar.scrollTop = active.offsetTop - sidebar.offsetTop - 15; + } +}) + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +function set_theme(theme) { + var active = null; + var disabled = []; + for (var i = 0; i < document.styleSheets.length; i++) { + var ss = document.styleSheets[i]; + var themename = ss.ownerNode.getAttribute("data-theme-name"); + if(themename === null) continue; // ignore non-theme stylesheets + // Find the active theme + if(themename === theme) active = ss; + else disabled.push(ss); + } + if(active !== null) { + active.disabled = false; + if(active.ownerNode.getAttribute("data-theme-primary") === null) { + document.getElementsByTagName('html')[0].className = "theme--" + theme; + } else { + document.getElementsByTagName('html')[0].className = ""; + } + disabled.forEach(function(ss){ + ss.disabled = true; + }); + } + + // Store the theme in localStorage + if(typeof(window.localStorage) !== "undefined") { + window.localStorage.setItem("documenter-theme", theme); + } else { + console.error("Browser does not support window.localStorage"); + } +} + +// Theme picker setup +$(document).ready(function() { + // onchange callback + $('#documenter-themepicker').change(function themepick_callback(ev){ + var themename = $('#documenter-themepicker option:selected').attr('value'); + set_theme(themename); + }); + + // Make sure that the themepicker displays the correct theme when the theme is retrieved + // from localStorage + if(typeof(window.localStorage) !== "undefined") { + var theme = window.localStorage.getItem("documenter-theme"); + if(theme !== null) { + $('#documenter-themepicker option').each(function(i,e) { + e.selected = (e.value === theme); + }) + } else { + $('#documenter-themepicker option').each(function(i,e) { + e.selected = $("html").hasClass(`theme--${e.value}`); + }) + } + } +}) + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// update the version selector with info from the siteinfo.js and ../versions.js files +$(document).ready(function() { + // If the version selector is disabled with DOCUMENTER_VERSION_SELECTOR_DISABLED in the + // siteinfo.js file, we just return immediately and not display the version selector. + if (typeof DOCUMENTER_VERSION_SELECTOR_DISABLED === 'boolean' && DOCUMENTER_VERSION_SELECTOR_DISABLED) { + return; + } + + var version_selector = $("#documenter .docs-version-selector"); + var version_selector_select = $("#documenter .docs-version-selector select"); + + version_selector_select.change(function(x) { + target_href = version_selector_select.children("option:selected").get(0).value; + window.location.href = target_href; + }); + + // add the current version to the selector based on siteinfo.js, but only if the selector is empty + if (typeof DOCUMENTER_CURRENT_VERSION !== 'undefined' && $('#version-selector > option').length == 0) { + var option = $(""); + version_selector_select.append(option); + } + + if (typeof DOC_VERSIONS !== 'undefined') { + var existing_versions = version_selector_select.children("option"); + var existing_versions_texts = existing_versions.map(function(i,x){return x.text}); + DOC_VERSIONS.forEach(function(each) { + var version_url = documenterBaseURL + "/../" + each; + var existing_id = $.inArray(each, existing_versions_texts); + // if not already in the version selector, add it as a new option, + // otherwise update the old option with the URL and enable it + if (existing_id == -1) { + var option = $(""); + version_selector_select.append(option); + } else { + var option = existing_versions[existing_id]; + option.value = version_url; + option.disabled = false; + } + }); + } + + // only show the version selector if the selector has been populated + if (version_selector_select.children("option").length > 0) { + version_selector.toggleClass("visible"); + } +}) + +}) diff --git a/previews/PR539/assets/search.js b/previews/PR539/assets/search.js new file mode 100644 index 000000000..c133f7410 --- /dev/null +++ b/previews/PR539/assets/search.js @@ -0,0 +1,267 @@ +// Generated by Documenter.jl +requirejs.config({ + paths: { + 'lunr': 'https://cdnjs.cloudflare.com/ajax/libs/lunr.js/2.3.9/lunr.min', + 'lodash': 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min', + 'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min', + } +}); +//////////////////////////////////////////////////////////////////////////////// +require(['jquery', 'lunr', 'lodash'], function($, lunr, _) { + +$(document).ready(function() { + // parseUri 1.2.2 + // (c) Steven Levithan + // MIT License + function parseUri (str) { + var o = parseUri.options, + m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), + uri = {}, + i = 14; + + while (i--) uri[o.key[i]] = m[i] || ""; + + uri[o.q.name] = {}; + uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { + if ($1) uri[o.q.name][$1] = $2; + }); + + return uri; + }; + parseUri.options = { + strictMode: false, + key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], + q: { + name: "queryKey", + parser: /(?:^|&)([^&=]*)=?([^&]*)/g + }, + parser: { + strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, + loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ + } + }; + + $("#search-form").submit(function(e) { + e.preventDefault() + }) + + // list below is the lunr 2.1.3 list minus the intersect with names(Base) + // (all, any, get, in, is, only, which) and (do, else, for, let, where, while, with) + // ideally we'd just filter the original list but it's not available as a variable + lunr.stopWordFilter = lunr.generateStopWordFilter([ + 'a', + 'able', + 'about', + 'across', + 'after', + 'almost', + 'also', + 'am', + 'among', + 'an', + 'and', + 'are', + 'as', + 'at', + 'be', + 'because', + 'been', + 'but', + 'by', + 'can', + 'cannot', + 'could', + 'dear', + 'did', + 'does', + 'either', + 'ever', + 'every', + 'from', + 'got', + 'had', + 'has', + 'have', + 'he', + 'her', + 'hers', + 'him', + 'his', + 'how', + 'however', + 'i', + 'if', + 'into', + 'it', + 'its', + 'just', + 'least', + 'like', + 'likely', + 'may', + 'me', + 'might', + 'most', + 'must', + 'my', + 'neither', + 'no', + 'nor', + 'not', + 'of', + 'off', + 'often', + 'on', + 'or', + 'other', + 'our', + 'own', + 'rather', + 'said', + 'say', + 'says', + 'she', + 'should', + 'since', + 'so', + 'some', + 'than', + 'that', + 'the', + 'their', + 'them', + 'then', + 'there', + 'these', + 'they', + 'this', + 'tis', + 'to', + 'too', + 'twas', + 'us', + 'wants', + 'was', + 'we', + 'were', + 'what', + 'when', + 'who', + 'whom', + 'why', + 'will', + 'would', + 'yet', + 'you', + 'your' + ]) + + // add . as a separator, because otherwise "title": "Documenter.Anchors.add!" + // would not find anything if searching for "add!", only for the entire qualification + lunr.tokenizer.separator = /[\s\-\.]+/ + + // custom trimmer that doesn't strip @ and !, which are used in julia macro and function names + lunr.trimmer = function (token) { + return token.update(function (s) { + return s.replace(/^[^a-zA-Z0-9@!]+/, '').replace(/[^a-zA-Z0-9@!]+$/, '') + }) + } + + lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'juliaStopWordFilter') + lunr.Pipeline.registerFunction(lunr.trimmer, 'juliaTrimmer') + + var index = lunr(function () { + this.ref('location') + this.field('title',{boost: 100}) + this.field('text') + documenterSearchIndex['docs'].forEach(function(e) { + this.add(e) + }, this) + }) + var store = {} + + documenterSearchIndex['docs'].forEach(function(e) { + store[e.location] = {title: e.title, category: e.category, page: e.page} + }) + + $(function(){ + searchresults = $('#documenter-search-results'); + searchinfo = $('#documenter-search-info'); + searchbox = $('#documenter-search-query'); + searchform = $('.docs-search'); + sidebar = $('.docs-sidebar'); + function update_search(querystring) { + tokens = lunr.tokenizer(querystring) + results = index.query(function (q) { + tokens.forEach(function (t) { + q.term(t.toString(), { + fields: ["title"], + boost: 100, + usePipeline: true, + editDistance: 0, + wildcard: lunr.Query.wildcard.NONE + }) + q.term(t.toString(), { + fields: ["title"], + boost: 10, + usePipeline: true, + editDistance: 2, + wildcard: lunr.Query.wildcard.NONE + }) + q.term(t.toString(), { + fields: ["text"], + boost: 1, + usePipeline: true, + editDistance: 0, + wildcard: lunr.Query.wildcard.NONE + }) + }) + }) + searchinfo.text("Number of results: " + results.length) + searchresults.empty() + results.forEach(function(result) { + data = store[result.ref] + link = $(''+data.title+'') + link.attr('href', documenterBaseURL+'/'+result.ref) + if (data.category != "page"){ + cat = $('('+data.category+', '+data.page+')') + } else { + cat = $('('+data.category+')') + } + li = $('
  • ').append(link).append(" ").append(cat) + searchresults.append(li) + }) + } + + function update_search_box() { + querystring = searchbox.val() + update_search(querystring) + } + + searchbox.keyup(_.debounce(update_search_box, 250)) + searchbox.change(update_search_box) + + // Disable enter-key form submission for the searchbox on the search page + // and just re-run search rather than refresh the whole page. + searchform.keypress( + function(event){ + if (event.which == '13') { + if (sidebar.hasClass('visible')) { + sidebar.removeClass('visible'); + } + update_search_box(); + event.preventDefault(); + } + } + ); + + search_query_uri = parseUri(window.location).queryKey["q"] + if(search_query_uri !== undefined) { + search_query = decodeURIComponent(search_query_uri.replace(/\+/g, '%20')) + searchbox.val(search_query) + } + update_search_box(); + }) +}) + +}) diff --git a/previews/PR539/assets/themes/documenter-dark.css b/previews/PR539/assets/themes/documenter-dark.css new file mode 100644 index 000000000..c94a294dc --- /dev/null +++ b/previews/PR539/assets/themes/documenter-dark.css @@ -0,0 +1,7 @@ +@keyframes spinAround{from{transform:rotate(0deg)}to{transform:rotate(359deg)}}html.theme--documenter-dark .tabs,html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .breadcrumb,html.theme--documenter-dark .file,html.theme--documenter-dark .button,.is-unselectable,html.theme--documenter-dark .modal-close,html.theme--documenter-dark .delete{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}html.theme--documenter-dark .navbar-link:not(.is-arrowless)::after,html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading)::after{border:3px solid rgba(0,0,0,0);border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:0.625em;margin-top:-0.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:0.625em}html.theme--documenter-dark .admonition:not(:last-child),html.theme--documenter-dark .tabs:not(:last-child),html.theme--documenter-dark .message:not(:last-child),html.theme--documenter-dark .list:not(:last-child),html.theme--documenter-dark .level:not(:last-child),html.theme--documenter-dark .breadcrumb:not(:last-child),html.theme--documenter-dark .highlight:not(:last-child),html.theme--documenter-dark .block:not(:last-child),html.theme--documenter-dark .title:not(:last-child),html.theme--documenter-dark .subtitle:not(:last-child),html.theme--documenter-dark .table-container:not(:last-child),html.theme--documenter-dark .table:not(:last-child),html.theme--documenter-dark .progress:not(:last-child),html.theme--documenter-dark .notification:not(:last-child),html.theme--documenter-dark .content:not(:last-child),html.theme--documenter-dark .box:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .modal-close,html.theme--documenter-dark .delete{-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,0.2);border:none;border-radius:290486px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:none;position:relative;vertical-align:top;width:20px}html.theme--documenter-dark .modal-close::before,html.theme--documenter-dark .delete::before,html.theme--documenter-dark .modal-close::after,html.theme--documenter-dark .delete::after{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}html.theme--documenter-dark .modal-close::before,html.theme--documenter-dark .delete::before{height:2px;width:50%}html.theme--documenter-dark .modal-close::after,html.theme--documenter-dark .delete::after{height:50%;width:2px}html.theme--documenter-dark .modal-close:hover,html.theme--documenter-dark .delete:hover,html.theme--documenter-dark .modal-close:focus,html.theme--documenter-dark .delete:focus{background-color:rgba(10,10,10,0.3)}html.theme--documenter-dark .modal-close:active,html.theme--documenter-dark .delete:active{background-color:rgba(10,10,10,0.4)}html.theme--documenter-dark .is-small.modal-close,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.modal-close,html.theme--documenter-dark .is-small.delete,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.delete{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}html.theme--documenter-dark .is-medium.modal-close,html.theme--documenter-dark .is-medium.delete{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}html.theme--documenter-dark .is-large.modal-close,html.theme--documenter-dark .is-large.delete{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}html.theme--documenter-dark .control.is-loading::after,html.theme--documenter-dark .select.is-loading::after,html.theme--documenter-dark .loader,html.theme--documenter-dark .button.is-loading::after{animation:spinAround 500ms infinite linear;border:2px solid #dbdee0;border-radius:290486px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}html.theme--documenter-dark .hero-video,html.theme--documenter-dark .modal-background,html.theme--documenter-dark .modal,html.theme--documenter-dark .image.is-square img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square img,html.theme--documenter-dark .image.is-square .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,html.theme--documenter-dark .image.is-1by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 img,html.theme--documenter-dark .image.is-1by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,html.theme--documenter-dark .image.is-5by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 img,html.theme--documenter-dark .image.is-5by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,html.theme--documenter-dark .image.is-4by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 img,html.theme--documenter-dark .image.is-4by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,html.theme--documenter-dark .image.is-3by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 img,html.theme--documenter-dark .image.is-3by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,html.theme--documenter-dark .image.is-5by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 img,html.theme--documenter-dark .image.is-5by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,html.theme--documenter-dark .image.is-16by9 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 img,html.theme--documenter-dark .image.is-16by9 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,html.theme--documenter-dark .image.is-2by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 img,html.theme--documenter-dark .image.is-2by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,html.theme--documenter-dark .image.is-3by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 img,html.theme--documenter-dark .image.is-3by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,html.theme--documenter-dark .image.is-4by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 img,html.theme--documenter-dark .image.is-4by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,html.theme--documenter-dark .image.is-3by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 img,html.theme--documenter-dark .image.is-3by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,html.theme--documenter-dark .image.is-2by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 img,html.theme--documenter-dark .image.is-2by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,html.theme--documenter-dark .image.is-3by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 img,html.theme--documenter-dark .image.is-3by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,html.theme--documenter-dark .image.is-9by16 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 img,html.theme--documenter-dark .image.is-9by16 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,html.theme--documenter-dark .image.is-1by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 img,html.theme--documenter-dark .image.is-1by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,html.theme--documenter-dark .image.is-1by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 img,html.theme--documenter-dark .image.is-1by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio,.is-overlay{bottom:0;left:0;position:absolute;right:0;top:0}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .file-cta,html.theme--documenter-dark .file-name,html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .button{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:.4em;box-shadow:none;display:inline-flex;font-size:15px;height:2.25em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(0.375em - 1px);padding-left:calc(0.625em - 1px);padding-right:calc(0.625em - 1px);padding-top:calc(0.375em - 1px);position:relative;vertical-align:top}html.theme--documenter-dark .pagination-previous:focus,html.theme--documenter-dark .pagination-next:focus,html.theme--documenter-dark .pagination-link:focus,html.theme--documenter-dark .pagination-ellipsis:focus,html.theme--documenter-dark .file-cta:focus,html.theme--documenter-dark .file-name:focus,html.theme--documenter-dark .select select:focus,html.theme--documenter-dark .textarea:focus,html.theme--documenter-dark .input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:focus,html.theme--documenter-dark .button:focus,html.theme--documenter-dark .is-focused.pagination-previous,html.theme--documenter-dark .is-focused.pagination-next,html.theme--documenter-dark .is-focused.pagination-link,html.theme--documenter-dark .is-focused.pagination-ellipsis,html.theme--documenter-dark .is-focused.file-cta,html.theme--documenter-dark .is-focused.file-name,html.theme--documenter-dark .select select.is-focused,html.theme--documenter-dark .is-focused.textarea,html.theme--documenter-dark .is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-focused.button,html.theme--documenter-dark .pagination-previous:active,html.theme--documenter-dark .pagination-next:active,html.theme--documenter-dark .pagination-link:active,html.theme--documenter-dark .pagination-ellipsis:active,html.theme--documenter-dark .file-cta:active,html.theme--documenter-dark .file-name:active,html.theme--documenter-dark .select select:active,html.theme--documenter-dark .textarea:active,html.theme--documenter-dark .input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:active,html.theme--documenter-dark .button:active,html.theme--documenter-dark .is-active.pagination-previous,html.theme--documenter-dark .is-active.pagination-next,html.theme--documenter-dark .is-active.pagination-link,html.theme--documenter-dark .is-active.pagination-ellipsis,html.theme--documenter-dark .is-active.file-cta,html.theme--documenter-dark .is-active.file-name,html.theme--documenter-dark .select select.is-active,html.theme--documenter-dark .is-active.textarea,html.theme--documenter-dark .is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .is-active.button{outline:none}html.theme--documenter-dark .pagination-previous[disabled],html.theme--documenter-dark .pagination-next[disabled],html.theme--documenter-dark .pagination-link[disabled],html.theme--documenter-dark .pagination-ellipsis[disabled],html.theme--documenter-dark .file-cta[disabled],html.theme--documenter-dark .file-name[disabled],html.theme--documenter-dark .select select[disabled],html.theme--documenter-dark .textarea[disabled],html.theme--documenter-dark .input[disabled],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled],html.theme--documenter-dark .button[disabled],fieldset[disabled] html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark fieldset[disabled] .pagination-previous,fieldset[disabled] html.theme--documenter-dark .pagination-next,html.theme--documenter-dark fieldset[disabled] .pagination-next,fieldset[disabled] html.theme--documenter-dark .pagination-link,html.theme--documenter-dark fieldset[disabled] .pagination-link,fieldset[disabled] html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark fieldset[disabled] .pagination-ellipsis,fieldset[disabled] html.theme--documenter-dark .file-cta,html.theme--documenter-dark fieldset[disabled] .file-cta,fieldset[disabled] html.theme--documenter-dark .file-name,html.theme--documenter-dark fieldset[disabled] .file-name,fieldset[disabled] html.theme--documenter-dark .select select,fieldset[disabled] html.theme--documenter-dark .textarea,fieldset[disabled] html.theme--documenter-dark .input,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark fieldset[disabled] .select select,html.theme--documenter-dark .select fieldset[disabled] select,html.theme--documenter-dark fieldset[disabled] .textarea,html.theme--documenter-dark fieldset[disabled] .input,html.theme--documenter-dark fieldset[disabled] #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar fieldset[disabled] form.docs-search>input,fieldset[disabled] html.theme--documenter-dark .button,html.theme--documenter-dark fieldset[disabled] .button{cursor:not-allowed}/*! minireset.css v0.0.4 | MIT License | github.com/jgthms/minireset.css */html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,embed,iframe,object,video{height:auto;max-width:100%}audio{max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:left}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left !important}.is-pulled-right{float:right !important}.is-clipped{overflow:hidden !important}.is-size-1{font-size:3rem !important}.is-size-2{font-size:2.5rem !important}.is-size-3{font-size:2rem !important}.is-size-4{font-size:1.5rem !important}.is-size-5{font-size:1.25rem !important}.is-size-6{font-size:15px !important}.is-size-7,html.theme--documenter-dark .docstring>section>a.docs-sourcelink{font-size:.85em !important}@media screen and (max-width: 768px){.is-size-1-mobile{font-size:3rem !important}.is-size-2-mobile{font-size:2.5rem !important}.is-size-3-mobile{font-size:2rem !important}.is-size-4-mobile{font-size:1.5rem !important}.is-size-5-mobile{font-size:1.25rem !important}.is-size-6-mobile{font-size:15px !important}.is-size-7-mobile{font-size:.85em !important}}@media screen and (min-width: 769px),print{.is-size-1-tablet{font-size:3rem !important}.is-size-2-tablet{font-size:2.5rem !important}.is-size-3-tablet{font-size:2rem !important}.is-size-4-tablet{font-size:1.5rem !important}.is-size-5-tablet{font-size:1.25rem !important}.is-size-6-tablet{font-size:15px !important}.is-size-7-tablet{font-size:.85em !important}}@media screen and (max-width: 1055px){.is-size-1-touch{font-size:3rem !important}.is-size-2-touch{font-size:2.5rem !important}.is-size-3-touch{font-size:2rem !important}.is-size-4-touch{font-size:1.5rem !important}.is-size-5-touch{font-size:1.25rem !important}.is-size-6-touch{font-size:15px !important}.is-size-7-touch{font-size:.85em !important}}@media screen and (min-width: 1056px){.is-size-1-desktop{font-size:3rem !important}.is-size-2-desktop{font-size:2.5rem !important}.is-size-3-desktop{font-size:2rem !important}.is-size-4-desktop{font-size:1.5rem !important}.is-size-5-desktop{font-size:1.25rem !important}.is-size-6-desktop{font-size:15px !important}.is-size-7-desktop{font-size:.85em !important}}@media screen and (min-width: 1216px){.is-size-1-widescreen{font-size:3rem !important}.is-size-2-widescreen{font-size:2.5rem !important}.is-size-3-widescreen{font-size:2rem !important}.is-size-4-widescreen{font-size:1.5rem !important}.is-size-5-widescreen{font-size:1.25rem !important}.is-size-6-widescreen{font-size:15px !important}.is-size-7-widescreen{font-size:.85em !important}}@media screen and (min-width: 1408px){.is-size-1-fullhd{font-size:3rem !important}.is-size-2-fullhd{font-size:2.5rem !important}.is-size-3-fullhd{font-size:2rem !important}.is-size-4-fullhd{font-size:1.5rem !important}.is-size-5-fullhd{font-size:1.25rem !important}.is-size-6-fullhd{font-size:15px !important}.is-size-7-fullhd{font-size:.85em !important}}.has-text-centered{text-align:center !important}.has-text-justified{text-align:justify !important}.has-text-left{text-align:left !important}.has-text-right{text-align:right !important}@media screen and (max-width: 768px){.has-text-centered-mobile{text-align:center !important}}@media screen and (min-width: 769px),print{.has-text-centered-tablet{text-align:center !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-centered-tablet-only{text-align:center !important}}@media screen and (max-width: 1055px){.has-text-centered-touch{text-align:center !important}}@media screen and (min-width: 1056px){.has-text-centered-desktop{text-align:center !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-centered-desktop-only{text-align:center !important}}@media screen and (min-width: 1216px){.has-text-centered-widescreen{text-align:center !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-centered-widescreen-only{text-align:center !important}}@media screen and (min-width: 1408px){.has-text-centered-fullhd{text-align:center !important}}@media screen and (max-width: 768px){.has-text-justified-mobile{text-align:justify !important}}@media screen and (min-width: 769px),print{.has-text-justified-tablet{text-align:justify !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-justified-tablet-only{text-align:justify !important}}@media screen and (max-width: 1055px){.has-text-justified-touch{text-align:justify !important}}@media screen and (min-width: 1056px){.has-text-justified-desktop{text-align:justify !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-justified-desktop-only{text-align:justify !important}}@media screen and (min-width: 1216px){.has-text-justified-widescreen{text-align:justify !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-justified-widescreen-only{text-align:justify !important}}@media screen and (min-width: 1408px){.has-text-justified-fullhd{text-align:justify !important}}@media screen and (max-width: 768px){.has-text-left-mobile{text-align:left !important}}@media screen and (min-width: 769px),print{.has-text-left-tablet{text-align:left !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-left-tablet-only{text-align:left !important}}@media screen and (max-width: 1055px){.has-text-left-touch{text-align:left !important}}@media screen and (min-width: 1056px){.has-text-left-desktop{text-align:left !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-left-desktop-only{text-align:left !important}}@media screen and (min-width: 1216px){.has-text-left-widescreen{text-align:left !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-left-widescreen-only{text-align:left !important}}@media screen and (min-width: 1408px){.has-text-left-fullhd{text-align:left !important}}@media screen and (max-width: 768px){.has-text-right-mobile{text-align:right !important}}@media screen and (min-width: 769px),print{.has-text-right-tablet{text-align:right !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-right-tablet-only{text-align:right !important}}@media screen and (max-width: 1055px){.has-text-right-touch{text-align:right !important}}@media screen and (min-width: 1056px){.has-text-right-desktop{text-align:right !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-right-desktop-only{text-align:right !important}}@media screen and (min-width: 1216px){.has-text-right-widescreen{text-align:right !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-right-widescreen-only{text-align:right !important}}@media screen and (min-width: 1408px){.has-text-right-fullhd{text-align:right !important}}.is-capitalized{text-transform:capitalize !important}.is-lowercase{text-transform:lowercase !important}.is-uppercase{text-transform:uppercase !important}.is-italic{font-style:italic !important}.has-text-white{color:#fff !important}a.has-text-white:hover,a.has-text-white:focus{color:#e6e6e6 !important}.has-background-white{background-color:#fff !important}.has-text-black{color:#0a0a0a !important}a.has-text-black:hover,a.has-text-black:focus{color:#000 !important}.has-background-black{background-color:#0a0a0a !important}.has-text-light{color:#ecf0f1 !important}a.has-text-light:hover,a.has-text-light:focus{color:#cfd9db !important}.has-background-light{background-color:#ecf0f1 !important}.has-text-dark{color:#282f2f !important}a.has-text-dark:hover,a.has-text-dark:focus{color:#111414 !important}.has-background-dark{background-color:#282f2f !important}.has-text-primary{color:#375a7f !important}a.has-text-primary:hover,a.has-text-primary:focus{color:#28415b !important}.has-background-primary{background-color:#375a7f !important}.has-text-link{color:#1abc9c !important}a.has-text-link:hover,a.has-text-link:focus{color:#148f77 !important}.has-background-link{background-color:#1abc9c !important}.has-text-info{color:#024c7d !important}a.has-text-info:hover,a.has-text-info:focus{color:#012d4b !important}.has-background-info{background-color:#024c7d !important}.has-text-success{color:#008438 !important}a.has-text-success:hover,a.has-text-success:focus{color:#005122 !important}.has-background-success{background-color:#008438 !important}.has-text-warning{color:#ad8100 !important}a.has-text-warning:hover,a.has-text-warning:focus{color:#7a5b00 !important}.has-background-warning{background-color:#ad8100 !important}.has-text-danger{color:#9e1b0d !important}a.has-text-danger:hover,a.has-text-danger:focus{color:#6f1309 !important}.has-background-danger{background-color:#9e1b0d !important}.has-text-black-bis{color:#121212 !important}.has-background-black-bis{background-color:#121212 !important}.has-text-black-ter{color:#242424 !important}.has-background-black-ter{background-color:#242424 !important}.has-text-grey-darker{color:#282f2f !important}.has-background-grey-darker{background-color:#282f2f !important}.has-text-grey-dark{color:#343c3d !important}.has-background-grey-dark{background-color:#343c3d !important}.has-text-grey{color:#5e6d6f !important}.has-background-grey{background-color:#5e6d6f !important}.has-text-grey-light{color:#8c9b9d !important}.has-background-grey-light{background-color:#8c9b9d !important}.has-text-grey-lighter{color:#dbdee0 !important}.has-background-grey-lighter{background-color:#dbdee0 !important}.has-text-white-ter{color:#ecf0f1 !important}.has-background-white-ter{background-color:#ecf0f1 !important}.has-text-white-bis{color:#fafafa !important}.has-background-white-bis{background-color:#fafafa !important}.has-text-weight-light{font-weight:300 !important}.has-text-weight-normal{font-weight:400 !important}.has-text-weight-medium{font-weight:500 !important}.has-text-weight-semibold{font-weight:600 !important}.has-text-weight-bold{font-weight:700 !important}.is-family-primary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-secondary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-sans-serif{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-monospace{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-family-code{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-block{display:block !important}@media screen and (max-width: 768px){.is-block-mobile{display:block !important}}@media screen and (min-width: 769px),print{.is-block-tablet{display:block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-block-tablet-only{display:block !important}}@media screen and (max-width: 1055px){.is-block-touch{display:block !important}}@media screen and (min-width: 1056px){.is-block-desktop{display:block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-block-desktop-only{display:block !important}}@media screen and (min-width: 1216px){.is-block-widescreen{display:block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-block-widescreen-only{display:block !important}}@media screen and (min-width: 1408px){.is-block-fullhd{display:block !important}}.is-flex{display:flex !important}@media screen and (max-width: 768px){.is-flex-mobile{display:flex !important}}@media screen and (min-width: 769px),print{.is-flex-tablet{display:flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-flex-tablet-only{display:flex !important}}@media screen and (max-width: 1055px){.is-flex-touch{display:flex !important}}@media screen and (min-width: 1056px){.is-flex-desktop{display:flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-flex-desktop-only{display:flex !important}}@media screen and (min-width: 1216px){.is-flex-widescreen{display:flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-flex-widescreen-only{display:flex !important}}@media screen and (min-width: 1408px){.is-flex-fullhd{display:flex !important}}.is-inline{display:inline !important}@media screen and (max-width: 768px){.is-inline-mobile{display:inline !important}}@media screen and (min-width: 769px),print{.is-inline-tablet{display:inline !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-tablet-only{display:inline !important}}@media screen and (max-width: 1055px){.is-inline-touch{display:inline !important}}@media screen and (min-width: 1056px){.is-inline-desktop{display:inline !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-desktop-only{display:inline !important}}@media screen and (min-width: 1216px){.is-inline-widescreen{display:inline !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-widescreen-only{display:inline !important}}@media screen and (min-width: 1408px){.is-inline-fullhd{display:inline !important}}.is-inline-block{display:inline-block !important}@media screen and (max-width: 768px){.is-inline-block-mobile{display:inline-block !important}}@media screen and (min-width: 769px),print{.is-inline-block-tablet{display:inline-block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-block-tablet-only{display:inline-block !important}}@media screen and (max-width: 1055px){.is-inline-block-touch{display:inline-block !important}}@media screen and (min-width: 1056px){.is-inline-block-desktop{display:inline-block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-block-desktop-only{display:inline-block !important}}@media screen and (min-width: 1216px){.is-inline-block-widescreen{display:inline-block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-block-widescreen-only{display:inline-block !important}}@media screen and (min-width: 1408px){.is-inline-block-fullhd{display:inline-block !important}}.is-inline-flex{display:inline-flex !important}@media screen and (max-width: 768px){.is-inline-flex-mobile{display:inline-flex !important}}@media screen and (min-width: 769px),print{.is-inline-flex-tablet{display:inline-flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-flex-tablet-only{display:inline-flex !important}}@media screen and (max-width: 1055px){.is-inline-flex-touch{display:inline-flex !important}}@media screen and (min-width: 1056px){.is-inline-flex-desktop{display:inline-flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-flex-desktop-only{display:inline-flex !important}}@media screen and (min-width: 1216px){.is-inline-flex-widescreen{display:inline-flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-flex-widescreen-only{display:inline-flex !important}}@media screen and (min-width: 1408px){.is-inline-flex-fullhd{display:inline-flex !important}}.is-hidden{display:none !important}.is-sr-only{border:none !important;clip:rect(0, 0, 0, 0) !important;height:0.01em !important;overflow:hidden !important;padding:0 !important;position:absolute !important;white-space:nowrap !important;width:0.01em !important}@media screen and (max-width: 768px){.is-hidden-mobile{display:none !important}}@media screen and (min-width: 769px),print{.is-hidden-tablet{display:none !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-hidden-tablet-only{display:none !important}}@media screen and (max-width: 1055px){.is-hidden-touch{display:none !important}}@media screen and (min-width: 1056px){.is-hidden-desktop{display:none !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-hidden-desktop-only{display:none !important}}@media screen and (min-width: 1216px){.is-hidden-widescreen{display:none !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-hidden-widescreen-only{display:none !important}}@media screen and (min-width: 1408px){.is-hidden-fullhd{display:none !important}}.is-invisible{visibility:hidden !important}@media screen and (max-width: 768px){.is-invisible-mobile{visibility:hidden !important}}@media screen and (min-width: 769px),print{.is-invisible-tablet{visibility:hidden !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-invisible-tablet-only{visibility:hidden !important}}@media screen and (max-width: 1055px){.is-invisible-touch{visibility:hidden !important}}@media screen and (min-width: 1056px){.is-invisible-desktop{visibility:hidden !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-invisible-desktop-only{visibility:hidden !important}}@media screen and (min-width: 1216px){.is-invisible-widescreen{visibility:hidden !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-invisible-widescreen-only{visibility:hidden !important}}@media screen and (min-width: 1408px){.is-invisible-fullhd{visibility:hidden !important}}.is-marginless{margin:0 !important}.is-paddingless{padding:0 !important}.is-radiusless{border-radius:0 !important}.is-shadowless{box-shadow:none !important}.is-relative{position:relative !important}html.theme--documenter-dark{/*! + Theme: a11y-dark + Author: @ericwbailey + Maintainer: @ericwbailey + + Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css +*/}html.theme--documenter-dark html{background-color:#1f2424;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark article,html.theme--documenter-dark aside,html.theme--documenter-dark figure,html.theme--documenter-dark footer,html.theme--documenter-dark header,html.theme--documenter-dark hgroup,html.theme--documenter-dark section{display:block}html.theme--documenter-dark body,html.theme--documenter-dark button,html.theme--documenter-dark input,html.theme--documenter-dark select,html.theme--documenter-dark textarea{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif}html.theme--documenter-dark code,html.theme--documenter-dark pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark body{color:#fff;font-size:1em;font-weight:400;line-height:1.5}html.theme--documenter-dark a{color:#1abc9c;cursor:pointer;text-decoration:none}html.theme--documenter-dark a strong{color:currentColor}html.theme--documenter-dark a:hover{color:#1dd2af}html.theme--documenter-dark code{background-color:rgba(255,255,255,0.05);color:#ececec;font-size:.875em;font-weight:normal;padding:.1em}html.theme--documenter-dark hr{background-color:#282f2f;border:none;display:block;height:2px;margin:1.5rem 0}html.theme--documenter-dark img{height:auto;max-width:100%}html.theme--documenter-dark input[type="checkbox"],html.theme--documenter-dark input[type="radio"]{vertical-align:baseline}html.theme--documenter-dark small{font-size:.875em}html.theme--documenter-dark span{font-style:inherit;font-weight:inherit}html.theme--documenter-dark strong{color:#f2f2f2;font-weight:700}html.theme--documenter-dark fieldset{border:none}html.theme--documenter-dark pre{-webkit-overflow-scrolling:touch;background-color:#282f2f;color:#fff;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}html.theme--documenter-dark pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}html.theme--documenter-dark table td,html.theme--documenter-dark table th{vertical-align:top}html.theme--documenter-dark table td:not([align]),html.theme--documenter-dark table th:not([align]){text-align:left}html.theme--documenter-dark table th{color:#f2f2f2}html.theme--documenter-dark .box{background-color:#343c3d;border-radius:8px;box-shadow:none;color:#fff;display:block;padding:1.25rem}html.theme--documenter-dark a.box:hover,html.theme--documenter-dark a.box:focus{box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px #1abc9c}html.theme--documenter-dark a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2),0 0 0 1px #1abc9c}html.theme--documenter-dark .button{background-color:#282f2f;border-color:#4c5759;border-width:1px;color:#375a7f;cursor:pointer;justify-content:center;padding-bottom:calc(0.375em - 1px);padding-left:.75em;padding-right:.75em;padding-top:calc(0.375em - 1px);text-align:center;white-space:nowrap}html.theme--documenter-dark .button strong{color:inherit}html.theme--documenter-dark .button .icon,html.theme--documenter-dark .button .icon.is-small,html.theme--documenter-dark .button #documenter .docs-sidebar form.docs-search>input.icon,html.theme--documenter-dark #documenter .docs-sidebar .button form.docs-search>input.icon,html.theme--documenter-dark .button .icon.is-medium,html.theme--documenter-dark .button .icon.is-large{height:1.5em;width:1.5em}html.theme--documenter-dark .button .icon:first-child:not(:last-child){margin-left:calc(-0.375em - 1px);margin-right:0.1875em}html.theme--documenter-dark .button .icon:last-child:not(:first-child){margin-left:0.1875em;margin-right:calc(-0.375em - 1px)}html.theme--documenter-dark .button .icon:first-child:last-child{margin-left:calc(-0.375em - 1px);margin-right:calc(-0.375em - 1px)}html.theme--documenter-dark .button:hover,html.theme--documenter-dark .button.is-hovered{border-color:#8c9b9d;color:#f2f2f2}html.theme--documenter-dark .button:focus,html.theme--documenter-dark .button.is-focused{border-color:#8c9b9d;color:#17a689}html.theme--documenter-dark .button:focus:not(:active),html.theme--documenter-dark .button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button:active,html.theme--documenter-dark .button.is-active{border-color:#343c3d;color:#f2f2f2}html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;color:#fff;text-decoration:underline}html.theme--documenter-dark .button.is-text:hover,html.theme--documenter-dark .button.is-text.is-hovered,html.theme--documenter-dark .button.is-text:focus,html.theme--documenter-dark .button.is-text.is-focused{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .button.is-text:active,html.theme--documenter-dark .button.is-text.is-active{background-color:#1d2122;color:#f2f2f2}html.theme--documenter-dark .button.is-text[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:hover,html.theme--documenter-dark .button.is-white.is-hovered{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus,html.theme--documenter-dark .button.is-white.is-focused{border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus:not(:active),html.theme--documenter-dark .button.is-white.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white.is-active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-hovered{background-color:#000}html.theme--documenter-dark .button.is-white.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-white.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-outlined.is-focused{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-focused{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:hover,html.theme--documenter-dark .button.is-black.is-hovered{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus,html.theme--documenter-dark .button.is-black.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus:not(:active),html.theme--documenter-dark .button.is-black.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black.is-active{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-black.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-outlined.is-focused{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-focused{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:transparent;color:#282f2f}html.theme--documenter-dark .button.is-light:hover,html.theme--documenter-dark .button.is-light.is-hovered{background-color:#e5eaec;border-color:transparent;color:#282f2f}html.theme--documenter-dark .button.is-light:focus,html.theme--documenter-dark .button.is-light.is-focused{border-color:transparent;color:#282f2f}html.theme--documenter-dark .button.is-light:focus:not(:active),html.theme--documenter-dark .button.is-light.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light.is-active{background-color:#dde4e6;border-color:transparent;color:#282f2f}html.theme--documenter-dark .button.is-light[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-light.is-inverted{background-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-hovered{background-color:#1d2122}html.theme--documenter-dark .button.is-light.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted{background-color:#282f2f;border-color:transparent;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-loading::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-outlined.is-focused{background-color:#ecf0f1;border-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-light.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:#282f2f;color:#282f2f}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-focused{background-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:#282f2f;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark,html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:transparent;color:#ecf0f1}html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover,html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered{background-color:#232829;border-color:transparent;color:#ecf0f1}html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused{border-color:transparent;color:#ecf0f1}html.theme--documenter-dark .button.is-dark:focus:not(:active),html.theme--documenter-dark .content kbd.button:focus:not(:active),html.theme--documenter-dark .button.is-dark.is-focused:not(:active),html.theme--documenter-dark .content kbd.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active{background-color:#1d2122;border-color:transparent;color:#ecf0f1}html.theme--documenter-dark .button.is-dark[disabled],html.theme--documenter-dark .content kbd.button[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark,fieldset[disabled] html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-dark.is-inverted,html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted:hover,html.theme--documenter-dark .content kbd.button.is-inverted:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-hovered{background-color:#dde4e6}html.theme--documenter-dark .button.is-dark.is-inverted[disabled],html.theme--documenter-dark .content kbd.button.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#ecf0f1;border-color:transparent;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-loading::after,html.theme--documenter-dark .content kbd.button.is-loading::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-dark.is-outlined,html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-outlined.is-focused{background-color:#282f2f;border-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-dark.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#ecf0f1;color:#ecf0f1}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-focused{background-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#ecf0f1;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-primary,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus:not(:active),html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus:not(:active),html.theme--documenter-dark .button.is-primary.is-focused:not(:active),html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink:not(:active){box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary[disabled],html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-primary.is-inverted,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-hovered.docs-sourcelink{background-color:#f2f2f2}html.theme--documenter-dark .button.is-primary.is-inverted[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;border-color:transparent;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-loading.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-focused.docs-sourcelink{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-focused.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:hover,html.theme--documenter-dark .button.is-link.is-hovered{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus,html.theme--documenter-dark .button.is-link.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus:not(:active),html.theme--documenter-dark .button.is-link.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link.is-active{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-link.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-outlined.is-focused{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-focused{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:hover,html.theme--documenter-dark .button.is-info.is-hovered{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus,html.theme--documenter-dark .button.is-info.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus:not(:active),html.theme--documenter-dark .button.is-info.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info.is-active{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-info.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;color:#024c7d}html.theme--documenter-dark .button.is-info.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-outlined.is-focused{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-focused{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:hover,html.theme--documenter-dark .button.is-success.is-hovered{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus,html.theme--documenter-dark .button.is-success.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus:not(:active),html.theme--documenter-dark .button.is-success.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success.is-active{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-success.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;color:#008438}html.theme--documenter-dark .button.is-success.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-outlined.is-focused{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-focused{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:hover,html.theme--documenter-dark .button.is-warning.is-hovered{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus,html.theme--documenter-dark .button.is-warning.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus:not(:active),html.theme--documenter-dark .button.is-warning.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning.is-active{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-warning.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-outlined.is-focused{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-focused{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:hover,html.theme--documenter-dark .button.is-danger.is-hovered{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus,html.theme--documenter-dark .button.is-danger.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus:not(:active),html.theme--documenter-dark .button.is-danger.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger.is-active{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-danger.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-outlined.is-focused{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-focused{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{border-radius:3px;font-size:.85em}html.theme--documenter-dark .button.is-normal{font-size:15px}html.theme--documenter-dark .button.is-medium{font-size:1.25rem}html.theme--documenter-dark .button.is-large{font-size:1.5rem}html.theme--documenter-dark .button[disabled],fieldset[disabled] html.theme--documenter-dark .button{background-color:#8c9b9d;border-color:#dbdee0;box-shadow:none;opacity:.5}html.theme--documenter-dark .button.is-fullwidth{display:flex;width:100%}html.theme--documenter-dark .button.is-loading{color:transparent !important;pointer-events:none}html.theme--documenter-dark .button.is-loading::after{position:absolute;left:calc(50% - (1em / 2));top:calc(50% - (1em / 2));position:absolute !important}html.theme--documenter-dark .button.is-static{background-color:#282f2f;border-color:#5e6d6f;color:#dbdee0;box-shadow:none;pointer-events:none}html.theme--documenter-dark .button.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{border-radius:290486px;padding-left:1em;padding-right:1em}html.theme--documenter-dark .buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .buttons .button{margin-bottom:0.5rem}html.theme--documenter-dark .buttons .button:not(:last-child):not(.is-fullwidth){margin-right:0.5rem}html.theme--documenter-dark .buttons:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .buttons:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){border-radius:3px;font-size:.85em}html.theme--documenter-dark .buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}html.theme--documenter-dark .buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}html.theme--documenter-dark .buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}html.theme--documenter-dark .buttons.has-addons .button:last-child{margin-right:0}html.theme--documenter-dark .buttons.has-addons .button:hover,html.theme--documenter-dark .buttons.has-addons .button.is-hovered{z-index:2}html.theme--documenter-dark .buttons.has-addons .button:focus,html.theme--documenter-dark .buttons.has-addons .button.is-focused,html.theme--documenter-dark .buttons.has-addons .button:active,html.theme--documenter-dark .buttons.has-addons .button.is-active,html.theme--documenter-dark .buttons.has-addons .button.is-selected{z-index:3}html.theme--documenter-dark .buttons.has-addons .button:focus:hover,html.theme--documenter-dark .buttons.has-addons .button.is-focused:hover,html.theme--documenter-dark .buttons.has-addons .button:active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-selected:hover{z-index:4}html.theme--documenter-dark .buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .buttons.is-centered{justify-content:center}html.theme--documenter-dark .buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}html.theme--documenter-dark .buttons.is-right{justify-content:flex-end}html.theme--documenter-dark .buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}html.theme--documenter-dark .container{flex-grow:1;margin:0 auto;position:relative;width:auto}@media screen and (min-width: 1056px){html.theme--documenter-dark .container{max-width:992px}html.theme--documenter-dark .container.is-fluid{margin-left:32px;margin-right:32px;max-width:none}}@media screen and (max-width: 1215px){html.theme--documenter-dark .container.is-widescreen{max-width:1152px}}@media screen and (max-width: 1407px){html.theme--documenter-dark .container.is-fullhd{max-width:1344px}}@media screen and (min-width: 1216px){html.theme--documenter-dark .container{max-width:1152px}}@media screen and (min-width: 1408px){html.theme--documenter-dark .container{max-width:1344px}}html.theme--documenter-dark .content li+li{margin-top:0.25em}html.theme--documenter-dark .content p:not(:last-child),html.theme--documenter-dark .content dl:not(:last-child),html.theme--documenter-dark .content ol:not(:last-child),html.theme--documenter-dark .content ul:not(:last-child),html.theme--documenter-dark .content blockquote:not(:last-child),html.theme--documenter-dark .content pre:not(:last-child),html.theme--documenter-dark .content table:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .content h1,html.theme--documenter-dark .content h2,html.theme--documenter-dark .content h3,html.theme--documenter-dark .content h4,html.theme--documenter-dark .content h5,html.theme--documenter-dark .content h6{color:#f2f2f2;font-weight:600;line-height:1.125}html.theme--documenter-dark .content h1{font-size:2em;margin-bottom:0.5em}html.theme--documenter-dark .content h1:not(:first-child){margin-top:1em}html.theme--documenter-dark .content h2{font-size:1.75em;margin-bottom:0.5714em}html.theme--documenter-dark .content h2:not(:first-child){margin-top:1.1428em}html.theme--documenter-dark .content h3{font-size:1.5em;margin-bottom:0.6666em}html.theme--documenter-dark .content h3:not(:first-child){margin-top:1.3333em}html.theme--documenter-dark .content h4{font-size:1.25em;margin-bottom:0.8em}html.theme--documenter-dark .content h5{font-size:1.125em;margin-bottom:0.8888em}html.theme--documenter-dark .content h6{font-size:1em;margin-bottom:1em}html.theme--documenter-dark .content blockquote{background-color:#282f2f;border-left:5px solid #5e6d6f;padding:1.25em 1.5em}html.theme--documenter-dark .content ol{list-style-position:outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ol:not([type]){list-style-type:decimal}html.theme--documenter-dark .content ol.is-lower-alpha:not([type]){list-style-type:lower-alpha}html.theme--documenter-dark .content ol.is-lower-roman:not([type]){list-style-type:lower-roman}html.theme--documenter-dark .content ol.is-upper-alpha:not([type]){list-style-type:upper-alpha}html.theme--documenter-dark .content ol.is-upper-roman:not([type]){list-style-type:upper-roman}html.theme--documenter-dark .content ul{list-style:disc outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ul ul{list-style-type:circle;margin-top:0.5em}html.theme--documenter-dark .content ul ul ul{list-style-type:square}html.theme--documenter-dark .content dd{margin-left:2em}html.theme--documenter-dark .content figure{margin-left:2em;margin-right:2em;text-align:center}html.theme--documenter-dark .content figure:not(:first-child){margin-top:2em}html.theme--documenter-dark .content figure:not(:last-child){margin-bottom:2em}html.theme--documenter-dark .content figure img{display:inline-block}html.theme--documenter-dark .content figure figcaption{font-style:italic}html.theme--documenter-dark .content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:0;white-space:pre;word-wrap:normal}html.theme--documenter-dark .content sup,html.theme--documenter-dark .content sub{font-size:75%}html.theme--documenter-dark .content table{width:100%}html.theme--documenter-dark .content table td,html.theme--documenter-dark .content table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .content table th{color:#f2f2f2}html.theme--documenter-dark .content table th:not([align]){text-align:left}html.theme--documenter-dark .content table thead td,html.theme--documenter-dark .content table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .content table tfoot td,html.theme--documenter-dark .content table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .content table tbody tr:last-child td,html.theme--documenter-dark .content table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .content .tabs li+li{margin-top:0}html.theme--documenter-dark .content.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.content{font-size:.85em}html.theme--documenter-dark .content.is-medium{font-size:1.25rem}html.theme--documenter-dark .content.is-large{font-size:1.5rem}html.theme--documenter-dark .icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}html.theme--documenter-dark .icon.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.icon{height:1rem;width:1rem}html.theme--documenter-dark .icon.is-medium{height:2rem;width:2rem}html.theme--documenter-dark .icon.is-large{height:3rem;width:3rem}html.theme--documenter-dark .image,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{display:block;position:relative}html.theme--documenter-dark .image img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img{display:block;height:auto;width:100%}html.theme--documenter-dark .image img.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img.is-rounded{border-radius:290486px}html.theme--documenter-dark .image.is-square img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square img,html.theme--documenter-dark .image.is-square .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,html.theme--documenter-dark .image.is-1by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 img,html.theme--documenter-dark .image.is-1by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,html.theme--documenter-dark .image.is-5by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 img,html.theme--documenter-dark .image.is-5by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,html.theme--documenter-dark .image.is-4by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 img,html.theme--documenter-dark .image.is-4by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,html.theme--documenter-dark .image.is-3by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 img,html.theme--documenter-dark .image.is-3by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,html.theme--documenter-dark .image.is-5by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 img,html.theme--documenter-dark .image.is-5by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,html.theme--documenter-dark .image.is-16by9 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 img,html.theme--documenter-dark .image.is-16by9 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,html.theme--documenter-dark .image.is-2by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 img,html.theme--documenter-dark .image.is-2by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,html.theme--documenter-dark .image.is-3by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 img,html.theme--documenter-dark .image.is-3by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,html.theme--documenter-dark .image.is-4by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 img,html.theme--documenter-dark .image.is-4by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,html.theme--documenter-dark .image.is-3by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 img,html.theme--documenter-dark .image.is-3by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,html.theme--documenter-dark .image.is-2by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 img,html.theme--documenter-dark .image.is-2by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,html.theme--documenter-dark .image.is-3by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 img,html.theme--documenter-dark .image.is-3by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,html.theme--documenter-dark .image.is-9by16 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 img,html.theme--documenter-dark .image.is-9by16 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,html.theme--documenter-dark .image.is-1by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 img,html.theme--documenter-dark .image.is-1by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,html.theme--documenter-dark .image.is-1by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 img,html.theme--documenter-dark .image.is-1by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio{height:100%;width:100%}html.theme--documenter-dark .image.is-square,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square,html.theme--documenter-dark .image.is-1by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1{padding-top:100%}html.theme--documenter-dark .image.is-5by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4{padding-top:80%}html.theme--documenter-dark .image.is-4by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3{padding-top:75%}html.theme--documenter-dark .image.is-3by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2{padding-top:66.6666%}html.theme--documenter-dark .image.is-5by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3{padding-top:60%}html.theme--documenter-dark .image.is-16by9,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9{padding-top:56.25%}html.theme--documenter-dark .image.is-2by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1{padding-top:50%}html.theme--documenter-dark .image.is-3by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1{padding-top:33.3333%}html.theme--documenter-dark .image.is-4by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5{padding-top:125%}html.theme--documenter-dark .image.is-3by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4{padding-top:133.3333%}html.theme--documenter-dark .image.is-2by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3{padding-top:150%}html.theme--documenter-dark .image.is-3by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5{padding-top:166.6666%}html.theme--documenter-dark .image.is-9by16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16{padding-top:177.7777%}html.theme--documenter-dark .image.is-1by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2{padding-top:200%}html.theme--documenter-dark .image.is-1by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3{padding-top:300%}html.theme--documenter-dark .image.is-16x16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16x16{height:16px;width:16px}html.theme--documenter-dark .image.is-24x24,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-24x24{height:24px;width:24px}html.theme--documenter-dark .image.is-32x32,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-32x32{height:32px;width:32px}html.theme--documenter-dark .image.is-48x48,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-48x48{height:48px;width:48px}html.theme--documenter-dark .image.is-64x64,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-64x64{height:64px;width:64px}html.theme--documenter-dark .image.is-96x96,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-96x96{height:96px;width:96px}html.theme--documenter-dark .image.is-128x128,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-128x128{height:128px;width:128px}html.theme--documenter-dark .notification{background-color:#282f2f;border-radius:.4em;padding:1.25rem 2.5rem 1.25rem 1.5rem;position:relative}html.theme--documenter-dark .notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .notification strong{color:currentColor}html.theme--documenter-dark .notification code,html.theme--documenter-dark .notification pre{background:#fff}html.theme--documenter-dark .notification pre code{background:transparent}html.theme--documenter-dark .notification>.delete{position:absolute;right:0.5rem;top:0.5rem}html.theme--documenter-dark .notification .title,html.theme--documenter-dark .notification .subtitle,html.theme--documenter-dark .notification .content{color:currentColor}html.theme--documenter-dark .notification.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .notification.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .notification.is-light{background-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .notification.is-dark,html.theme--documenter-dark .content kbd.notification{background-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .notification.is-primary,html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .notification.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .notification.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .notification.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .notification.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .notification.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:290486px;display:block;height:15px;overflow:hidden;padding:0;width:100%}html.theme--documenter-dark .progress::-webkit-progress-bar{background-color:#5e6d6f}html.theme--documenter-dark .progress::-webkit-progress-value{background-color:#dbdee0}html.theme--documenter-dark .progress::-moz-progress-bar{background-color:#dbdee0}html.theme--documenter-dark .progress::-ms-fill{background-color:#dbdee0;border:none}html.theme--documenter-dark .progress.is-white::-webkit-progress-value{background-color:#fff}html.theme--documenter-dark .progress.is-white::-moz-progress-bar{background-color:#fff}html.theme--documenter-dark .progress.is-white::-ms-fill{background-color:#fff}html.theme--documenter-dark .progress.is-white:indeterminate{background-image:linear-gradient(to right, #fff 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress.is-black::-webkit-progress-value{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-moz-progress-bar{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-ms-fill{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black:indeterminate{background-image:linear-gradient(to right, #0a0a0a 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress.is-light::-webkit-progress-value{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-moz-progress-bar{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-ms-fill{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light:indeterminate{background-image:linear-gradient(to right, #ecf0f1 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress.is-dark::-webkit-progress-value,html.theme--documenter-dark .content kbd.progress::-webkit-progress-value{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-moz-progress-bar,html.theme--documenter-dark .content kbd.progress::-moz-progress-bar{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-ms-fill,html.theme--documenter-dark .content kbd.progress::-ms-fill{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark:indeterminate,html.theme--documenter-dark .content kbd.progress:indeterminate{background-image:linear-gradient(to right, #282f2f 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress.is-primary::-webkit-progress-value,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-webkit-progress-value{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-moz-progress-bar,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-moz-progress-bar{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-ms-fill,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-ms-fill{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary:indeterminate,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink:indeterminate{background-image:linear-gradient(to right, #375a7f 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress.is-link::-webkit-progress-value{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-moz-progress-bar{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-ms-fill{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link:indeterminate{background-image:linear-gradient(to right, #1abc9c 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress.is-info::-webkit-progress-value{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-moz-progress-bar{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-ms-fill{background-color:#024c7d}html.theme--documenter-dark .progress.is-info:indeterminate{background-image:linear-gradient(to right, #024c7d 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress.is-success::-webkit-progress-value{background-color:#008438}html.theme--documenter-dark .progress.is-success::-moz-progress-bar{background-color:#008438}html.theme--documenter-dark .progress.is-success::-ms-fill{background-color:#008438}html.theme--documenter-dark .progress.is-success:indeterminate{background-image:linear-gradient(to right, #008438 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress.is-warning::-webkit-progress-value{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-moz-progress-bar{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-ms-fill{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning:indeterminate{background-image:linear-gradient(to right, #ad8100 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress.is-danger::-webkit-progress-value{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-moz-progress-bar{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-ms-fill{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger:indeterminate{background-image:linear-gradient(to right, #9e1b0d 30%, #5e6d6f 30%)}html.theme--documenter-dark .progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#5e6d6f;background-image:linear-gradient(to right, #fff 30%, #5e6d6f 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}html.theme--documenter-dark .progress:indeterminate::-webkit-progress-bar{background-color:transparent}html.theme--documenter-dark .progress:indeterminate::-moz-progress-bar{background-color:transparent}html.theme--documenter-dark .progress.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.progress{height:.85em}html.theme--documenter-dark .progress.is-medium{height:1.25rem}html.theme--documenter-dark .progress.is-large{height:1.5rem}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}html.theme--documenter-dark .table{background-color:#343c3d;color:#fff}html.theme--documenter-dark .table td,html.theme--documenter-dark .table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .table td.is-white,html.theme--documenter-dark .table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .table td.is-black,html.theme--documenter-dark .table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .table td.is-light,html.theme--documenter-dark .table th.is-light{background-color:#ecf0f1;border-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .table td.is-dark,html.theme--documenter-dark .table th.is-dark{background-color:#282f2f;border-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .table td.is-primary,html.theme--documenter-dark .table th.is-primary{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-link,html.theme--documenter-dark .table th.is-link{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .table td.is-info,html.theme--documenter-dark .table th.is-info{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .table td.is-success,html.theme--documenter-dark .table th.is-success{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .table td.is-warning,html.theme--documenter-dark .table th.is-warning{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .table td.is-danger,html.theme--documenter-dark .table th.is-danger{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .table td.is-narrow,html.theme--documenter-dark .table th.is-narrow{white-space:nowrap;width:1%}html.theme--documenter-dark .table td.is-selected,html.theme--documenter-dark .table th.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-selected a,html.theme--documenter-dark .table td.is-selected strong,html.theme--documenter-dark .table th.is-selected a,html.theme--documenter-dark .table th.is-selected strong{color:currentColor}html.theme--documenter-dark .table th{color:#f2f2f2}html.theme--documenter-dark .table th:not([align]){text-align:left}html.theme--documenter-dark .table tr.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table tr.is-selected a,html.theme--documenter-dark .table tr.is-selected strong{color:currentColor}html.theme--documenter-dark .table tr.is-selected td,html.theme--documenter-dark .table tr.is-selected th{border-color:#fff;color:currentColor}html.theme--documenter-dark .table thead{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table thead td,html.theme--documenter-dark .table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .table tfoot{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tfoot td,html.theme--documenter-dark .table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .table tbody{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tbody tr:last-child td,html.theme--documenter-dark .table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .table.is-bordered td,html.theme--documenter-dark .table.is-bordered th{border-width:1px}html.theme--documenter-dark .table.is-bordered tr:last-child td,html.theme--documenter-dark .table.is-bordered tr:last-child th{border-bottom-width:1px}html.theme--documenter-dark .table.is-fullwidth{width:100%}html.theme--documenter-dark .table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#2d3435}html.theme--documenter-dark .table.is-narrow td,html.theme--documenter-dark .table.is-narrow th{padding:0.25em 0.5em}html.theme--documenter-dark .table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#282f2f}html.theme--documenter-dark .table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}html.theme--documenter-dark .tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .tags .tag,html.theme--documenter-dark .tags .content kbd,html.theme--documenter-dark .content .tags kbd,html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink{margin-bottom:0.5rem}html.theme--documenter-dark .tags .tag:not(:last-child),html.theme--documenter-dark .tags .content kbd:not(:last-child),html.theme--documenter-dark .content .tags kbd:not(:last-child),html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0.5rem}html.theme--documenter-dark .tags:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .tags:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .tags.are-medium .tag:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .content kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .content .tags.are-medium kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-large){font-size:15px}html.theme--documenter-dark .tags.are-large .tag:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .content kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .content .tags.are-large kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-medium){font-size:1.25rem}html.theme--documenter-dark .tags.is-centered{justify-content:center}html.theme--documenter-dark .tags.is-centered .tag,html.theme--documenter-dark .tags.is-centered .content kbd,html.theme--documenter-dark .content .tags.is-centered kbd,html.theme--documenter-dark .tags.is-centered .docstring>section>a.docs-sourcelink{margin-right:0.25rem;margin-left:0.25rem}html.theme--documenter-dark .tags.is-right{justify-content:flex-end}html.theme--documenter-dark .tags.is-right .tag:not(:first-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:first-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0.5rem}html.theme--documenter-dark .tags.is-right .tag:not(:last-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:last-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0}html.theme--documenter-dark .tags.has-addons .tag,html.theme--documenter-dark .tags.has-addons .content kbd,html.theme--documenter-dark .content .tags.has-addons kbd,html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink{margin-right:0}html.theme--documenter-dark .tags.has-addons .tag:not(:first-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:first-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0;border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .tags.has-addons .tag:not(:last-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:last-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .tag:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){align-items:center;background-color:#282f2f;border-radius:.4em;color:#fff;display:inline-flex;font-size:.85em;height:2em;justify-content:center;line-height:1.5;padding-left:0.75em;padding-right:0.75em;white-space:nowrap}html.theme--documenter-dark .tag:not(body) .delete,html.theme--documenter-dark .content kbd:not(body) .delete,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .delete{margin-left:0.25rem;margin-right:-0.375rem}html.theme--documenter-dark .tag.is-white:not(body),html.theme--documenter-dark .content kbd.is-white:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-white:not(body){background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .tag.is-black:not(body),html.theme--documenter-dark .content kbd.is-black:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-black:not(body){background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .tag.is-light:not(body),html.theme--documenter-dark .content kbd.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .tag.is-dark:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-dark:not(body),html.theme--documenter-dark .content .docstring>section>kbd:not(body){background-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .tag.is-primary:not(body),html.theme--documenter-dark .content kbd.is-primary:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){background-color:#375a7f;color:#fff}html.theme--documenter-dark .tag.is-link:not(body),html.theme--documenter-dark .content kbd.is-link:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link:not(body){background-color:#1abc9c;color:#fff}html.theme--documenter-dark .tag.is-info:not(body),html.theme--documenter-dark .content kbd.is-info:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info:not(body){background-color:#024c7d;color:#fff}html.theme--documenter-dark .tag.is-success:not(body),html.theme--documenter-dark .content kbd.is-success:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success:not(body){background-color:#008438;color:#fff}html.theme--documenter-dark .tag.is-warning:not(body),html.theme--documenter-dark .content kbd.is-warning:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning:not(body){background-color:#ad8100;color:#fff}html.theme--documenter-dark .tag.is-danger:not(body),html.theme--documenter-dark .content kbd.is-danger:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger:not(body){background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .tag.is-normal:not(body),html.theme--documenter-dark .content kbd.is-normal:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-normal:not(body){font-size:.85em}html.theme--documenter-dark .tag.is-medium:not(body),html.theme--documenter-dark .content kbd.is-medium:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-medium:not(body){font-size:15px}html.theme--documenter-dark .tag.is-large:not(body),html.theme--documenter-dark .content kbd.is-large:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-large:not(body){font-size:1.25rem}html.theme--documenter-dark .tag:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .content kbd:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:not(:last-child){margin-left:-0.375em;margin-right:0.1875em}html.theme--documenter-dark .tag:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .content kbd:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:last-child:not(:first-child){margin-left:0.1875em;margin-right:-0.375em}html.theme--documenter-dark .tag:not(body) .icon:first-child:last-child,html.theme--documenter-dark .content kbd:not(body) .icon:first-child:last-child,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:last-child{margin-left:-0.375em;margin-right:-0.375em}html.theme--documenter-dark .tag.is-delete:not(body),html.theme--documenter-dark .content kbd.is-delete:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body){margin-left:1px;padding:0;position:relative;width:2em}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before,html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before{height:1px;width:50%}html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{height:50%;width:1px}html.theme--documenter-dark .tag.is-delete:not(body):hover,html.theme--documenter-dark .content kbd.is-delete:not(body):hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):hover,html.theme--documenter-dark .tag.is-delete:not(body):focus,html.theme--documenter-dark .content kbd.is-delete:not(body):focus,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):focus{background-color:#1d2122}html.theme--documenter-dark .tag.is-delete:not(body):active,html.theme--documenter-dark .content kbd.is-delete:not(body):active,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):active{background-color:#111414}html.theme--documenter-dark .tag.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:not(body),html.theme--documenter-dark .content kbd.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-rounded:not(body){border-radius:290486px}html.theme--documenter-dark a.tag:hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:hover{text-decoration:underline}html.theme--documenter-dark .title,html.theme--documenter-dark .subtitle{word-break:break-word}html.theme--documenter-dark .title em,html.theme--documenter-dark .title span,html.theme--documenter-dark .subtitle em,html.theme--documenter-dark .subtitle span{font-weight:inherit}html.theme--documenter-dark .title sub,html.theme--documenter-dark .subtitle sub{font-size:.75em}html.theme--documenter-dark .title sup,html.theme--documenter-dark .subtitle sup{font-size:.75em}html.theme--documenter-dark .title .tag,html.theme--documenter-dark .title .content kbd,html.theme--documenter-dark .content .title kbd,html.theme--documenter-dark .title .docstring>section>a.docs-sourcelink,html.theme--documenter-dark .subtitle .tag,html.theme--documenter-dark .subtitle .content kbd,html.theme--documenter-dark .content .subtitle kbd,html.theme--documenter-dark .subtitle .docstring>section>a.docs-sourcelink{vertical-align:middle}html.theme--documenter-dark .title{color:#fff;font-size:2rem;font-weight:500;line-height:1.125}html.theme--documenter-dark .title strong{color:inherit;font-weight:inherit}html.theme--documenter-dark .title+.highlight{margin-top:-0.75rem}html.theme--documenter-dark .title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}html.theme--documenter-dark .title.is-1{font-size:3rem}html.theme--documenter-dark .title.is-2{font-size:2.5rem}html.theme--documenter-dark .title.is-3{font-size:2rem}html.theme--documenter-dark .title.is-4{font-size:1.5rem}html.theme--documenter-dark .title.is-5{font-size:1.25rem}html.theme--documenter-dark .title.is-6{font-size:15px}html.theme--documenter-dark .title.is-7{font-size:.85em}html.theme--documenter-dark .subtitle{color:#8c9b9d;font-size:1.25rem;font-weight:400;line-height:1.25}html.theme--documenter-dark .subtitle strong{color:#8c9b9d;font-weight:600}html.theme--documenter-dark .subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}html.theme--documenter-dark .subtitle.is-1{font-size:3rem}html.theme--documenter-dark .subtitle.is-2{font-size:2.5rem}html.theme--documenter-dark .subtitle.is-3{font-size:2rem}html.theme--documenter-dark .subtitle.is-4{font-size:1.5rem}html.theme--documenter-dark .subtitle.is-5{font-size:1.25rem}html.theme--documenter-dark .subtitle.is-6{font-size:15px}html.theme--documenter-dark .subtitle.is-7{font-size:.85em}html.theme--documenter-dark .heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}html.theme--documenter-dark .highlight{font-weight:400;max-width:100%;overflow:hidden;padding:0}html.theme--documenter-dark .highlight pre{overflow:auto;max-width:100%}html.theme--documenter-dark .number{align-items:center;background-color:#282f2f;border-radius:290486px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:0.25rem 0.5rem;text-align:center;vertical-align:top}html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#1f2424;border-color:#5e6d6f;border-radius:.4em;color:#dbdee0}html.theme--documenter-dark .select select::-moz-placeholder,html.theme--documenter-dark .textarea::-moz-placeholder,html.theme--documenter-dark .input::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:rgba(219,222,224,0.3)}html.theme--documenter-dark .select select::-webkit-input-placeholder,html.theme--documenter-dark .textarea::-webkit-input-placeholder,html.theme--documenter-dark .input::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:rgba(219,222,224,0.3)}html.theme--documenter-dark .select select:-moz-placeholder,html.theme--documenter-dark .textarea:-moz-placeholder,html.theme--documenter-dark .input:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:rgba(219,222,224,0.3)}html.theme--documenter-dark .select select:-ms-input-placeholder,html.theme--documenter-dark .textarea:-ms-input-placeholder,html.theme--documenter-dark .input:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:rgba(219,222,224,0.3)}html.theme--documenter-dark .select select:hover,html.theme--documenter-dark .textarea:hover,html.theme--documenter-dark .input:hover,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:hover,html.theme--documenter-dark .select select.is-hovered,html.theme--documenter-dark .is-hovered.textarea,html.theme--documenter-dark .is-hovered.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-hovered{border-color:#8c9b9d}html.theme--documenter-dark .select select:focus,html.theme--documenter-dark .textarea:focus,html.theme--documenter-dark .input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:focus,html.theme--documenter-dark .select select.is-focused,html.theme--documenter-dark .is-focused.textarea,html.theme--documenter-dark .is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .select select:active,html.theme--documenter-dark .textarea:active,html.theme--documenter-dark .input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:active,html.theme--documenter-dark .select select.is-active,html.theme--documenter-dark .is-active.textarea,html.theme--documenter-dark .is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{border-color:#1abc9c;box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select select[disabled],html.theme--documenter-dark .textarea[disabled],html.theme--documenter-dark .input[disabled],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled],fieldset[disabled] html.theme--documenter-dark .select select,fieldset[disabled] html.theme--documenter-dark .textarea,fieldset[disabled] html.theme--documenter-dark .input,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#8c9b9d;border-color:#282f2f;box-shadow:none;color:#fff}html.theme--documenter-dark .select select[disabled]::-moz-placeholder,html.theme--documenter-dark .textarea[disabled]::-moz-placeholder,html.theme--documenter-dark .input[disabled]::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .textarea[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .input[disabled]::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-moz-placeholder,html.theme--documenter-dark .textarea[disabled]:-moz-placeholder,html.theme--documenter-dark .input[disabled]:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-ms-input-placeholder,html.theme--documenter-dark .textarea[disabled]:-ms-input-placeholder,html.theme--documenter-dark .input[disabled]:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{box-shadow:inset 0 1px 2px rgba(10,10,10,0.1);max-width:100%;width:100%}html.theme--documenter-dark .textarea[readonly],html.theme--documenter-dark .input[readonly],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[readonly]{box-shadow:none}html.theme--documenter-dark .is-white.textarea,html.theme--documenter-dark .is-white.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white{border-color:#fff}html.theme--documenter-dark .is-white.textarea:focus,html.theme--documenter-dark .is-white.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:focus,html.theme--documenter-dark .is-white.is-focused.textarea,html.theme--documenter-dark .is-white.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-white.textarea:active,html.theme--documenter-dark .is-white.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:active,html.theme--documenter-dark .is-white.is-active.textarea,html.theme--documenter-dark .is-white.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .is-black.textarea,html.theme--documenter-dark .is-black.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black{border-color:#0a0a0a}html.theme--documenter-dark .is-black.textarea:focus,html.theme--documenter-dark .is-black.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:focus,html.theme--documenter-dark .is-black.is-focused.textarea,html.theme--documenter-dark .is-black.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-black.textarea:active,html.theme--documenter-dark .is-black.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:active,html.theme--documenter-dark .is-black.is-active.textarea,html.theme--documenter-dark .is-black.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .is-light.textarea,html.theme--documenter-dark .is-light.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light{border-color:#ecf0f1}html.theme--documenter-dark .is-light.textarea:focus,html.theme--documenter-dark .is-light.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:focus,html.theme--documenter-dark .is-light.is-focused.textarea,html.theme--documenter-dark .is-light.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-light.textarea:active,html.theme--documenter-dark .is-light.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:active,html.theme--documenter-dark .is-light.is-active.textarea,html.theme--documenter-dark .is-light.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .is-dark.textarea,html.theme--documenter-dark .content kbd.textarea,html.theme--documenter-dark .is-dark.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark,html.theme--documenter-dark .content kbd.input{border-color:#282f2f}html.theme--documenter-dark .is-dark.textarea:focus,html.theme--documenter-dark .content kbd.textarea:focus,html.theme--documenter-dark .is-dark.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:focus,html.theme--documenter-dark .content kbd.input:focus,html.theme--documenter-dark .is-dark.is-focused.textarea,html.theme--documenter-dark .content kbd.is-focused.textarea,html.theme--documenter-dark .is-dark.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .content kbd.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-focused,html.theme--documenter-dark .is-dark.textarea:active,html.theme--documenter-dark .content kbd.textarea:active,html.theme--documenter-dark .is-dark.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:active,html.theme--documenter-dark .content kbd.input:active,html.theme--documenter-dark .is-dark.is-active.textarea,html.theme--documenter-dark .content kbd.is-active.textarea,html.theme--documenter-dark .is-dark.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .content kbd.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .is-primary.textarea,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink{border-color:#375a7f}html.theme--documenter-dark .is-primary.textarea:focus,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:focus,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.is-focused.textarea,html.theme--documenter-dark .docstring>section>a.is-focused.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .docstring>section>a.is-focused.input.docs-sourcelink,html.theme--documenter-dark .is-primary.textarea:active,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:active,html.theme--documenter-dark .is-primary.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:active,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:active,html.theme--documenter-dark .is-primary.is-active.textarea,html.theme--documenter-dark .docstring>section>a.is-active.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .docstring>section>a.is-active.input.docs-sourcelink{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .is-link.textarea,html.theme--documenter-dark .is-link.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link{border-color:#1abc9c}html.theme--documenter-dark .is-link.textarea:focus,html.theme--documenter-dark .is-link.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:focus,html.theme--documenter-dark .is-link.is-focused.textarea,html.theme--documenter-dark .is-link.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-link.textarea:active,html.theme--documenter-dark .is-link.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:active,html.theme--documenter-dark .is-link.is-active.textarea,html.theme--documenter-dark .is-link.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .is-info.textarea,html.theme--documenter-dark .is-info.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info{border-color:#024c7d}html.theme--documenter-dark .is-info.textarea:focus,html.theme--documenter-dark .is-info.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:focus,html.theme--documenter-dark .is-info.is-focused.textarea,html.theme--documenter-dark .is-info.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-info.textarea:active,html.theme--documenter-dark .is-info.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:active,html.theme--documenter-dark .is-info.is-active.textarea,html.theme--documenter-dark .is-info.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .is-success.textarea,html.theme--documenter-dark .is-success.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success{border-color:#008438}html.theme--documenter-dark .is-success.textarea:focus,html.theme--documenter-dark .is-success.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:focus,html.theme--documenter-dark .is-success.is-focused.textarea,html.theme--documenter-dark .is-success.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-success.textarea:active,html.theme--documenter-dark .is-success.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:active,html.theme--documenter-dark .is-success.is-active.textarea,html.theme--documenter-dark .is-success.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .is-warning.textarea,html.theme--documenter-dark .is-warning.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning{border-color:#ad8100}html.theme--documenter-dark .is-warning.textarea:focus,html.theme--documenter-dark .is-warning.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:focus,html.theme--documenter-dark .is-warning.is-focused.textarea,html.theme--documenter-dark .is-warning.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-warning.textarea:active,html.theme--documenter-dark .is-warning.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:active,html.theme--documenter-dark .is-warning.is-active.textarea,html.theme--documenter-dark .is-warning.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .is-danger.textarea,html.theme--documenter-dark .is-danger.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger{border-color:#9e1b0d}html.theme--documenter-dark .is-danger.textarea:focus,html.theme--documenter-dark .is-danger.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:focus,html.theme--documenter-dark .is-danger.is-focused.textarea,html.theme--documenter-dark .is-danger.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-danger.textarea:active,html.theme--documenter-dark .is-danger.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:active,html.theme--documenter-dark .is-danger.is-active.textarea,html.theme--documenter-dark .is-danger.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .is-small.textarea,html.theme--documenter-dark .is-small.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:3px;font-size:.85em}html.theme--documenter-dark .is-medium.textarea,html.theme--documenter-dark .is-medium.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-medium{font-size:1.25rem}html.theme--documenter-dark .is-large.textarea,html.theme--documenter-dark .is-large.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-large{font-size:1.5rem}html.theme--documenter-dark .is-fullwidth.textarea,html.theme--documenter-dark .is-fullwidth.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-fullwidth{display:block;width:100%}html.theme--documenter-dark .is-inline.textarea,html.theme--documenter-dark .is-inline.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-inline{display:inline;width:auto}html.theme--documenter-dark .input.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:290486px;padding-left:1em;padding-right:1em}html.theme--documenter-dark .input.is-static,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}html.theme--documenter-dark .textarea{display:block;max-width:100%;min-width:100%;padding:0.625em;resize:vertical}html.theme--documenter-dark .textarea:not([rows]){max-height:600px;min-height:120px}html.theme--documenter-dark .textarea[rows]{height:initial}html.theme--documenter-dark .textarea.has-fixed-size{resize:none}html.theme--documenter-dark .radio,html.theme--documenter-dark .checkbox{cursor:pointer;display:inline-block;line-height:1.25;position:relative}html.theme--documenter-dark .radio input,html.theme--documenter-dark .checkbox input{cursor:pointer}html.theme--documenter-dark .radio:hover,html.theme--documenter-dark .checkbox:hover{color:#8c9b9d}html.theme--documenter-dark .radio[disabled],html.theme--documenter-dark .checkbox[disabled],fieldset[disabled] html.theme--documenter-dark .radio,fieldset[disabled] html.theme--documenter-dark .checkbox{color:#fff;cursor:not-allowed}html.theme--documenter-dark .radio+.radio{margin-left:0.5em}html.theme--documenter-dark .select{display:inline-block;max-width:100%;position:relative;vertical-align:top}html.theme--documenter-dark .select:not(.is-multiple){height:2.25em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading)::after{border-color:#1abc9c;right:1.125em;z-index:4}html.theme--documenter-dark .select.is-rounded select,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select select{border-radius:290486px;padding-left:1em}html.theme--documenter-dark .select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:none}html.theme--documenter-dark .select select::-ms-expand{display:none}html.theme--documenter-dark .select select[disabled]:hover,fieldset[disabled] html.theme--documenter-dark .select select:hover{border-color:#282f2f}html.theme--documenter-dark .select select:not([multiple]){padding-right:2.5em}html.theme--documenter-dark .select select[multiple]{height:auto;padding:0}html.theme--documenter-dark .select select[multiple] option{padding:0.5em 1em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading):hover::after{border-color:#8c9b9d}html.theme--documenter-dark .select.is-white:not(:hover)::after{border-color:#fff}html.theme--documenter-dark .select.is-white select{border-color:#fff}html.theme--documenter-dark .select.is-white select:hover,html.theme--documenter-dark .select.is-white select.is-hovered{border-color:#f2f2f2}html.theme--documenter-dark .select.is-white select:focus,html.theme--documenter-dark .select.is-white select.is-focused,html.theme--documenter-dark .select.is-white select:active,html.theme--documenter-dark .select.is-white select.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .select.is-black:not(:hover)::after{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select:hover,html.theme--documenter-dark .select.is-black select.is-hovered{border-color:#000}html.theme--documenter-dark .select.is-black select:focus,html.theme--documenter-dark .select.is-black select.is-focused,html.theme--documenter-dark .select.is-black select:active,html.theme--documenter-dark .select.is-black select.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .select.is-light:not(:hover)::after{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select:hover,html.theme--documenter-dark .select.is-light select.is-hovered{border-color:#dde4e6}html.theme--documenter-dark .select.is-light select:focus,html.theme--documenter-dark .select.is-light select.is-focused,html.theme--documenter-dark .select.is-light select:active,html.theme--documenter-dark .select.is-light select.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .select.is-dark:not(:hover)::after,html.theme--documenter-dark .content kbd.select:not(:hover)::after{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select,html.theme--documenter-dark .content kbd.select select{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select:hover,html.theme--documenter-dark .content kbd.select select:hover,html.theme--documenter-dark .select.is-dark select.is-hovered,html.theme--documenter-dark .content kbd.select select.is-hovered{border-color:#1d2122}html.theme--documenter-dark .select.is-dark select:focus,html.theme--documenter-dark .content kbd.select select:focus,html.theme--documenter-dark .select.is-dark select.is-focused,html.theme--documenter-dark .content kbd.select select.is-focused,html.theme--documenter-dark .select.is-dark select:active,html.theme--documenter-dark .content kbd.select select:active,html.theme--documenter-dark .select.is-dark select.is-active,html.theme--documenter-dark .content kbd.select select.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .select.is-primary:not(:hover)::after,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink:not(:hover)::after{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select:hover,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:hover,html.theme--documenter-dark .select.is-primary select.is-hovered,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-hovered{border-color:#2f4d6d}html.theme--documenter-dark .select.is-primary select:focus,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:focus,html.theme--documenter-dark .select.is-primary select.is-focused,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-focused,html.theme--documenter-dark .select.is-primary select:active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:active,html.theme--documenter-dark .select.is-primary select.is-active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-active{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .select.is-link:not(:hover)::after{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select:hover,html.theme--documenter-dark .select.is-link select.is-hovered{border-color:#17a689}html.theme--documenter-dark .select.is-link select:focus,html.theme--documenter-dark .select.is-link select.is-focused,html.theme--documenter-dark .select.is-link select:active,html.theme--documenter-dark .select.is-link select.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select.is-info:not(:hover)::after{border-color:#024c7d}html.theme--documenter-dark .select.is-info select{border-color:#024c7d}html.theme--documenter-dark .select.is-info select:hover,html.theme--documenter-dark .select.is-info select.is-hovered{border-color:#023d64}html.theme--documenter-dark .select.is-info select:focus,html.theme--documenter-dark .select.is-info select.is-focused,html.theme--documenter-dark .select.is-info select:active,html.theme--documenter-dark .select.is-info select.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .select.is-success:not(:hover)::after{border-color:#008438}html.theme--documenter-dark .select.is-success select{border-color:#008438}html.theme--documenter-dark .select.is-success select:hover,html.theme--documenter-dark .select.is-success select.is-hovered{border-color:#006b2d}html.theme--documenter-dark .select.is-success select:focus,html.theme--documenter-dark .select.is-success select.is-focused,html.theme--documenter-dark .select.is-success select:active,html.theme--documenter-dark .select.is-success select.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .select.is-warning:not(:hover)::after{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select:hover,html.theme--documenter-dark .select.is-warning select.is-hovered{border-color:#946e00}html.theme--documenter-dark .select.is-warning select:focus,html.theme--documenter-dark .select.is-warning select.is-focused,html.theme--documenter-dark .select.is-warning select:active,html.theme--documenter-dark .select.is-warning select.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .select.is-danger:not(:hover)::after{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select:hover,html.theme--documenter-dark .select.is-danger select.is-hovered{border-color:#86170b}html.theme--documenter-dark .select.is-danger select:focus,html.theme--documenter-dark .select.is-danger select.is-focused,html.theme--documenter-dark .select.is-danger select:active,html.theme--documenter-dark .select.is-danger select.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .select.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select{border-radius:3px;font-size:.85em}html.theme--documenter-dark .select.is-medium{font-size:1.25rem}html.theme--documenter-dark .select.is-large{font-size:1.5rem}html.theme--documenter-dark .select.is-disabled::after{border-color:#fff}html.theme--documenter-dark .select.is-fullwidth{width:100%}html.theme--documenter-dark .select.is-fullwidth select{width:100%}html.theme--documenter-dark .select.is-loading::after{margin-top:0;position:absolute;right:0.625em;top:0.625em;transform:none}html.theme--documenter-dark .select.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.85em}html.theme--documenter-dark .select.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .select.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}html.theme--documenter-dark .file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:hover .file-cta,html.theme--documenter-dark .file.is-white.is-hovered .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:focus .file-cta,html.theme--documenter-dark .file.is-white.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,255,255,0.25);color:#0a0a0a}html.theme--documenter-dark .file.is-white:active .file-cta,html.theme--documenter-dark .file.is-white.is-active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:hover .file-cta,html.theme--documenter-dark .file.is-black.is-hovered .file-cta{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:focus .file-cta,html.theme--documenter-dark .file.is-black.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(10,10,10,0.25);color:#fff}html.theme--documenter-dark .file.is-black:active .file-cta,html.theme--documenter-dark .file.is-black.is-active .file-cta{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-light .file-cta{background-color:#ecf0f1;border-color:transparent;color:#282f2f}html.theme--documenter-dark .file.is-light:hover .file-cta,html.theme--documenter-dark .file.is-light.is-hovered .file-cta{background-color:#e5eaec;border-color:transparent;color:#282f2f}html.theme--documenter-dark .file.is-light:focus .file-cta,html.theme--documenter-dark .file.is-light.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(236,240,241,0.25);color:#282f2f}html.theme--documenter-dark .file.is-light:active .file-cta,html.theme--documenter-dark .file.is-light.is-active .file-cta{background-color:#dde4e6;border-color:transparent;color:#282f2f}html.theme--documenter-dark .file.is-dark .file-cta,html.theme--documenter-dark .content kbd.file .file-cta{background-color:#282f2f;border-color:transparent;color:#ecf0f1}html.theme--documenter-dark .file.is-dark:hover .file-cta,html.theme--documenter-dark .content kbd.file:hover .file-cta,html.theme--documenter-dark .file.is-dark.is-hovered .file-cta,html.theme--documenter-dark .content kbd.file.is-hovered .file-cta{background-color:#232829;border-color:transparent;color:#ecf0f1}html.theme--documenter-dark .file.is-dark:focus .file-cta,html.theme--documenter-dark .content kbd.file:focus .file-cta,html.theme--documenter-dark .file.is-dark.is-focused .file-cta,html.theme--documenter-dark .content kbd.file.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(40,47,47,0.25);color:#ecf0f1}html.theme--documenter-dark .file.is-dark:active .file-cta,html.theme--documenter-dark .content kbd.file:active .file-cta,html.theme--documenter-dark .file.is-dark.is-active .file-cta,html.theme--documenter-dark .content kbd.file.is-active .file-cta{background-color:#1d2122;border-color:transparent;color:#ecf0f1}html.theme--documenter-dark .file.is-primary .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink .file-cta{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:hover .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:hover .file-cta,html.theme--documenter-dark .file.is-primary.is-hovered .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-hovered.docs-sourcelink .file-cta{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:focus .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:focus .file-cta,html.theme--documenter-dark .file.is-primary.is-focused .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-focused.docs-sourcelink .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(55,90,127,0.25);color:#fff}html.theme--documenter-dark .file.is-primary:active .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:active .file-cta,html.theme--documenter-dark .file.is-primary.is-active .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-active.docs-sourcelink .file-cta{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link .file-cta{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:hover .file-cta,html.theme--documenter-dark .file.is-link.is-hovered .file-cta{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:focus .file-cta,html.theme--documenter-dark .file.is-link.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(26,188,156,0.25);color:#fff}html.theme--documenter-dark .file.is-link:active .file-cta,html.theme--documenter-dark .file.is-link.is-active .file-cta{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info .file-cta{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:hover .file-cta,html.theme--documenter-dark .file.is-info.is-hovered .file-cta{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:focus .file-cta,html.theme--documenter-dark .file.is-info.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(2,76,125,0.25);color:#fff}html.theme--documenter-dark .file.is-info:active .file-cta,html.theme--documenter-dark .file.is-info.is-active .file-cta{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success .file-cta{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:hover .file-cta,html.theme--documenter-dark .file.is-success.is-hovered .file-cta{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:focus .file-cta,html.theme--documenter-dark .file.is-success.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(0,132,56,0.25);color:#fff}html.theme--documenter-dark .file.is-success:active .file-cta,html.theme--documenter-dark .file.is-success.is-active .file-cta{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning .file-cta{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:hover .file-cta,html.theme--documenter-dark .file.is-warning.is-hovered .file-cta{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:focus .file-cta,html.theme--documenter-dark .file.is-warning.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(173,129,0,0.25);color:#fff}html.theme--documenter-dark .file.is-warning:active .file-cta,html.theme--documenter-dark .file.is-warning.is-active .file-cta{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger .file-cta{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:hover .file-cta,html.theme--documenter-dark .file.is-danger.is-hovered .file-cta{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:focus .file-cta,html.theme--documenter-dark .file.is-danger.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(158,27,13,0.25);color:#fff}html.theme--documenter-dark .file.is-danger:active .file-cta,html.theme--documenter-dark .file.is-danger.is-active .file-cta{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.file{font-size:.85em}html.theme--documenter-dark .file.is-medium{font-size:1.25rem}html.theme--documenter-dark .file.is-medium .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-large{font-size:1.5rem}html.theme--documenter-dark .file.is-large .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .file.has-name.is-empty .file-cta{border-radius:.4em}html.theme--documenter-dark .file.has-name.is-empty .file-name{display:none}html.theme--documenter-dark .file.is-boxed .file-label{flex-direction:column}html.theme--documenter-dark .file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}html.theme--documenter-dark .file.is-boxed .file-name{border-width:0 1px 1px}html.theme--documenter-dark .file.is-boxed .file-icon{height:1.5em;width:1.5em}html.theme--documenter-dark .file.is-boxed .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-boxed.is-small .file-icon .fa,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-boxed .file-icon .fa{font-size:14px}html.theme--documenter-dark .file.is-boxed.is-medium .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.is-boxed.is-large .file-icon .fa{font-size:35px}html.theme--documenter-dark .file.is-boxed.has-name .file-cta{border-radius:.4em .4em 0 0}html.theme--documenter-dark .file.is-boxed.has-name .file-name{border-radius:0 0 .4em .4em;border-width:0 1px 1px}html.theme--documenter-dark .file.is-centered{justify-content:center}html.theme--documenter-dark .file.is-fullwidth .file-label{width:100%}html.theme--documenter-dark .file.is-fullwidth .file-name{flex-grow:1;max-width:none}html.theme--documenter-dark .file.is-right{justify-content:flex-end}html.theme--documenter-dark .file.is-right .file-cta{border-radius:0 .4em .4em 0}html.theme--documenter-dark .file.is-right .file-name{border-radius:.4em 0 0 .4em;border-width:1px 0 1px 1px;order:-1}html.theme--documenter-dark .file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}html.theme--documenter-dark .file-label:hover .file-cta{background-color:#e5eaec;color:#282f2f}html.theme--documenter-dark .file-label:hover .file-name{border-color:#596668}html.theme--documenter-dark .file-label:active .file-cta{background-color:#dde4e6;color:#282f2f}html.theme--documenter-dark .file-label:active .file-name{border-color:#535f61}html.theme--documenter-dark .file-input{height:100%;left:0;opacity:0;outline:none;position:absolute;top:0;width:100%}html.theme--documenter-dark .file-cta,html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-radius:.4em;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}html.theme--documenter-dark .file-cta{background-color:#ecf0f1;color:#343c3d}html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:left;text-overflow:ellipsis}html.theme--documenter-dark .file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:0.5em;width:1em}html.theme--documenter-dark .file-icon .fa{font-size:14px}html.theme--documenter-dark .label{color:#282f2f;display:block;font-size:15px;font-weight:700}html.theme--documenter-dark .label:not(:last-child){margin-bottom:0.5em}html.theme--documenter-dark .label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.label{font-size:.85em}html.theme--documenter-dark .label.is-medium{font-size:1.25rem}html.theme--documenter-dark .label.is-large{font-size:1.5rem}html.theme--documenter-dark .help{display:block;font-size:.85em;margin-top:0.25rem}html.theme--documenter-dark .help.is-white{color:#fff}html.theme--documenter-dark .help.is-black{color:#0a0a0a}html.theme--documenter-dark .help.is-light{color:#ecf0f1}html.theme--documenter-dark .help.is-dark,html.theme--documenter-dark .content kbd.help{color:#282f2f}html.theme--documenter-dark .help.is-primary,html.theme--documenter-dark .docstring>section>a.help.docs-sourcelink{color:#375a7f}html.theme--documenter-dark .help.is-link{color:#1abc9c}html.theme--documenter-dark .help.is-info{color:#024c7d}html.theme--documenter-dark .help.is-success{color:#008438}html.theme--documenter-dark .help.is-warning{color:#ad8100}html.theme--documenter-dark .help.is-danger{color:#9e1b0d}html.theme--documenter-dark .field:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.has-addons{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.has-addons .control:not(:last-child){margin-right:-1px}html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .button,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:not(:first-child):not(:last-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:first-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:last-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select.is-hovered:not([disabled]){z-index:2}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]){z-index:3}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]):hover{z-index:4}html.theme--documenter-dark .field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.has-addons.has-addons-centered{justify-content:center}html.theme--documenter-dark .field.has-addons.has-addons-right{justify-content:flex-end}html.theme--documenter-dark .field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .field.is-grouped{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.is-grouped>.control{flex-shrink:0}html.theme--documenter-dark .field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:0.75rem}html.theme--documenter-dark .field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.is-grouped.is-grouped-centered{justify-content:center}html.theme--documenter-dark .field.is-grouped.is-grouped-right{justify-content:flex-end}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline{flex-wrap:wrap}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:last-child,html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field.is-horizontal{display:flex}}html.theme--documenter-dark .field-label .label{font-size:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .field-label{margin-bottom:0.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}html.theme--documenter-dark .field-label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.field-label{font-size:.85em;padding-top:0.375em}html.theme--documenter-dark .field-label.is-normal{padding-top:0.375em}html.theme--documenter-dark .field-label.is-medium{font-size:1.25rem;padding-top:0.375em}html.theme--documenter-dark .field-label.is-large{font-size:1.5rem;padding-top:0.375em}}html.theme--documenter-dark .field-body .field .field{margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}html.theme--documenter-dark .field-body .field{margin-bottom:0}html.theme--documenter-dark .field-body>.field{flex-shrink:1}html.theme--documenter-dark .field-body>.field:not(.is-narrow){flex-grow:1}html.theme--documenter-dark .field-body>.field:not(:last-child){margin-right:0.75rem}}html.theme--documenter-dark .control{box-sizing:border-box;clear:both;font-size:15px;position:relative;text-align:left}html.theme--documenter-dark .control.has-icons-left .input:focus~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-left .select:focus~.icon,html.theme--documenter-dark .control.has-icons-right .input:focus~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-right .select:focus~.icon{color:#5e6d6f}html.theme--documenter-dark .control.has-icons-left .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-small~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-small~.icon{font-size:.85em}html.theme--documenter-dark .control.has-icons-left .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}html.theme--documenter-dark .control.has-icons-left .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-large~.icon{font-size:1.5rem}html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon{color:#dbdee0;height:2.25em;pointer-events:none;position:absolute;top:0;width:2.25em;z-index:4}html.theme--documenter-dark .control.has-icons-left .input,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input,html.theme--documenter-dark .control.has-icons-left .select select{padding-left:2.25em}html.theme--documenter-dark .control.has-icons-left .icon.is-left{left:0}html.theme--documenter-dark .control.has-icons-right .input,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input,html.theme--documenter-dark .control.has-icons-right .select select{padding-right:2.25em}html.theme--documenter-dark .control.has-icons-right .icon.is-right{right:0}html.theme--documenter-dark .control.is-loading::after{position:absolute !important;right:0.625em;top:0.625em;z-index:4}html.theme--documenter-dark .control.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.85em}html.theme--documenter-dark .control.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .control.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .breadcrumb{font-size:15px;white-space:nowrap}html.theme--documenter-dark .breadcrumb a{align-items:center;color:#1abc9c;display:flex;justify-content:center;padding:0 .75em}html.theme--documenter-dark .breadcrumb a:hover{color:#1dd2af}html.theme--documenter-dark .breadcrumb li{align-items:center;display:flex}html.theme--documenter-dark .breadcrumb li:first-child a{padding-left:0}html.theme--documenter-dark .breadcrumb li.is-active a{color:#f2f2f2;cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb li+li::before{color:#8c9b9d;content:"\0002f"}html.theme--documenter-dark .breadcrumb ul,html.theme--documenter-dark .breadcrumb ol{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .breadcrumb .icon:first-child{margin-right:0.5em}html.theme--documenter-dark .breadcrumb .icon:last-child{margin-left:0.5em}html.theme--documenter-dark .breadcrumb.is-centered ol,html.theme--documenter-dark .breadcrumb.is-centered ul{justify-content:center}html.theme--documenter-dark .breadcrumb.is-right ol,html.theme--documenter-dark .breadcrumb.is-right ul{justify-content:flex-end}html.theme--documenter-dark .breadcrumb.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.breadcrumb{font-size:.85em}html.theme--documenter-dark .breadcrumb.is-medium{font-size:1.25rem}html.theme--documenter-dark .breadcrumb.is-large{font-size:1.5rem}html.theme--documenter-dark .breadcrumb.has-arrow-separator li+li::before{content:"\02192"}html.theme--documenter-dark .breadcrumb.has-bullet-separator li+li::before{content:"\02022"}html.theme--documenter-dark .breadcrumb.has-dot-separator li+li::before{content:"\000b7"}html.theme--documenter-dark .breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}html.theme--documenter-dark .card{background-color:#fff;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1);color:#fff;max-width:100%;position:relative}html.theme--documenter-dark .card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 1px 2px rgba(10,10,10,0.1);display:flex}html.theme--documenter-dark .card-header-title{align-items:center;color:#f2f2f2;display:flex;flex-grow:1;font-weight:700;padding:.75rem}html.theme--documenter-dark .card-header-title.is-centered{justify-content:center}html.theme--documenter-dark .card-header-icon{align-items:center;cursor:pointer;display:flex;justify-content:center;padding:.75rem}html.theme--documenter-dark .card-image{display:block;position:relative}html.theme--documenter-dark .card-content{background-color:rgba(0,0,0,0);padding:1.5rem}html.theme--documenter-dark .card-footer{background-color:rgba(0,0,0,0);border-top:1px solid #5e6d6f;align-items:stretch;display:flex}html.theme--documenter-dark .card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}html.theme--documenter-dark .card-footer-item:not(:last-child){border-right:1px solid #5e6d6f}html.theme--documenter-dark .card .media:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .dropdown{display:inline-flex;position:relative;vertical-align:top}html.theme--documenter-dark .dropdown.is-active .dropdown-menu,html.theme--documenter-dark .dropdown.is-hoverable:hover .dropdown-menu{display:block}html.theme--documenter-dark .dropdown.is-right .dropdown-menu{left:auto;right:0}html.theme--documenter-dark .dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}html.theme--documenter-dark .dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .dropdown-content{background-color:#282f2f;border-radius:.4em;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1);padding-bottom:.5rem;padding-top:.5rem}html.theme--documenter-dark .dropdown-item{color:#fff;display:block;font-size:0.875rem;line-height:1.5;padding:0.375rem 1rem;position:relative}html.theme--documenter-dark a.dropdown-item,html.theme--documenter-dark button.dropdown-item{padding-right:3rem;text-align:left;white-space:nowrap;width:100%}html.theme--documenter-dark a.dropdown-item:hover,html.theme--documenter-dark button.dropdown-item:hover{background-color:#282f2f;color:#0a0a0a}html.theme--documenter-dark a.dropdown-item.is-active,html.theme--documenter-dark button.dropdown-item.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .dropdown-divider{background-color:#5e6d6f;border:none;display:block;height:1px;margin:0.5rem 0}html.theme--documenter-dark .level{align-items:center;justify-content:space-between}html.theme--documenter-dark .level code{border-radius:.4em}html.theme--documenter-dark .level img{display:inline-block;vertical-align:top}html.theme--documenter-dark .level.is-mobile{display:flex}html.theme--documenter-dark .level.is-mobile .level-left,html.theme--documenter-dark .level.is-mobile .level-right{display:flex}html.theme--documenter-dark .level.is-mobile .level-left+.level-right{margin-top:0}html.theme--documenter-dark .level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}html.theme--documenter-dark .level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level{display:flex}html.theme--documenter-dark .level>.level-item:not(.is-narrow){flex-grow:1}}html.theme--documenter-dark .level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}html.theme--documenter-dark .level-item .title,html.theme--documenter-dark .level-item .subtitle{margin-bottom:0}@media screen and (max-width: 768px){html.theme--documenter-dark .level-item:not(:last-child){margin-bottom:.75rem}}html.theme--documenter-dark .level-left,html.theme--documenter-dark .level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .level-left .level-item.is-flexible,html.theme--documenter-dark .level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left .level-item:not(:last-child),html.theme--documenter-dark .level-right .level-item:not(:last-child){margin-right:.75rem}}html.theme--documenter-dark .level-left{align-items:center;justify-content:flex-start}@media screen and (max-width: 768px){html.theme--documenter-dark .level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left{display:flex}}html.theme--documenter-dark .level-right{align-items:center;justify-content:flex-end}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-right{display:flex}}html.theme--documenter-dark .list{background-color:#fff;border-radius:.4em;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1)}html.theme--documenter-dark .list-item{display:block;padding:0.5em 1em}html.theme--documenter-dark .list-item:not(a){color:#fff}html.theme--documenter-dark .list-item:first-child{border-top-left-radius:.4em;border-top-right-radius:.4em}html.theme--documenter-dark .list-item:last-child{border-bottom-left-radius:.4em;border-bottom-right-radius:.4em}html.theme--documenter-dark .list-item:not(:last-child){border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .list-item.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark a.list-item{background-color:#282f2f;cursor:pointer}html.theme--documenter-dark .media{align-items:flex-start;display:flex;text-align:left}html.theme--documenter-dark .media .content:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .media .media{border-top:1px solid rgba(94,109,111,0.5);display:flex;padding-top:0.75rem}html.theme--documenter-dark .media .media .content:not(:last-child),html.theme--documenter-dark .media .media .control:not(:last-child){margin-bottom:0.5rem}html.theme--documenter-dark .media .media .media{padding-top:0.5rem}html.theme--documenter-dark .media .media .media+.media{margin-top:0.5rem}html.theme--documenter-dark .media+.media{border-top:1px solid rgba(94,109,111,0.5);margin-top:1rem;padding-top:1rem}html.theme--documenter-dark .media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}html.theme--documenter-dark .media-left,html.theme--documenter-dark .media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .media-left{margin-right:1rem}html.theme--documenter-dark .media-right{margin-left:1rem}html.theme--documenter-dark .media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:left}@media screen and (max-width: 768px){html.theme--documenter-dark .media-content{overflow-x:auto}}html.theme--documenter-dark .menu{font-size:15px}html.theme--documenter-dark .menu.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.menu{font-size:.85em}html.theme--documenter-dark .menu.is-medium{font-size:1.25rem}html.theme--documenter-dark .menu.is-large{font-size:1.5rem}html.theme--documenter-dark .menu-list{line-height:1.25}html.theme--documenter-dark .menu-list a{border-radius:3px;color:#fff;display:block;padding:0.5em 0.75em}html.theme--documenter-dark .menu-list a:hover{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .menu-list a.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .menu-list li ul{border-left:1px solid #5e6d6f;margin:.75em;padding-left:.75em}html.theme--documenter-dark .menu-label{color:#fff;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}html.theme--documenter-dark .menu-label:not(:first-child){margin-top:1em}html.theme--documenter-dark .menu-label:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .message{background-color:#282f2f;border-radius:.4em;font-size:15px}html.theme--documenter-dark .message strong{color:currentColor}html.theme--documenter-dark .message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .message.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.message{font-size:.85em}html.theme--documenter-dark .message.is-medium{font-size:1.25rem}html.theme--documenter-dark .message.is-large{font-size:1.5rem}html.theme--documenter-dark .message.is-white{background-color:#fff}html.theme--documenter-dark .message.is-white .message-header{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .message.is-white .message-body{border-color:#fff;color:#4d4d4d}html.theme--documenter-dark .message.is-black{background-color:#fafafa}html.theme--documenter-dark .message.is-black .message-header{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .message.is-black .message-body{border-color:#0a0a0a;color:#090909}html.theme--documenter-dark .message.is-light{background-color:#f9fafb}html.theme--documenter-dark .message.is-light .message-header{background-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .message.is-light .message-body{border-color:#ecf0f1;color:#505050}html.theme--documenter-dark .message.is-dark,html.theme--documenter-dark .content kbd.message{background-color:#f9fafa}html.theme--documenter-dark .message.is-dark .message-header,html.theme--documenter-dark .content kbd.message .message-header{background-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .message.is-dark .message-body,html.theme--documenter-dark .content kbd.message .message-body{border-color:#282f2f;color:#212526}html.theme--documenter-dark .message.is-primary,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink{background-color:#f8fafc}html.theme--documenter-dark .message.is-primary .message-header,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-header{background-color:#375a7f;color:#fff}html.theme--documenter-dark .message.is-primary .message-body,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-body{border-color:#375a7f;color:#2b4159}html.theme--documenter-dark .message.is-link{background-color:#f6fefc}html.theme--documenter-dark .message.is-link .message-header{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .message.is-link .message-body{border-color:#1abc9c;color:#0b2f28}html.theme--documenter-dark .message.is-info{background-color:#f5fbff}html.theme--documenter-dark .message.is-info .message-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .message.is-info .message-body{border-color:#024c7d;color:#033659}html.theme--documenter-dark .message.is-success{background-color:#f5fff9}html.theme--documenter-dark .message.is-success .message-header{background-color:#008438;color:#fff}html.theme--documenter-dark .message.is-success .message-body{border-color:#008438;color:#023518}html.theme--documenter-dark .message.is-warning{background-color:#fffcf5}html.theme--documenter-dark .message.is-warning .message-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .message.is-warning .message-body{border-color:#ad8100;color:#3d2e03}html.theme--documenter-dark .message.is-danger{background-color:#fef6f6}html.theme--documenter-dark .message.is-danger .message-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .message.is-danger .message-body{border-color:#9e1b0d;color:#7a170c}html.theme--documenter-dark .message-header{align-items:center;background-color:#fff;border-radius:.4em .4em 0 0;color:rgba(0,0,0,0.7);display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.75em 1em;position:relative}html.theme--documenter-dark .message-header .delete{flex-grow:0;flex-shrink:0;margin-left:0.75em}html.theme--documenter-dark .message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}html.theme--documenter-dark .message-body{border-color:#5e6d6f;border-radius:.4em;border-style:solid;border-width:0 0 0 4px;color:#fff;padding:1.25em 1.5em}html.theme--documenter-dark .message-body code,html.theme--documenter-dark .message-body pre{background-color:#fff}html.theme--documenter-dark .message-body pre code{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}html.theme--documenter-dark .modal.is-active{display:flex}html.theme--documenter-dark .modal-background{background-color:rgba(10,10,10,0.86)}html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width: 769px),print{html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}html.theme--documenter-dark .modal-close{background:none;height:40px;position:fixed;right:20px;top:20px;width:40px}html.theme--documenter-dark .modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}html.theme--documenter-dark .modal-card-head,html.theme--documenter-dark .modal-card-foot{align-items:center;background-color:#282f2f;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}html.theme--documenter-dark .modal-card-head{border-bottom:1px solid #5e6d6f;border-top-left-radius:8px;border-top-right-radius:8px}html.theme--documenter-dark .modal-card-title{color:#f2f2f2;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}html.theme--documenter-dark .modal-card-foot{border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid #5e6d6f}html.theme--documenter-dark .modal-card-foot .button:not(:last-child){margin-right:0.5em}html.theme--documenter-dark .modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}html.theme--documenter-dark .navbar{background-color:#375a7f;min-height:4rem;position:relative;z-index:30}html.theme--documenter-dark .navbar.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-white .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}html.theme--documenter-dark .navbar.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-black .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}html.theme--documenter-dark .navbar.is-light{background-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .navbar.is-light .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link{color:#282f2f}html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link.is-active{background-color:#dde4e6;color:#282f2f}html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link::after{border-color:#282f2f}html.theme--documenter-dark .navbar.is-light .navbar-burger{color:#282f2f}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-light .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link{color:#282f2f}html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link.is-active{background-color:#dde4e6;color:#282f2f}html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link::after{border-color:#282f2f}html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link{background-color:#dde4e6;color:#282f2f}html.theme--documenter-dark .navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#ecf0f1;color:#282f2f}}html.theme--documenter-dark .navbar.is-dark,html.theme--documenter-dark .content kbd.navbar{background-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .navbar.is-dark .navbar-brand>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link{color:#ecf0f1}html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link.is-active{background-color:#1d2122;color:#ecf0f1}html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link::after{border-color:#ecf0f1}html.theme--documenter-dark .navbar.is-dark .navbar-burger,html.theme--documenter-dark .content kbd.navbar .navbar-burger{color:#ecf0f1}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-dark .navbar-start>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-end>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link{color:#ecf0f1}html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link.is-active{background-color:#1d2122;color:#ecf0f1}html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link::after{border-color:#ecf0f1}html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1d2122;color:#ecf0f1}html.theme--documenter-dark .navbar.is-dark .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-dropdown a.navbar-item.is-active{background-color:#282f2f;color:#ecf0f1}}html.theme--documenter-dark .navbar.is-primary,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-burger,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-primary .navbar-start>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-end>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown.is-active .navbar-link{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#375a7f;color:#fff}}html.theme--documenter-dark .navbar.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-link .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c;color:#fff}}html.theme--documenter-dark .navbar.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-info .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#024c7d;color:#fff}}html.theme--documenter-dark .navbar.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-success .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#008438;color:#fff}}html.theme--documenter-dark .navbar.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-warning .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ad8100;color:#fff}}html.theme--documenter-dark .navbar.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-danger .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#9e1b0d;color:#fff}}html.theme--documenter-dark .navbar>.container{align-items:stretch;display:flex;min-height:4rem;width:100%}html.theme--documenter-dark .navbar.has-shadow{box-shadow:0 2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-bottom,html.theme--documenter-dark .navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-top{top:0}html.theme--documenter-dark html.has-navbar-fixed-top,html.theme--documenter-dark body.has-navbar-fixed-top{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom,html.theme--documenter-dark body.has-navbar-fixed-bottom{padding-bottom:4rem}html.theme--documenter-dark .navbar-brand,html.theme--documenter-dark .navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:4rem}html.theme--documenter-dark .navbar-brand a.navbar-item:focus,html.theme--documenter-dark .navbar-brand a.navbar-item:hover{background-color:transparent}html.theme--documenter-dark .navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}html.theme--documenter-dark .navbar-burger{color:#fff;cursor:pointer;display:block;height:4rem;position:relative;width:4rem;margin-left:auto}html.theme--documenter-dark .navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color, opacity, transform;transition-timing-function:ease-out;width:16px}html.theme--documenter-dark .navbar-burger span:nth-child(1){top:calc(50% - 6px)}html.theme--documenter-dark .navbar-burger span:nth-child(2){top:calc(50% - 1px)}html.theme--documenter-dark .navbar-burger span:nth-child(3){top:calc(50% + 4px)}html.theme--documenter-dark .navbar-burger:hover{background-color:rgba(0,0,0,0.05)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(2){opacity:0}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}html.theme--documenter-dark .navbar-menu{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{color:#fff;display:block;line-height:1.5;padding:0.5rem 0.75rem;position:relative}html.theme--documenter-dark .navbar-item .icon:only-child,html.theme--documenter-dark .navbar-link .icon:only-child{margin-left:-0.25rem;margin-right:-0.25rem}html.theme--documenter-dark a.navbar-item,html.theme--documenter-dark .navbar-link{cursor:pointer}html.theme--documenter-dark a.navbar-item:focus,html.theme--documenter-dark a.navbar-item:focus-within,html.theme--documenter-dark a.navbar-item:hover,html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link:focus,html.theme--documenter-dark .navbar-link:focus-within,html.theme--documenter-dark .navbar-link:hover,html.theme--documenter-dark .navbar-link.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-item{display:block;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .navbar-item img{max-height:1.75rem}html.theme--documenter-dark .navbar-item.has-dropdown{padding:0}html.theme--documenter-dark .navbar-item.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-item.is-tab{border-bottom:1px solid transparent;min-height:4rem;padding-bottom:calc(0.5rem - 1px)}html.theme--documenter-dark .navbar-item.is-tab:focus,html.theme--documenter-dark .navbar-item.is-tab:hover{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c}html.theme--documenter-dark .navbar-item.is-tab.is-active{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c;border-bottom-style:solid;border-bottom-width:3px;color:#1abc9c;padding-bottom:calc(0.5rem - 3px)}html.theme--documenter-dark .navbar-content{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-link:not(.is-arrowless){padding-right:2.5em}html.theme--documenter-dark .navbar-link:not(.is-arrowless)::after{border-color:#fff;margin-top:-0.375em;right:1.125em}html.theme--documenter-dark .navbar-dropdown{font-size:0.875rem;padding-bottom:0.5rem;padding-top:0.5rem}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}html.theme--documenter-dark .navbar-divider{background-color:rgba(0,0,0,0.2);border:none;display:none;height:2px;margin:0.5rem 0}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar>.container{display:block}html.theme--documenter-dark .navbar-brand .navbar-item,html.theme--documenter-dark .navbar-tabs .navbar-item{align-items:center;display:flex}html.theme--documenter-dark .navbar-link::after{display:none}html.theme--documenter-dark .navbar-menu{background-color:#375a7f;box-shadow:0 8px 16px rgba(10,10,10,0.1);padding:0.5rem 0}html.theme--documenter-dark .navbar-menu.is-active{display:block}html.theme--documenter-dark .navbar.is-fixed-bottom-touch,html.theme--documenter-dark .navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-touch{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-touch{top:0}html.theme--documenter-dark .navbar.is-fixed-top .navbar-menu,html.theme--documenter-dark .navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 4rem);overflow:auto}html.theme--documenter-dark html.has-navbar-fixed-top-touch,html.theme--documenter-dark body.has-navbar-fixed-top-touch{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-touch,html.theme--documenter-dark body.has-navbar-fixed-bottom-touch{padding-bottom:4rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar,html.theme--documenter-dark .navbar-menu,html.theme--documenter-dark .navbar-start,html.theme--documenter-dark .navbar-end{align-items:stretch;display:flex}html.theme--documenter-dark .navbar{min-height:4rem}html.theme--documenter-dark .navbar.is-spaced{padding:1rem 2rem}html.theme--documenter-dark .navbar.is-spaced .navbar-start,html.theme--documenter-dark .navbar.is-spaced .navbar-end{align-items:center}html.theme--documenter-dark .navbar.is-spaced a.navbar-item,html.theme--documenter-dark .navbar.is-spaced .navbar-link{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent a.navbar-item:hover,html.theme--documenter-dark .navbar.is-transparent a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-transparent .navbar-link:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-link:hover,html.theme--documenter-dark .navbar.is-transparent .navbar-link.is-active{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-burger{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{align-items:center;display:flex}html.theme--documenter-dark .navbar-item{display:flex}html.theme--documenter-dark .navbar-item.has-dropdown{align-items:stretch}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(0.25em, -0.25em)}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:1px solid rgba(0,0,0,0.2);border-radius:8px 8px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,0.1);top:auto}html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed{opacity:1;pointer-events:auto;transform:translateY(0)}html.theme--documenter-dark .navbar-menu{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .navbar-start{justify-content:flex-start;margin-right:auto}html.theme--documenter-dark .navbar-end{justify-content:flex-end;margin-left:auto}html.theme--documenter-dark .navbar-dropdown{background-color:#375a7f;border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid rgba(0,0,0,0.2);box-shadow:0 8px 8px rgba(10,10,10,0.1);display:none;font-size:0.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding:0.375rem 1rem;white-space:nowrap}html.theme--documenter-dark .navbar-dropdown a.navbar-item{padding-right:3rem}html.theme--documenter-dark .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}.navbar.is-spaced html.theme--documenter-dark .navbar-dropdown,html.theme--documenter-dark .navbar-dropdown.is-boxed{border-radius:8px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity, transform}html.theme--documenter-dark .navbar-dropdown.is-right{left:auto;right:0}html.theme--documenter-dark .navbar-divider{display:block}html.theme--documenter-dark .navbar>.container .navbar-brand,html.theme--documenter-dark .container>.navbar .navbar-brand{margin-left:-.75rem}html.theme--documenter-dark .navbar>.container .navbar-menu,html.theme--documenter-dark .container>.navbar .navbar-menu{margin-right:-.75rem}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop,html.theme--documenter-dark .navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-desktop{top:0}html.theme--documenter-dark html.has-navbar-fixed-top-desktop,html.theme--documenter-dark body.has-navbar-fixed-top-desktop{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-desktop,html.theme--documenter-dark body.has-navbar-fixed-bottom-desktop{padding-bottom:4rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-top,html.theme--documenter-dark body.has-spaced-navbar-fixed-top{padding-top:6rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-bottom,html.theme--documenter-dark body.has-spaced-navbar-fixed-bottom{padding-bottom:6rem}html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link.is-active{color:#1abc9c}html.theme--documenter-dark a.navbar-item.is-active:not(:focus):not(:hover),html.theme--documenter-dark .navbar-link.is-active:not(:focus):not(:hover){background-color:rgba(0,0,0,0)}html.theme--documenter-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown.is-active .navbar-link{background-color:rgba(0,0,0,0)}}html.theme--documenter-dark .hero.is-fullheight-with-navbar{min-height:calc(100vh - 4rem)}html.theme--documenter-dark .pagination{font-size:15px;margin:-.25rem}html.theme--documenter-dark .pagination.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination{font-size:.85em}html.theme--documenter-dark .pagination.is-medium{font-size:1.25rem}html.theme--documenter-dark .pagination.is-large{font-size:1.5rem}html.theme--documenter-dark .pagination.is-rounded .pagination-previous,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-previous,html.theme--documenter-dark .pagination.is-rounded .pagination-next,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-next{padding-left:1em;padding-right:1em;border-radius:290486px}html.theme--documenter-dark .pagination.is-rounded .pagination-link,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-link{border-radius:290486px}html.theme--documenter-dark .pagination,html.theme--documenter-dark .pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link{border-color:#5e6d6f;color:#1abc9c;min-width:2.25em}html.theme--documenter-dark .pagination-previous:hover,html.theme--documenter-dark .pagination-next:hover,html.theme--documenter-dark .pagination-link:hover{border-color:#8c9b9d;color:#1dd2af}html.theme--documenter-dark .pagination-previous:focus,html.theme--documenter-dark .pagination-next:focus,html.theme--documenter-dark .pagination-link:focus{border-color:#8c9b9d}html.theme--documenter-dark .pagination-previous:active,html.theme--documenter-dark .pagination-next:active,html.theme--documenter-dark .pagination-link:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2)}html.theme--documenter-dark .pagination-previous[disabled],html.theme--documenter-dark .pagination-next[disabled],html.theme--documenter-dark .pagination-link[disabled]{background-color:#dbdee0;border-color:#dbdee0;box-shadow:none;color:#5e6d6f;opacity:0.5}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{padding-left:0.75em;padding-right:0.75em;white-space:nowrap}html.theme--documenter-dark .pagination-link.is-current{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .pagination-ellipsis{color:#8c9b9d;pointer-events:none}html.theme--documenter-dark .pagination-list{flex-wrap:wrap}@media screen and (max-width: 768px){html.theme--documenter-dark .pagination{flex-wrap:wrap}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}html.theme--documenter-dark .pagination-previous{order:2}html.theme--documenter-dark .pagination-next{order:3}html.theme--documenter-dark .pagination{justify-content:space-between}html.theme--documenter-dark .pagination.is-centered .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-centered .pagination-list{justify-content:center;order:2}html.theme--documenter-dark .pagination.is-centered .pagination-next{order:3}html.theme--documenter-dark .pagination.is-right .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-right .pagination-next{order:2}html.theme--documenter-dark .pagination.is-right .pagination-list{justify-content:flex-end;order:3}}html.theme--documenter-dark .panel{font-size:15px}html.theme--documenter-dark .panel:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .panel-heading,html.theme--documenter-dark .panel-tabs,html.theme--documenter-dark .panel-block{border-bottom:1px solid #5e6d6f;border-left:1px solid #5e6d6f;border-right:1px solid #5e6d6f}html.theme--documenter-dark .panel-heading:first-child,html.theme--documenter-dark .panel-tabs:first-child,html.theme--documenter-dark .panel-block:first-child{border-top:1px solid #5e6d6f}html.theme--documenter-dark .panel-heading{background-color:#282f2f;border-radius:.4em .4em 0 0;color:#f2f2f2;font-size:1.25em;font-weight:300;line-height:1.25;padding:0.5em 0.75em}html.theme--documenter-dark .panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}html.theme--documenter-dark .panel-tabs a{border-bottom:1px solid #5e6d6f;margin-bottom:-1px;padding:0.5em}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#343c3d;color:#17a689}html.theme--documenter-dark .panel-list a{color:#fff}html.theme--documenter-dark .panel-list a:hover{color:#1abc9c}html.theme--documenter-dark .panel-block{align-items:center;color:#f2f2f2;display:flex;justify-content:flex-start;padding:0.5em 0.75em}html.theme--documenter-dark .panel-block input[type="checkbox"]{margin-right:0.75em}html.theme--documenter-dark .panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}html.theme--documenter-dark .panel-block.is-wrapped{flex-wrap:wrap}html.theme--documenter-dark .panel-block.is-active{border-left-color:#1abc9c;color:#17a689}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark a.panel-block,html.theme--documenter-dark label.panel-block{cursor:pointer}html.theme--documenter-dark a.panel-block:hover,html.theme--documenter-dark label.panel-block:hover{background-color:#282f2f}html.theme--documenter-dark .panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#fff;margin-right:0.75em}html.theme--documenter-dark .panel-icon .fa{font-size:inherit;line-height:inherit}html.theme--documenter-dark .tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:15px;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}html.theme--documenter-dark .tabs a{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;color:#fff;display:flex;justify-content:center;margin-bottom:-1px;padding:0.5em 1em;vertical-align:top}html.theme--documenter-dark .tabs a:hover{border-bottom-color:#f2f2f2;color:#f2f2f2}html.theme--documenter-dark .tabs li{display:block}html.theme--documenter-dark .tabs li.is-active a{border-bottom-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .tabs ul{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}html.theme--documenter-dark .tabs ul.is-left{padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-center{flex:none;justify-content:center;padding-left:0.75em;padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-right{justify-content:flex-end;padding-left:0.75em}html.theme--documenter-dark .tabs .icon:first-child{margin-right:0.5em}html.theme--documenter-dark .tabs .icon:last-child{margin-left:0.5em}html.theme--documenter-dark .tabs.is-centered ul{justify-content:center}html.theme--documenter-dark .tabs.is-right ul{justify-content:flex-end}html.theme--documenter-dark .tabs.is-boxed a{border:1px solid transparent;border-radius:.4em .4em 0 0}html.theme--documenter-dark .tabs.is-boxed a:hover{background-color:#282f2f;border-bottom-color:#5e6d6f}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#fff;border-color:#5e6d6f;border-bottom-color:rgba(0,0,0,0) !important}html.theme--documenter-dark .tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .tabs.is-toggle a{border-color:#5e6d6f;border-style:solid;border-width:1px;margin-bottom:0;position:relative}html.theme--documenter-dark .tabs.is-toggle a:hover{background-color:#282f2f;border-color:#8c9b9d;z-index:2}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .tabs.is-toggle li:first-child a{border-radius:.4em 0 0 .4em}html.theme--documenter-dark .tabs.is-toggle li:last-child a{border-radius:0 .4em .4em 0}html.theme--documenter-dark .tabs.is-toggle li.is-active a{background-color:#1abc9c;border-color:#1abc9c;color:#fff;z-index:1}html.theme--documenter-dark .tabs.is-toggle ul{border-bottom:none}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:290486px;border-top-left-radius:290486px;padding-left:1.25em}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:290486px;border-top-right-radius:290486px;padding-right:1.25em}html.theme--documenter-dark .tabs.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.tabs{font-size:.85em}html.theme--documenter-dark .tabs.is-medium{font-size:1.25rem}html.theme--documenter-dark .tabs.is-large{font-size:1.5rem}html.theme--documenter-dark .column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>html.theme--documenter-dark .column.is-narrow{flex:none}.columns.is-mobile>html.theme--documenter-dark .column.is-full{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-half{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-half{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-0{flex:none;width:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-0{margin-left:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-1{flex:none;width:8.3333333333%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-1{margin-left:8.3333333333%}.columns.is-mobile>html.theme--documenter-dark .column.is-2{flex:none;width:16.6666666667%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-2{margin-left:16.6666666667%}.columns.is-mobile>html.theme--documenter-dark .column.is-3{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-3{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-4{flex:none;width:33.3333333333%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-4{margin-left:33.3333333333%}.columns.is-mobile>html.theme--documenter-dark .column.is-5{flex:none;width:41.6666666667%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-5{margin-left:41.6666666667%}.columns.is-mobile>html.theme--documenter-dark .column.is-6{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-6{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-7{flex:none;width:58.3333333333%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-7{margin-left:58.3333333333%}.columns.is-mobile>html.theme--documenter-dark .column.is-8{flex:none;width:66.6666666667%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-8{margin-left:66.6666666667%}.columns.is-mobile>html.theme--documenter-dark .column.is-9{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-9{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-10{flex:none;width:83.3333333333%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-10{margin-left:83.3333333333%}.columns.is-mobile>html.theme--documenter-dark .column.is-11{flex:none;width:91.6666666667%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-11{margin-left:91.6666666667%}.columns.is-mobile>html.theme--documenter-dark .column.is-12{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-12{margin-left:100%}@media screen and (max-width: 768px){html.theme--documenter-dark .column.is-narrow-mobile{flex:none}html.theme--documenter-dark .column.is-full-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-mobile{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-mobile{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-mobile{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-mobile{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-mobile{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-mobile{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-mobile{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-mobile{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-mobile{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-mobile{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-mobile{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-mobile{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-mobile{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-mobile{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-mobile{margin-left:80%}html.theme--documenter-dark .column.is-0-mobile{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-mobile{margin-left:0%}html.theme--documenter-dark .column.is-1-mobile{flex:none;width:8.3333333333%}html.theme--documenter-dark .column.is-offset-1-mobile{margin-left:8.3333333333%}html.theme--documenter-dark .column.is-2-mobile{flex:none;width:16.6666666667%}html.theme--documenter-dark .column.is-offset-2-mobile{margin-left:16.6666666667%}html.theme--documenter-dark .column.is-3-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-mobile{margin-left:25%}html.theme--documenter-dark .column.is-4-mobile{flex:none;width:33.3333333333%}html.theme--documenter-dark .column.is-offset-4-mobile{margin-left:33.3333333333%}html.theme--documenter-dark .column.is-5-mobile{flex:none;width:41.6666666667%}html.theme--documenter-dark .column.is-offset-5-mobile{margin-left:41.6666666667%}html.theme--documenter-dark .column.is-6-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-mobile{margin-left:50%}html.theme--documenter-dark .column.is-7-mobile{flex:none;width:58.3333333333%}html.theme--documenter-dark .column.is-offset-7-mobile{margin-left:58.3333333333%}html.theme--documenter-dark .column.is-8-mobile{flex:none;width:66.6666666667%}html.theme--documenter-dark .column.is-offset-8-mobile{margin-left:66.6666666667%}html.theme--documenter-dark .column.is-9-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-mobile{margin-left:75%}html.theme--documenter-dark .column.is-10-mobile{flex:none;width:83.3333333333%}html.theme--documenter-dark .column.is-offset-10-mobile{margin-left:83.3333333333%}html.theme--documenter-dark .column.is-11-mobile{flex:none;width:91.6666666667%}html.theme--documenter-dark .column.is-offset-11-mobile{margin-left:91.6666666667%}html.theme--documenter-dark .column.is-12-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .column.is-narrow,html.theme--documenter-dark .column.is-narrow-tablet{flex:none}html.theme--documenter-dark .column.is-full,html.theme--documenter-dark .column.is-full-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters,html.theme--documenter-dark .column.is-three-quarters-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds,html.theme--documenter-dark .column.is-two-thirds-tablet{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half,html.theme--documenter-dark .column.is-half-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third,html.theme--documenter-dark .column.is-one-third-tablet{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter,html.theme--documenter-dark .column.is-one-quarter-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth,html.theme--documenter-dark .column.is-one-fifth-tablet{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths,html.theme--documenter-dark .column.is-two-fifths-tablet{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths,html.theme--documenter-dark .column.is-three-fifths-tablet{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths,html.theme--documenter-dark .column.is-four-fifths-tablet{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters,html.theme--documenter-dark .column.is-offset-three-quarters-tablet{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds,html.theme--documenter-dark .column.is-offset-two-thirds-tablet{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half,html.theme--documenter-dark .column.is-offset-half-tablet{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third,html.theme--documenter-dark .column.is-offset-one-third-tablet{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter,html.theme--documenter-dark .column.is-offset-one-quarter-tablet{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth,html.theme--documenter-dark .column.is-offset-one-fifth-tablet{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths,html.theme--documenter-dark .column.is-offset-two-fifths-tablet{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths,html.theme--documenter-dark .column.is-offset-three-fifths-tablet{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths,html.theme--documenter-dark .column.is-offset-four-fifths-tablet{margin-left:80%}html.theme--documenter-dark .column.is-0,html.theme--documenter-dark .column.is-0-tablet{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0,html.theme--documenter-dark .column.is-offset-0-tablet{margin-left:0%}html.theme--documenter-dark .column.is-1,html.theme--documenter-dark .column.is-1-tablet{flex:none;width:8.3333333333%}html.theme--documenter-dark .column.is-offset-1,html.theme--documenter-dark .column.is-offset-1-tablet{margin-left:8.3333333333%}html.theme--documenter-dark .column.is-2,html.theme--documenter-dark .column.is-2-tablet{flex:none;width:16.6666666667%}html.theme--documenter-dark .column.is-offset-2,html.theme--documenter-dark .column.is-offset-2-tablet{margin-left:16.6666666667%}html.theme--documenter-dark .column.is-3,html.theme--documenter-dark .column.is-3-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3,html.theme--documenter-dark .column.is-offset-3-tablet{margin-left:25%}html.theme--documenter-dark .column.is-4,html.theme--documenter-dark .column.is-4-tablet{flex:none;width:33.3333333333%}html.theme--documenter-dark .column.is-offset-4,html.theme--documenter-dark .column.is-offset-4-tablet{margin-left:33.3333333333%}html.theme--documenter-dark .column.is-5,html.theme--documenter-dark .column.is-5-tablet{flex:none;width:41.6666666667%}html.theme--documenter-dark .column.is-offset-5,html.theme--documenter-dark .column.is-offset-5-tablet{margin-left:41.6666666667%}html.theme--documenter-dark .column.is-6,html.theme--documenter-dark .column.is-6-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6,html.theme--documenter-dark .column.is-offset-6-tablet{margin-left:50%}html.theme--documenter-dark .column.is-7,html.theme--documenter-dark .column.is-7-tablet{flex:none;width:58.3333333333%}html.theme--documenter-dark .column.is-offset-7,html.theme--documenter-dark .column.is-offset-7-tablet{margin-left:58.3333333333%}html.theme--documenter-dark .column.is-8,html.theme--documenter-dark .column.is-8-tablet{flex:none;width:66.6666666667%}html.theme--documenter-dark .column.is-offset-8,html.theme--documenter-dark .column.is-offset-8-tablet{margin-left:66.6666666667%}html.theme--documenter-dark .column.is-9,html.theme--documenter-dark .column.is-9-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9,html.theme--documenter-dark .column.is-offset-9-tablet{margin-left:75%}html.theme--documenter-dark .column.is-10,html.theme--documenter-dark .column.is-10-tablet{flex:none;width:83.3333333333%}html.theme--documenter-dark .column.is-offset-10,html.theme--documenter-dark .column.is-offset-10-tablet{margin-left:83.3333333333%}html.theme--documenter-dark .column.is-11,html.theme--documenter-dark .column.is-11-tablet{flex:none;width:91.6666666667%}html.theme--documenter-dark .column.is-offset-11,html.theme--documenter-dark .column.is-offset-11-tablet{margin-left:91.6666666667%}html.theme--documenter-dark .column.is-12,html.theme--documenter-dark .column.is-12-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12,html.theme--documenter-dark .column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width: 1055px){html.theme--documenter-dark .column.is-narrow-touch{flex:none}html.theme--documenter-dark .column.is-full-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-touch{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-touch{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-touch{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-touch{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-touch{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-touch{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-touch{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-touch{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-touch{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-touch{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-touch{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-touch{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-touch{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-touch{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-touch{margin-left:80%}html.theme--documenter-dark .column.is-0-touch{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-touch{margin-left:0%}html.theme--documenter-dark .column.is-1-touch{flex:none;width:8.3333333333%}html.theme--documenter-dark .column.is-offset-1-touch{margin-left:8.3333333333%}html.theme--documenter-dark .column.is-2-touch{flex:none;width:16.6666666667%}html.theme--documenter-dark .column.is-offset-2-touch{margin-left:16.6666666667%}html.theme--documenter-dark .column.is-3-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-touch{margin-left:25%}html.theme--documenter-dark .column.is-4-touch{flex:none;width:33.3333333333%}html.theme--documenter-dark .column.is-offset-4-touch{margin-left:33.3333333333%}html.theme--documenter-dark .column.is-5-touch{flex:none;width:41.6666666667%}html.theme--documenter-dark .column.is-offset-5-touch{margin-left:41.6666666667%}html.theme--documenter-dark .column.is-6-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-touch{margin-left:50%}html.theme--documenter-dark .column.is-7-touch{flex:none;width:58.3333333333%}html.theme--documenter-dark .column.is-offset-7-touch{margin-left:58.3333333333%}html.theme--documenter-dark .column.is-8-touch{flex:none;width:66.6666666667%}html.theme--documenter-dark .column.is-offset-8-touch{margin-left:66.6666666667%}html.theme--documenter-dark .column.is-9-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-touch{margin-left:75%}html.theme--documenter-dark .column.is-10-touch{flex:none;width:83.3333333333%}html.theme--documenter-dark .column.is-offset-10-touch{margin-left:83.3333333333%}html.theme--documenter-dark .column.is-11-touch{flex:none;width:91.6666666667%}html.theme--documenter-dark .column.is-offset-11-touch{margin-left:91.6666666667%}html.theme--documenter-dark .column.is-12-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width: 1056px){html.theme--documenter-dark .column.is-narrow-desktop{flex:none}html.theme--documenter-dark .column.is-full-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-desktop{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-desktop{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-desktop{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-desktop{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-desktop{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-desktop{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-desktop{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-desktop{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-desktop{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-desktop{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-desktop{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-desktop{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-desktop{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-desktop{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-desktop{margin-left:80%}html.theme--documenter-dark .column.is-0-desktop{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-desktop{margin-left:0%}html.theme--documenter-dark .column.is-1-desktop{flex:none;width:8.3333333333%}html.theme--documenter-dark .column.is-offset-1-desktop{margin-left:8.3333333333%}html.theme--documenter-dark .column.is-2-desktop{flex:none;width:16.6666666667%}html.theme--documenter-dark .column.is-offset-2-desktop{margin-left:16.6666666667%}html.theme--documenter-dark .column.is-3-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-desktop{margin-left:25%}html.theme--documenter-dark .column.is-4-desktop{flex:none;width:33.3333333333%}html.theme--documenter-dark .column.is-offset-4-desktop{margin-left:33.3333333333%}html.theme--documenter-dark .column.is-5-desktop{flex:none;width:41.6666666667%}html.theme--documenter-dark .column.is-offset-5-desktop{margin-left:41.6666666667%}html.theme--documenter-dark .column.is-6-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-desktop{margin-left:50%}html.theme--documenter-dark .column.is-7-desktop{flex:none;width:58.3333333333%}html.theme--documenter-dark .column.is-offset-7-desktop{margin-left:58.3333333333%}html.theme--documenter-dark .column.is-8-desktop{flex:none;width:66.6666666667%}html.theme--documenter-dark .column.is-offset-8-desktop{margin-left:66.6666666667%}html.theme--documenter-dark .column.is-9-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-desktop{margin-left:75%}html.theme--documenter-dark .column.is-10-desktop{flex:none;width:83.3333333333%}html.theme--documenter-dark .column.is-offset-10-desktop{margin-left:83.3333333333%}html.theme--documenter-dark .column.is-11-desktop{flex:none;width:91.6666666667%}html.theme--documenter-dark .column.is-offset-11-desktop{margin-left:91.6666666667%}html.theme--documenter-dark .column.is-12-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width: 1216px){html.theme--documenter-dark .column.is-narrow-widescreen{flex:none}html.theme--documenter-dark .column.is-full-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-widescreen{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-widescreen{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-widescreen{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-widescreen{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-widescreen{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-widescreen{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-widescreen{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-widescreen{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-widescreen{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-widescreen{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-widescreen{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-widescreen{margin-left:80%}html.theme--documenter-dark .column.is-0-widescreen{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-widescreen{margin-left:0%}html.theme--documenter-dark .column.is-1-widescreen{flex:none;width:8.3333333333%}html.theme--documenter-dark .column.is-offset-1-widescreen{margin-left:8.3333333333%}html.theme--documenter-dark .column.is-2-widescreen{flex:none;width:16.6666666667%}html.theme--documenter-dark .column.is-offset-2-widescreen{margin-left:16.6666666667%}html.theme--documenter-dark .column.is-3-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-4-widescreen{flex:none;width:33.3333333333%}html.theme--documenter-dark .column.is-offset-4-widescreen{margin-left:33.3333333333%}html.theme--documenter-dark .column.is-5-widescreen{flex:none;width:41.6666666667%}html.theme--documenter-dark .column.is-offset-5-widescreen{margin-left:41.6666666667%}html.theme--documenter-dark .column.is-6-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-7-widescreen{flex:none;width:58.3333333333%}html.theme--documenter-dark .column.is-offset-7-widescreen{margin-left:58.3333333333%}html.theme--documenter-dark .column.is-8-widescreen{flex:none;width:66.6666666667%}html.theme--documenter-dark .column.is-offset-8-widescreen{margin-left:66.6666666667%}html.theme--documenter-dark .column.is-9-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-10-widescreen{flex:none;width:83.3333333333%}html.theme--documenter-dark .column.is-offset-10-widescreen{margin-left:83.3333333333%}html.theme--documenter-dark .column.is-11-widescreen{flex:none;width:91.6666666667%}html.theme--documenter-dark .column.is-offset-11-widescreen{margin-left:91.6666666667%}html.theme--documenter-dark .column.is-12-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width: 1408px){html.theme--documenter-dark .column.is-narrow-fullhd{flex:none}html.theme--documenter-dark .column.is-full-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-fullhd{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-fullhd{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-fullhd{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-fullhd{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-fullhd{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-fullhd{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-fullhd{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-fullhd{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-fullhd{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-fullhd{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-fullhd{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-fullhd{margin-left:80%}html.theme--documenter-dark .column.is-0-fullhd{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-fullhd{margin-left:0%}html.theme--documenter-dark .column.is-1-fullhd{flex:none;width:8.3333333333%}html.theme--documenter-dark .column.is-offset-1-fullhd{margin-left:8.3333333333%}html.theme--documenter-dark .column.is-2-fullhd{flex:none;width:16.6666666667%}html.theme--documenter-dark .column.is-offset-2-fullhd{margin-left:16.6666666667%}html.theme--documenter-dark .column.is-3-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-4-fullhd{flex:none;width:33.3333333333%}html.theme--documenter-dark .column.is-offset-4-fullhd{margin-left:33.3333333333%}html.theme--documenter-dark .column.is-5-fullhd{flex:none;width:41.6666666667%}html.theme--documenter-dark .column.is-offset-5-fullhd{margin-left:41.6666666667%}html.theme--documenter-dark .column.is-6-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-7-fullhd{flex:none;width:58.3333333333%}html.theme--documenter-dark .column.is-offset-7-fullhd{margin-left:58.3333333333%}html.theme--documenter-dark .column.is-8-fullhd{flex:none;width:66.6666666667%}html.theme--documenter-dark .column.is-offset-8-fullhd{margin-left:66.6666666667%}html.theme--documenter-dark .column.is-9-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-10-fullhd{flex:none;width:83.3333333333%}html.theme--documenter-dark .column.is-offset-10-fullhd{margin-left:83.3333333333%}html.theme--documenter-dark .column.is-11-fullhd{flex:none;width:91.6666666667%}html.theme--documenter-dark .column.is-offset-11-fullhd{margin-left:91.6666666667%}html.theme--documenter-dark .column.is-12-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-fullhd{margin-left:100%}}html.theme--documenter-dark .columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .columns:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}html.theme--documenter-dark .columns.is-centered{justify-content:center}html.theme--documenter-dark .columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}html.theme--documenter-dark .columns.is-gapless>.column{margin:0;padding:0 !important}html.theme--documenter-dark .columns.is-gapless:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .columns.is-gapless:last-child{margin-bottom:0}html.theme--documenter-dark .columns.is-mobile{display:flex}html.theme--documenter-dark .columns.is-multiline{flex-wrap:wrap}html.theme--documenter-dark .columns.is-vcentered{align-items:center}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns:not(.is-desktop){display:flex}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-desktop{display:flex}}html.theme--documenter-dark .columns.is-variable{--columnGap: 0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}html.theme--documenter-dark .columns.is-variable .column{padding-left:var(--columnGap);padding-right:var(--columnGap)}html.theme--documenter-dark .columns.is-variable.is-0{--columnGap: 0rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-0-mobile{--columnGap: 0rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-0-tablet{--columnGap: 0rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-tablet-only{--columnGap: 0rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-touch{--columnGap: 0rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-0-desktop{--columnGap: 0rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-0-desktop-only{--columnGap: 0rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen{--columnGap: 0rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen-only{--columnGap: 0rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-0-fullhd{--columnGap: 0rem}}html.theme--documenter-dark .columns.is-variable.is-1{--columnGap: .25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-1-mobile{--columnGap: .25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-1-tablet{--columnGap: .25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-tablet-only{--columnGap: .25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-touch{--columnGap: .25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-1-desktop{--columnGap: .25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-1-desktop-only{--columnGap: .25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen{--columnGap: .25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen-only{--columnGap: .25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-1-fullhd{--columnGap: .25rem}}html.theme--documenter-dark .columns.is-variable.is-2{--columnGap: .5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-2-mobile{--columnGap: .5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-2-tablet{--columnGap: .5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-tablet-only{--columnGap: .5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-touch{--columnGap: .5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-2-desktop{--columnGap: .5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-2-desktop-only{--columnGap: .5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen{--columnGap: .5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen-only{--columnGap: .5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-2-fullhd{--columnGap: .5rem}}html.theme--documenter-dark .columns.is-variable.is-3{--columnGap: .75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-3-mobile{--columnGap: .75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-3-tablet{--columnGap: .75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-tablet-only{--columnGap: .75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-touch{--columnGap: .75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-3-desktop{--columnGap: .75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-3-desktop-only{--columnGap: .75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen{--columnGap: .75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen-only{--columnGap: .75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-3-fullhd{--columnGap: .75rem}}html.theme--documenter-dark .columns.is-variable.is-4{--columnGap: 1rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-4-mobile{--columnGap: 1rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-4-tablet{--columnGap: 1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-tablet-only{--columnGap: 1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-touch{--columnGap: 1rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-4-desktop{--columnGap: 1rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-4-desktop-only{--columnGap: 1rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen{--columnGap: 1rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen-only{--columnGap: 1rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-4-fullhd{--columnGap: 1rem}}html.theme--documenter-dark .columns.is-variable.is-5{--columnGap: 1.25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-5-mobile{--columnGap: 1.25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-5-tablet{--columnGap: 1.25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-tablet-only{--columnGap: 1.25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-touch{--columnGap: 1.25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-5-desktop{--columnGap: 1.25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-5-desktop-only{--columnGap: 1.25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen{--columnGap: 1.25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen-only{--columnGap: 1.25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-5-fullhd{--columnGap: 1.25rem}}html.theme--documenter-dark .columns.is-variable.is-6{--columnGap: 1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-6-mobile{--columnGap: 1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-6-tablet{--columnGap: 1.5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-tablet-only{--columnGap: 1.5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-touch{--columnGap: 1.5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-6-desktop{--columnGap: 1.5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-6-desktop-only{--columnGap: 1.5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen{--columnGap: 1.5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen-only{--columnGap: 1.5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-6-fullhd{--columnGap: 1.5rem}}html.theme--documenter-dark .columns.is-variable.is-7{--columnGap: 1.75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-7-mobile{--columnGap: 1.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-7-tablet{--columnGap: 1.75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-tablet-only{--columnGap: 1.75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-touch{--columnGap: 1.75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-7-desktop{--columnGap: 1.75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-7-desktop-only{--columnGap: 1.75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen{--columnGap: 1.75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen-only{--columnGap: 1.75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-7-fullhd{--columnGap: 1.75rem}}html.theme--documenter-dark .columns.is-variable.is-8{--columnGap: 2rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-8-mobile{--columnGap: 2rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-8-tablet{--columnGap: 2rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-tablet-only{--columnGap: 2rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-touch{--columnGap: 2rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-8-desktop{--columnGap: 2rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-8-desktop-only{--columnGap: 2rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen{--columnGap: 2rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen-only{--columnGap: 2rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-8-fullhd{--columnGap: 2rem}}html.theme--documenter-dark .tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:min-content}html.theme--documenter-dark .tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .tile.is-ancestor:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .tile.is-ancestor:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .tile.is-child{margin:0 !important}html.theme--documenter-dark .tile.is-parent{padding:.75rem}html.theme--documenter-dark .tile.is-vertical{flex-direction:column}html.theme--documenter-dark .tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem !important}@media screen and (min-width: 769px),print{html.theme--documenter-dark .tile:not(.is-child){display:flex}html.theme--documenter-dark .tile.is-1{flex:none;width:8.3333333333%}html.theme--documenter-dark .tile.is-2{flex:none;width:16.6666666667%}html.theme--documenter-dark .tile.is-3{flex:none;width:25%}html.theme--documenter-dark .tile.is-4{flex:none;width:33.3333333333%}html.theme--documenter-dark .tile.is-5{flex:none;width:41.6666666667%}html.theme--documenter-dark .tile.is-6{flex:none;width:50%}html.theme--documenter-dark .tile.is-7{flex:none;width:58.3333333333%}html.theme--documenter-dark .tile.is-8{flex:none;width:66.6666666667%}html.theme--documenter-dark .tile.is-9{flex:none;width:75%}html.theme--documenter-dark .tile.is-10{flex:none;width:83.3333333333%}html.theme--documenter-dark .tile.is-11{flex:none;width:91.6666666667%}html.theme--documenter-dark .tile.is-12{flex:none;width:100%}}html.theme--documenter-dark .hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}html.theme--documenter-dark .hero .navbar{background:none}html.theme--documenter-dark .hero .tabs ul{border-bottom:none}html.theme--documenter-dark .hero.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-white strong{color:inherit}html.theme--documenter-dark .hero.is-white .title{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .subtitle{color:rgba(10,10,10,0.9)}html.theme--documenter-dark .hero.is-white .subtitle a:not(.button),html.theme--documenter-dark .hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-white .navbar-menu{background-color:#fff}}html.theme--documenter-dark .hero.is-white .navbar-item,html.theme--documenter-dark .hero.is-white .navbar-link{color:rgba(10,10,10,0.7)}html.theme--documenter-dark .hero.is-white a.navbar-item:hover,html.theme--documenter-dark .hero.is-white a.navbar-item.is-active,html.theme--documenter-dark .hero.is-white .navbar-link:hover,html.theme--documenter-dark .hero.is-white .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs a{color:#0a0a0a;opacity:0.9}html.theme--documenter-dark .hero.is-white .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-white .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-white.is-bold{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}}html.theme--documenter-dark .hero.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-black strong{color:inherit}html.theme--documenter-dark .hero.is-black .title{color:#fff}html.theme--documenter-dark .hero.is-black .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-black .subtitle a:not(.button),html.theme--documenter-dark .hero.is-black .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-black .navbar-menu{background-color:#0a0a0a}}html.theme--documenter-dark .hero.is-black .navbar-item,html.theme--documenter-dark .hero.is-black .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-black a.navbar-item:hover,html.theme--documenter-dark .hero.is-black a.navbar-item.is-active,html.theme--documenter-dark .hero.is-black .navbar-link:hover,html.theme--documenter-dark .hero.is-black .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .hero.is-black .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-black .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-black .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-black.is-bold{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}}html.theme--documenter-dark .hero.is-light{background-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-light strong{color:inherit}html.theme--documenter-dark .hero.is-light .title{color:#282f2f}html.theme--documenter-dark .hero.is-light .subtitle{color:rgba(40,47,47,0.9)}html.theme--documenter-dark .hero.is-light .subtitle a:not(.button),html.theme--documenter-dark .hero.is-light .subtitle strong{color:#282f2f}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-light .navbar-menu{background-color:#ecf0f1}}html.theme--documenter-dark .hero.is-light .navbar-item,html.theme--documenter-dark .hero.is-light .navbar-link{color:rgba(40,47,47,0.7)}html.theme--documenter-dark .hero.is-light a.navbar-item:hover,html.theme--documenter-dark .hero.is-light a.navbar-item.is-active,html.theme--documenter-dark .hero.is-light .navbar-link:hover,html.theme--documenter-dark .hero.is-light .navbar-link.is-active{background-color:#dde4e6;color:#282f2f}html.theme--documenter-dark .hero.is-light .tabs a{color:#282f2f;opacity:0.9}html.theme--documenter-dark .hero.is-light .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-light .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a{color:#282f2f}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:#282f2f;border-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .hero.is-light.is-bold{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}}html.theme--documenter-dark .hero.is-dark,html.theme--documenter-dark .content kbd.hero{background-color:#282f2f;color:#ecf0f1}html.theme--documenter-dark .hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .content kbd.hero a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-dark strong,html.theme--documenter-dark .content kbd.hero strong{color:inherit}html.theme--documenter-dark .hero.is-dark .title,html.theme--documenter-dark .content kbd.hero .title{color:#ecf0f1}html.theme--documenter-dark .hero.is-dark .subtitle,html.theme--documenter-dark .content kbd.hero .subtitle{color:rgba(236,240,241,0.9)}html.theme--documenter-dark .hero.is-dark .subtitle a:not(.button),html.theme--documenter-dark .content kbd.hero .subtitle a:not(.button),html.theme--documenter-dark .hero.is-dark .subtitle strong,html.theme--documenter-dark .content kbd.hero .subtitle strong{color:#ecf0f1}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-dark .navbar-menu,html.theme--documenter-dark .content kbd.hero .navbar-menu{background-color:#282f2f}}html.theme--documenter-dark .hero.is-dark .navbar-item,html.theme--documenter-dark .content kbd.hero .navbar-item,html.theme--documenter-dark .hero.is-dark .navbar-link,html.theme--documenter-dark .content kbd.hero .navbar-link{color:rgba(236,240,241,0.7)}html.theme--documenter-dark .hero.is-dark a.navbar-item:hover,html.theme--documenter-dark .content kbd.hero a.navbar-item:hover,html.theme--documenter-dark .hero.is-dark a.navbar-item.is-active,html.theme--documenter-dark .content kbd.hero a.navbar-item.is-active,html.theme--documenter-dark .hero.is-dark .navbar-link:hover,html.theme--documenter-dark .content kbd.hero .navbar-link:hover,html.theme--documenter-dark .hero.is-dark .navbar-link.is-active,html.theme--documenter-dark .content kbd.hero .navbar-link.is-active{background-color:#1d2122;color:#ecf0f1}html.theme--documenter-dark .hero.is-dark .tabs a,html.theme--documenter-dark .content kbd.hero .tabs a{color:#ecf0f1;opacity:0.9}html.theme--documenter-dark .hero.is-dark .tabs a:hover,html.theme--documenter-dark .content kbd.hero .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-dark .tabs li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a{color:#ecf0f1}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#ecf0f1;border-color:#ecf0f1;color:#282f2f}html.theme--documenter-dark .hero.is-dark.is-bold,html.theme--documenter-dark .content kbd.hero.is-bold{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-dark.is-bold .navbar-menu,html.theme--documenter-dark .content kbd.hero.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}}html.theme--documenter-dark .hero.is-primary,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-primary strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink strong{color:inherit}html.theme--documenter-dark .hero.is-primary .title,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .title{color:#fff}html.theme--documenter-dark .hero.is-primary .subtitle,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-primary .subtitle a:not(.button),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle a:not(.button),html.theme--documenter-dark .hero.is-primary .subtitle strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-primary .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-menu{background-color:#375a7f}}html.theme--documenter-dark .hero.is-primary .navbar-item,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-item,html.theme--documenter-dark .hero.is-primary .navbar-link,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-primary a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item:hover,html.theme--documenter-dark .hero.is-primary a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item.is-active,html.theme--documenter-dark .hero.is-primary .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link:hover,html.theme--documenter-dark .hero.is-primary .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .hero.is-primary .tabs a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-primary .tabs a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-primary .tabs li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#375a7f}html.theme--documenter-dark .hero.is-primary.is-bold,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-primary.is-bold .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink .navbar-menu{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}}html.theme--documenter-dark .hero.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-link strong{color:inherit}html.theme--documenter-dark .hero.is-link .title{color:#fff}html.theme--documenter-dark .hero.is-link .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-link .subtitle a:not(.button),html.theme--documenter-dark .hero.is-link .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-link .navbar-menu{background-color:#1abc9c}}html.theme--documenter-dark .hero.is-link .navbar-item,html.theme--documenter-dark .hero.is-link .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-link a.navbar-item:hover,html.theme--documenter-dark .hero.is-link a.navbar-item.is-active,html.theme--documenter-dark .hero.is-link .navbar-link:hover,html.theme--documenter-dark .hero.is-link .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .hero.is-link .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-link .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-link .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#1abc9c}html.theme--documenter-dark .hero.is-link.is-bold{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}}html.theme--documenter-dark .hero.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-info strong{color:inherit}html.theme--documenter-dark .hero.is-info .title{color:#fff}html.theme--documenter-dark .hero.is-info .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-info .subtitle a:not(.button),html.theme--documenter-dark .hero.is-info .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-info .navbar-menu{background-color:#024c7d}}html.theme--documenter-dark .hero.is-info .navbar-item,html.theme--documenter-dark .hero.is-info .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-info a.navbar-item:hover,html.theme--documenter-dark .hero.is-info a.navbar-item.is-active,html.theme--documenter-dark .hero.is-info .navbar-link:hover,html.theme--documenter-dark .hero.is-info .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .hero.is-info .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-info .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-info .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#024c7d}html.theme--documenter-dark .hero.is-info.is-bold{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}}html.theme--documenter-dark .hero.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-success strong{color:inherit}html.theme--documenter-dark .hero.is-success .title{color:#fff}html.theme--documenter-dark .hero.is-success .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-success .subtitle a:not(.button),html.theme--documenter-dark .hero.is-success .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-success .navbar-menu{background-color:#008438}}html.theme--documenter-dark .hero.is-success .navbar-item,html.theme--documenter-dark .hero.is-success .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-success a.navbar-item:hover,html.theme--documenter-dark .hero.is-success a.navbar-item.is-active,html.theme--documenter-dark .hero.is-success .navbar-link:hover,html.theme--documenter-dark .hero.is-success .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .hero.is-success .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-success .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-success .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#008438}html.theme--documenter-dark .hero.is-success.is-bold{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}}html.theme--documenter-dark .hero.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-warning strong{color:inherit}html.theme--documenter-dark .hero.is-warning .title{color:#fff}html.theme--documenter-dark .hero.is-warning .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-warning .subtitle a:not(.button),html.theme--documenter-dark .hero.is-warning .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-warning .navbar-menu{background-color:#ad8100}}html.theme--documenter-dark .hero.is-warning .navbar-item,html.theme--documenter-dark .hero.is-warning .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-warning a.navbar-item:hover,html.theme--documenter-dark .hero.is-warning a.navbar-item.is-active,html.theme--documenter-dark .hero.is-warning .navbar-link:hover,html.theme--documenter-dark .hero.is-warning .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .hero.is-warning .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-warning .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-warning .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#ad8100}html.theme--documenter-dark .hero.is-warning.is-bold{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}}html.theme--documenter-dark .hero.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-danger strong{color:inherit}html.theme--documenter-dark .hero.is-danger .title{color:#fff}html.theme--documenter-dark .hero.is-danger .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-danger .subtitle a:not(.button),html.theme--documenter-dark .hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-danger .navbar-menu{background-color:#9e1b0d}}html.theme--documenter-dark .hero.is-danger .navbar-item,html.theme--documenter-dark .hero.is-danger .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-danger a.navbar-item:hover,html.theme--documenter-dark .hero.is-danger a.navbar-item.is-active,html.theme--documenter-dark .hero.is-danger .navbar-link:hover,html.theme--documenter-dark .hero.is-danger .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .hero.is-danger .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-danger .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-danger .tabs li.is-active a{opacity:1}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#9e1b0d}html.theme--documenter-dark .hero.is-danger.is-bold{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}}html.theme--documenter-dark .hero.is-small .hero-body,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.hero .hero-body{padding-bottom:1.5rem;padding-top:1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-medium .hero-body{padding-bottom:9rem;padding-top:9rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-large .hero-body{padding-bottom:18rem;padding-top:18rem}}html.theme--documenter-dark .hero.is-halfheight .hero-body,html.theme--documenter-dark .hero.is-fullheight .hero-body,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body{align-items:center;display:flex}html.theme--documenter-dark .hero.is-halfheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body>.container{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .hero.is-halfheight{min-height:50vh}html.theme--documenter-dark .hero.is-fullheight{min-height:100vh}html.theme--documenter-dark .hero-video{overflow:hidden}html.theme--documenter-dark .hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%, -50%, 0)}html.theme--documenter-dark .hero-video.is-transparent{opacity:0.3}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-video{display:none}}html.theme--documenter-dark .hero-buttons{margin-top:1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-buttons .button{display:flex}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-bottom:0.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-buttons{display:flex;justify-content:center}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-right:1.5rem}}html.theme--documenter-dark .hero-head,html.theme--documenter-dark .hero-foot{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}html.theme--documenter-dark .section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){html.theme--documenter-dark .section.is-medium{padding:9rem 1.5rem}html.theme--documenter-dark .section.is-large{padding:18rem 1.5rem}}html.theme--documenter-dark .footer{background-color:#282f2f;padding:3rem 1.5rem 6rem}html.theme--documenter-dark hr{height:1px}html.theme--documenter-dark h6{text-transform:uppercase;letter-spacing:0.5px}html.theme--documenter-dark .hero{background-color:#343c3d}html.theme--documenter-dark a{transition:all 200ms ease}html.theme--documenter-dark .button{transition:all 200ms ease;border-width:1px;color:#fff}html.theme--documenter-dark .button.is-active,html.theme--documenter-dark .button.is-focused,html.theme--documenter-dark .button:active,html.theme--documenter-dark .button:focus{box-shadow:0 0 0 2px rgba(140,155,157,0.5)}html.theme--documenter-dark .button.is-white.is-hovered,html.theme--documenter-dark .button.is-white:hover{background-color:#fff}html.theme--documenter-dark .button.is-white.is-active,html.theme--documenter-dark .button.is-white.is-focused,html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white:focus{border-color:#fff;box-shadow:0 0 0 2px rgba(255,255,255,0.5)}html.theme--documenter-dark .button.is-black.is-hovered,html.theme--documenter-dark .button.is-black:hover{background-color:#1d1d1d}html.theme--documenter-dark .button.is-black.is-active,html.theme--documenter-dark .button.is-black.is-focused,html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black:focus{border-color:#0a0a0a;box-shadow:0 0 0 2px rgba(10,10,10,0.5)}html.theme--documenter-dark .button.is-light.is-hovered,html.theme--documenter-dark .button.is-light:hover{background-color:#fff}html.theme--documenter-dark .button.is-light.is-active,html.theme--documenter-dark .button.is-light.is-focused,html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light:focus{border-color:#ecf0f1;box-shadow:0 0 0 2px rgba(236,240,241,0.5)}html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered,html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover{background-color:#3a4344}html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused,html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus{border-color:#282f2f;box-shadow:0 0 0 2px rgba(40,47,47,0.5)}html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover{background-color:#436d9a}html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink,html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus{border-color:#375a7f;box-shadow:0 0 0 2px rgba(55,90,127,0.5)}html.theme--documenter-dark .button.is-link.is-hovered,html.theme--documenter-dark .button.is-link:hover{background-color:#1fdeb8}html.theme--documenter-dark .button.is-link.is-active,html.theme--documenter-dark .button.is-link.is-focused,html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link:focus{border-color:#1abc9c;box-shadow:0 0 0 2px rgba(26,188,156,0.5)}html.theme--documenter-dark .button.is-info.is-hovered,html.theme--documenter-dark .button.is-info:hover{background-color:#0363a3}html.theme--documenter-dark .button.is-info.is-active,html.theme--documenter-dark .button.is-info.is-focused,html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info:focus{border-color:#024c7d;box-shadow:0 0 0 2px rgba(2,76,125,0.5)}html.theme--documenter-dark .button.is-success.is-hovered,html.theme--documenter-dark .button.is-success:hover{background-color:#00aa48}html.theme--documenter-dark .button.is-success.is-active,html.theme--documenter-dark .button.is-success.is-focused,html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success:focus{border-color:#008438;box-shadow:0 0 0 2px rgba(0,132,56,0.5)}html.theme--documenter-dark .button.is-warning.is-hovered,html.theme--documenter-dark .button.is-warning:hover{background-color:#d39e00}html.theme--documenter-dark .button.is-warning.is-active,html.theme--documenter-dark .button.is-warning.is-focused,html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning:focus{border-color:#ad8100;box-shadow:0 0 0 2px rgba(173,129,0,0.5)}html.theme--documenter-dark .button.is-danger.is-hovered,html.theme--documenter-dark .button.is-danger:hover{background-color:#c12110}html.theme--documenter-dark .button.is-danger.is-active,html.theme--documenter-dark .button.is-danger.is-focused,html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger:focus{border-color:#9e1b0d;box-shadow:0 0 0 2px rgba(158,27,13,0.5)}html.theme--documenter-dark .label{color:#dbdee0}html.theme--documenter-dark .button,html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .select,html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea{height:2.5em}html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .textarea{transition:all 200ms ease;box-shadow:none;border-width:1px;padding-left:1em;padding-right:1em}html.theme--documenter-dark .select:after,html.theme--documenter-dark .select select{border-width:1px}html.theme--documenter-dark .control.has-addons .button,html.theme--documenter-dark .control.has-addons .input,html.theme--documenter-dark .control.has-addons #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-addons form.docs-search>input,html.theme--documenter-dark .control.has-addons .select{margin-right:-1px}html.theme--documenter-dark .notification{background-color:#343c3d}html.theme--documenter-dark .card{box-shadow:none;border:1px solid #343c3d;background-color:#282f2f;border-radius:.4em}html.theme--documenter-dark .card .card-image img{border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-header{box-shadow:none;background-color:rgba(18,18,18,0.2);border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-footer{background-color:rgba(18,18,18,0.2)}html.theme--documenter-dark .card .card-footer,html.theme--documenter-dark .card .card-footer-item{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .notification.is-white a:not(.button){color:#0a0a0a;text-decoration:underline}html.theme--documenter-dark .notification.is-black a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-light a:not(.button){color:#282f2f;text-decoration:underline}html.theme--documenter-dark .notification.is-dark a:not(.button),html.theme--documenter-dark .content kbd.notification a:not(.button){color:#ecf0f1;text-decoration:underline}html.theme--documenter-dark .notification.is-primary a:not(.button),html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-link a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-info a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-success a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-warning a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-danger a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .tag,html.theme--documenter-dark .content kbd,html.theme--documenter-dark .docstring>section>a.docs-sourcelink{border-radius:.4em}html.theme--documenter-dark .menu-list a{transition:all 300ms ease}html.theme--documenter-dark .modal-card-body{background-color:#282f2f}html.theme--documenter-dark .modal-card-foot,html.theme--documenter-dark .modal-card-head{border-color:#343c3d}html.theme--documenter-dark .message-header{font-weight:700;background-color:#343c3d;color:#fff}html.theme--documenter-dark .message-body{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .navbar{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent{background:none}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar .navbar-menu{background-color:#375a7f;border-radius:0 0 .4em .4em}}html.theme--documenter-dark .hero .navbar,html.theme--documenter-dark body>.navbar{border-radius:0}html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous{border-width:1px}html.theme--documenter-dark .panel-block,html.theme--documenter-dark .panel-heading,html.theme--documenter-dark .panel-tabs{border-width:1px}html.theme--documenter-dark .panel-block:first-child,html.theme--documenter-dark .panel-heading:first-child,html.theme--documenter-dark .panel-tabs:first-child{border-top-width:1px}html.theme--documenter-dark .panel-heading{font-weight:700}html.theme--documenter-dark .panel-tabs a{border-width:1px;margin-bottom:-1px}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#17a689}html.theme--documenter-dark .panel-block:hover{color:#1dd2af}html.theme--documenter-dark .panel-block:hover .panel-icon{color:#1dd2af}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#17a689}html.theme--documenter-dark .tabs a{border-bottom-width:1px;margin-bottom:-1px}html.theme--documenter-dark .tabs ul{border-bottom-width:1px}html.theme--documenter-dark .tabs.is-boxed a{border-width:1px}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#1f2424}html.theme--documenter-dark .tabs.is-toggle li a{border-width:1px;margin-bottom:0}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .hero.is-white .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-black .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-light .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-dark .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .content kbd.hero .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-primary .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-link .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-info .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-success .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-warning .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-danger .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark h1 .docs-heading-anchor,html.theme--documenter-dark h1 .docs-heading-anchor:hover,html.theme--documenter-dark h1 .docs-heading-anchor:visited,html.theme--documenter-dark h2 .docs-heading-anchor,html.theme--documenter-dark h2 .docs-heading-anchor:hover,html.theme--documenter-dark h2 .docs-heading-anchor:visited,html.theme--documenter-dark h3 .docs-heading-anchor,html.theme--documenter-dark h3 .docs-heading-anchor:hover,html.theme--documenter-dark h3 .docs-heading-anchor:visited,html.theme--documenter-dark h4 .docs-heading-anchor,html.theme--documenter-dark h4 .docs-heading-anchor:hover,html.theme--documenter-dark h4 .docs-heading-anchor:visited,html.theme--documenter-dark h5 .docs-heading-anchor,html.theme--documenter-dark h5 .docs-heading-anchor:hover,html.theme--documenter-dark h5 .docs-heading-anchor:visited,html.theme--documenter-dark h6 .docs-heading-anchor,html.theme--documenter-dark h6 .docs-heading-anchor:hover,html.theme--documenter-dark h6 .docs-heading-anchor:visited{color:#f2f2f2}html.theme--documenter-dark h1 .docs-heading-anchor-permalink,html.theme--documenter-dark h2 .docs-heading-anchor-permalink,html.theme--documenter-dark h3 .docs-heading-anchor-permalink,html.theme--documenter-dark h4 .docs-heading-anchor-permalink,html.theme--documenter-dark h5 .docs-heading-anchor-permalink,html.theme--documenter-dark h6 .docs-heading-anchor-permalink{visibility:hidden;vertical-align:middle;margin-left:0.5em;font-size:0.7rem}html.theme--documenter-dark h1 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h2 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h3 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h4 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h5 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h6 .docs-heading-anchor-permalink::before{font-family:"Font Awesome 5 Free";font-weight:900;content:"\f0c1"}html.theme--documenter-dark h1:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h2:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h3:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h4:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h5:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h6:hover .docs-heading-anchor-permalink{visibility:visible}html.theme--documenter-dark .docs-light-only{display:none !important}html.theme--documenter-dark pre{position:relative;overflow:hidden}html.theme--documenter-dark pre code,html.theme--documenter-dark pre code.hljs{padding:0 .75rem !important;overflow:auto;display:block}html.theme--documenter-dark pre code:first-of-type,html.theme--documenter-dark pre code.hljs:first-of-type{padding-top:0.5rem !important}html.theme--documenter-dark pre code:last-of-type,html.theme--documenter-dark pre code.hljs:last-of-type{padding-bottom:0.5rem !important}html.theme--documenter-dark pre .copy-button{opacity:0.2;transition:opacity 0.2s;position:absolute;right:0em;top:0em;padding:0.5em;width:2.5em;height:2.5em;background:transparent;border:none;font-family:"Font Awesome 5 Free";color:#fff;cursor:pointer;text-align:center}html.theme--documenter-dark pre .copy-button:focus,html.theme--documenter-dark pre .copy-button:hover{opacity:1;background:rgba(255,255,255,0.1);color:#1abc9c}html.theme--documenter-dark pre .copy-button.success{color:#259a12;opacity:1}html.theme--documenter-dark pre .copy-button.error{color:#cb3c33;opacity:1}html.theme--documenter-dark pre:hover .copy-button{opacity:1}html.theme--documenter-dark .admonition{background-color:#282f2f;border-style:solid;border-width:1px;border-color:#5e6d6f;border-radius:.4em;font-size:15px}html.theme--documenter-dark .admonition strong{color:currentColor}html.theme--documenter-dark .admonition.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.admonition{font-size:.85em}html.theme--documenter-dark .admonition.is-medium{font-size:1.25rem}html.theme--documenter-dark .admonition.is-large{font-size:1.5rem}html.theme--documenter-dark .admonition.is-default{background-color:#282f2f;border-color:#5e6d6f}html.theme--documenter-dark .admonition.is-default>.admonition-header{background-color:#5e6d6f;color:#fff}html.theme--documenter-dark .admonition.is-default>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-info{background-color:#282f2f;border-color:#024c7d}html.theme--documenter-dark .admonition.is-info>.admonition-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .admonition.is-info>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-success{background-color:#282f2f;border-color:#008438}html.theme--documenter-dark .admonition.is-success>.admonition-header{background-color:#008438;color:#fff}html.theme--documenter-dark .admonition.is-success>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-warning{background-color:#282f2f;border-color:#ad8100}html.theme--documenter-dark .admonition.is-warning>.admonition-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .admonition.is-warning>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-danger{background-color:#282f2f;border-color:#9e1b0d}html.theme--documenter-dark .admonition.is-danger>.admonition-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .admonition.is-danger>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-compat{background-color:#282f2f;border-color:#137886}html.theme--documenter-dark .admonition.is-compat>.admonition-header{background-color:#137886;color:#fff}html.theme--documenter-dark .admonition.is-compat>.admonition-body{color:#fff}html.theme--documenter-dark .admonition-header{color:#fff;background-color:#5e6d6f;align-items:center;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.5rem .75rem;position:relative}html.theme--documenter-dark .admonition-header:before{font-family:"Font Awesome 5 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}html.theme--documenter-dark .admonition-body{color:#fff;padding:0.5rem .75rem}html.theme--documenter-dark .admonition-body pre{background-color:#282f2f}html.theme--documenter-dark .admonition-body code{background-color:rgba(255,255,255,0.05)}html.theme--documenter-dark .docstring{margin-bottom:1em;background-color:rgba(0,0,0,0);border:1px solid #5e6d6f;box-shadow:none;max-width:100%}html.theme--documenter-dark .docstring>header{display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#282f2f;box-shadow:0 1px 2px rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .docstring>header code{background-color:transparent}html.theme--documenter-dark .docstring>header .docstring-binding{margin-right:0.3em}html.theme--documenter-dark .docstring>header .docstring-category{margin-left:0.3em}html.theme--documenter-dark .docstring>section{position:relative;padding:.75rem .75rem;border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .docstring>section:last-child{border-bottom:none}html.theme--documenter-dark .docstring>section>a.docs-sourcelink{transition:opacity 0.3s;opacity:0;position:absolute;right:.375rem;bottom:.375rem}html.theme--documenter-dark .docstring>section>a.docs-sourcelink:focus{opacity:1 !important}html.theme--documenter-dark .docstring:hover>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring:focus-within>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring>section:hover a.docs-sourcelink{opacity:1}html.theme--documenter-dark .documenter-example-output{background-color:#1f2424}html.theme--documenter-dark .outdated-warning-overlay{position:fixed;top:0;left:0;right:0;box-shadow:0 0 10px rgba(0,0,0,0.3);z-index:999;background-color:#282f2f;color:#fff;border-bottom:3px solid #9e1b0d;padding:10px 35px;text-align:center;font-size:15px}html.theme--documenter-dark .outdated-warning-overlay .outdated-warning-closer{position:absolute;top:calc(50% - 10px);right:18px;cursor:pointer;width:12px}html.theme--documenter-dark .outdated-warning-overlay a{color:#1abc9c}html.theme--documenter-dark .outdated-warning-overlay a:hover{color:#1dd2af}html.theme--documenter-dark .content pre{border:1px solid #5e6d6f}html.theme--documenter-dark .content code{font-weight:inherit}html.theme--documenter-dark .content a code{color:#1abc9c}html.theme--documenter-dark .content h1 code,html.theme--documenter-dark .content h2 code,html.theme--documenter-dark .content h3 code,html.theme--documenter-dark .content h4 code,html.theme--documenter-dark .content h5 code,html.theme--documenter-dark .content h6 code{color:#f2f2f2}html.theme--documenter-dark .content table{display:block;width:initial;max-width:100%;overflow-x:auto}html.theme--documenter-dark .content blockquote>ul:first-child,html.theme--documenter-dark .content blockquote>ol:first-child,html.theme--documenter-dark .content .admonition-body>ul:first-child,html.theme--documenter-dark .content .admonition-body>ol:first-child{margin-top:0}html.theme--documenter-dark pre,html.theme--documenter-dark code{font-variant-ligatures:no-contextual}html.theme--documenter-dark .breadcrumb a.is-disabled{cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb a.is-disabled,html.theme--documenter-dark .breadcrumb a.is-disabled:hover{color:#f2f2f2}html.theme--documenter-dark .hljs{background:initial !important}html.theme--documenter-dark .katex .katex-mathml{top:0;right:0}html.theme--documenter-dark .katex-display,html.theme--documenter-dark mjx-container,html.theme--documenter-dark .MathJax_Display{margin:0.5em 0 !important}html.theme--documenter-dark html{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto}html.theme--documenter-dark li.no-marker{list-style:none}html.theme--documenter-dark #documenter .docs-main>article{overflow-wrap:break-word}html.theme--documenter-dark #documenter .docs-main>article .math-container{overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-main{max-width:52rem;margin-left:20rem;padding-right:1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main{width:100%}html.theme--documenter-dark #documenter .docs-main>article{max-width:52rem;margin-left:auto;margin-right:auto;margin-bottom:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-main>header,html.theme--documenter-dark #documenter .docs-main>nav{max-width:100%;width:100%;margin:0}}html.theme--documenter-dark #documenter .docs-main header.docs-navbar{background-color:#1f2424;border-bottom:1px solid #5e6d6f;z-index:2;min-height:4rem;margin-bottom:1rem;display:flex}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .breadcrumb{flex-grow:1}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-icon,html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label,html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-sidebar-button{display:inline-block}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-settings-button{margin:auto 0 auto 1rem}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-sidebar-button{font-size:1.5rem;margin:auto 0 auto 1rem}html.theme--documenter-dark #documenter .docs-main header.docs-navbar>*{margin:auto 0}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar{position:sticky;top:0;padding:0 1rem;transition-property:top, box-shadow;-webkit-transition-property:top, box-shadow;transition-duration:0.3s;-webkit-transition-duration:0.3s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--not-top{box-shadow:.2rem 0rem .4rem #171717;transition-duration:0.7s;-webkit-transition-duration:0.7s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--unpinned.headroom--not-top.headroom--not-bottom{top:-4.5rem;transition-duration:0.7s;-webkit-transition-duration:0.7s}}html.theme--documenter-dark #documenter .docs-main section.footnotes{border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-main section.footnotes li .tag:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .docstring>section>a.docs-sourcelink:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .content kbd:first-child,html.theme--documenter-dark .content #documenter .docs-main section.footnotes li kbd:first-child{margin-right:1em;margin-bottom:0.4em}html.theme--documenter-dark #documenter .docs-main .docs-footer{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;border-top:1px solid #5e6d6f;padding-top:1rem;padding-bottom:1rem}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main .docs-footer{padding-left:1rem;padding-right:1rem}}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage,html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-prevpage{flex-grow:1}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage{text-align:right}html.theme--documenter-dark #documenter .docs-main .docs-footer .flexbox-break{flex-basis:100%;height:0}html.theme--documenter-dark #documenter .docs-main .docs-footer .footer-message{font-size:0.8em;margin:0.5em auto 0 auto;text-align:center}html.theme--documenter-dark #documenter .docs-sidebar{display:flex;flex-direction:column;color:#fff;background-color:#282f2f;border-right:1px solid #5e6d6f;padding:0;flex:0 0 18rem;z-index:5;font-size:15px;position:fixed;left:-18rem;width:18rem;height:100%;transition:left 0.3s}html.theme--documenter-dark #documenter .docs-sidebar.visible{left:0;box-shadow:.4rem 0rem .8rem #171717}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar.visible{box-shadow:none}}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar{left:0;top:0}}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo{margin-top:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{max-height:6rem;margin:auto}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name{flex-shrink:0;font-size:1.5rem;font-weight:700;text-align:center;white-space:nowrap;overflow:hidden;padding:0.5rem 0}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name .docs-autofit{max-width:16.2rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a,html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a:hover{color:#fff}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector{border-top:1px solid #5e6d6f;display:none;padding:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector.visible{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{flex-grow:1;user-select:none;border-top:1px solid #5e6d6f;padding-bottom:1.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li>.tocitem{font-weight:bold}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li li{font-size:14.25px;margin-left:1em;border-left:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input.collapse-toggle{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.collapsed{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~ul.collapsed{display:block}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-label{flex-grow:2}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;font-size:11.25px;margin-left:1rem;margin-top:auto;margin-bottom:auto}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron::before{font-family:"Font Awesome 5 Free";font-weight:900;content:"\f054"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~label.tocitem .docs-chevron::before{content:"\f078"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem{display:block;padding:0.5rem 0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem:hover{color:#fff;background:#282f2f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu a.tocitem:hover,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem:hover{color:#fff;background-color:#32393a}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active{border-top:1px solid #5e6d6f;border-bottom:1px solid #5e6d6f;background-color:#1f2424}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem:hover{background-color:#1f2424;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem:hover{background-color:#32393a;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li.is-active:first-child{border-top:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal{margin:0 0.5rem 0.5rem;border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal li{font-size:12.75px;border-left:none;margin-left:0;margin-top:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem{width:100%;padding:0}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem::before{content:"⚬";margin-right:0.4em}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search{margin:auto;margin-top:0.5rem;margin-bottom:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{width:14.4rem}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-sidebar{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}html.theme--documenter-dark #documenter .docs-main #documenter-search-info{margin-bottom:1rem}html.theme--documenter-dark #documenter .docs-main #documenter-search-results{list-style-type:circle;list-style-position:outside}html.theme--documenter-dark #documenter .docs-main #documenter-search-results li{margin-left:2rem}html.theme--documenter-dark #documenter .docs-main #documenter-search-results .docs-highlight{background-color:yellow}html.theme--documenter-dark{background-color:#1f2424;font-size:16px;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark .ansi span.sgr1{font-weight:bolder}html.theme--documenter-dark .ansi span.sgr2{font-weight:lighter}html.theme--documenter-dark .ansi span.sgr3{font-style:italic}html.theme--documenter-dark .ansi span.sgr4{text-decoration:underline}html.theme--documenter-dark .ansi span.sgr7{color:#1f2424;background-color:#fff}html.theme--documenter-dark .ansi span.sgr8{color:transparent}html.theme--documenter-dark .ansi span.sgr8 span{color:transparent}html.theme--documenter-dark .ansi span.sgr9{text-decoration:line-through}html.theme--documenter-dark .ansi span.sgr30{color:#242424}html.theme--documenter-dark .ansi span.sgr31{color:#f6705f}html.theme--documenter-dark .ansi span.sgr32{color:#4fb43a}html.theme--documenter-dark .ansi span.sgr33{color:#f4c72f}html.theme--documenter-dark .ansi span.sgr34{color:#7587f0}html.theme--documenter-dark .ansi span.sgr35{color:#bc89d3}html.theme--documenter-dark .ansi span.sgr36{color:#49b6ca}html.theme--documenter-dark .ansi span.sgr37{color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr40{background-color:#242424}html.theme--documenter-dark .ansi span.sgr41{background-color:#f6705f}html.theme--documenter-dark .ansi span.sgr42{background-color:#4fb43a}html.theme--documenter-dark .ansi span.sgr43{background-color:#f4c72f}html.theme--documenter-dark .ansi span.sgr44{background-color:#7587f0}html.theme--documenter-dark .ansi span.sgr45{background-color:#bc89d3}html.theme--documenter-dark .ansi span.sgr46{background-color:#49b6ca}html.theme--documenter-dark .ansi span.sgr47{background-color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr90{color:#92a0a2}html.theme--documenter-dark .ansi span.sgr91{color:#ff8674}html.theme--documenter-dark .ansi span.sgr92{color:#79d462}html.theme--documenter-dark .ansi span.sgr93{color:#ffe76b}html.theme--documenter-dark .ansi span.sgr94{color:#8a98ff}html.theme--documenter-dark .ansi span.sgr95{color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr96{color:#6bc8db}html.theme--documenter-dark .ansi span.sgr97{color:#ecf0f1}html.theme--documenter-dark .ansi span.sgr100{background-color:#92a0a2}html.theme--documenter-dark .ansi span.sgr101{background-color:#ff8674}html.theme--documenter-dark .ansi span.sgr102{background-color:#79d462}html.theme--documenter-dark .ansi span.sgr103{background-color:#ffe76b}html.theme--documenter-dark .ansi span.sgr104{background-color:#8a98ff}html.theme--documenter-dark .ansi span.sgr105{background-color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr106{background-color:#6bc8db}html.theme--documenter-dark .ansi span.sgr107{background-color:#ecf0f1}html.theme--documenter-dark code.language-julia-repl>span.hljs-meta{color:#4fb43a;font-weight:bolder}html.theme--documenter-dark .hljs{background:#2b2b2b;color:#f8f8f2}html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-quote{color:#d4d0ab}html.theme--documenter-dark .hljs-variable,html.theme--documenter-dark .hljs-template-variable,html.theme--documenter-dark .hljs-tag,html.theme--documenter-dark .hljs-name,html.theme--documenter-dark .hljs-selector-id,html.theme--documenter-dark .hljs-selector-class,html.theme--documenter-dark .hljs-regexp,html.theme--documenter-dark .hljs-deletion{color:#ffa07a}html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-link{color:#f5ab35}html.theme--documenter-dark .hljs-attribute{color:#ffd700}html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-addition{color:#abe338}html.theme--documenter-dark .hljs-title,html.theme--documenter-dark .hljs-section{color:#00e0e0}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{color:#dcc6e0}html.theme--documenter-dark .hljs-emphasis{font-style:italic}html.theme--documenter-dark .hljs-strong{font-weight:bold}@media screen and (-ms-high-contrast: active){html.theme--documenter-dark .hljs-addition,html.theme--documenter-dark .hljs-attribute,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-link,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-quote{color:highlight}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{font-weight:bold}}html.theme--documenter-dark .hljs-subst{color:#f8f8f2} diff --git a/previews/PR539/assets/themes/documenter-light.css b/previews/PR539/assets/themes/documenter-light.css new file mode 100644 index 000000000..9b9a14b04 --- /dev/null +++ b/previews/PR539/assets/themes/documenter-light.css @@ -0,0 +1,9 @@ +@keyframes spinAround{from{transform:rotate(0deg)}to{transform:rotate(359deg)}}.tabs,.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis,.breadcrumb,.file,.button,.is-unselectable,.modal-close,.delete{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.navbar-link:not(.is-arrowless)::after,.select:not(.is-multiple):not(.is-loading)::after{border:3px solid rgba(0,0,0,0);border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:0.625em;margin-top:-0.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:0.625em}.admonition:not(:last-child),.tabs:not(:last-child),.message:not(:last-child),.list:not(:last-child),.level:not(:last-child),.breadcrumb:not(:last-child),.highlight:not(:last-child),.block:not(:last-child),.title:not(:last-child),.subtitle:not(:last-child),.table-container:not(:last-child),.table:not(:last-child),.progress:not(:last-child),.notification:not(:last-child),.content:not(:last-child),.box:not(:last-child){margin-bottom:1.5rem}.modal-close,.delete{-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,0.2);border:none;border-radius:290486px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:none;position:relative;vertical-align:top;width:20px}.modal-close::before,.delete::before,.modal-close::after,.delete::after{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.modal-close::before,.delete::before{height:2px;width:50%}.modal-close::after,.delete::after{height:50%;width:2px}.modal-close:hover,.delete:hover,.modal-close:focus,.delete:focus{background-color:rgba(10,10,10,0.3)}.modal-close:active,.delete:active{background-color:rgba(10,10,10,0.4)}.is-small.modal-close,#documenter .docs-sidebar form.docs-search>input.modal-close,.is-small.delete,#documenter .docs-sidebar form.docs-search>input.delete{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}.is-medium.modal-close,.is-medium.delete{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}.is-large.modal-close,.is-large.delete{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}.control.is-loading::after,.select.is-loading::after,.loader,.button.is-loading::after{animation:spinAround 500ms infinite linear;border:2px solid #dbdbdb;border-radius:290486px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}.hero-video,.modal-background,.modal,.image.is-square img,#documenter .docs-sidebar .docs-logo>img.is-square img,.image.is-square .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,.image.is-1by1 img,#documenter .docs-sidebar .docs-logo>img.is-1by1 img,.image.is-1by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,.image.is-5by4 img,#documenter .docs-sidebar .docs-logo>img.is-5by4 img,.image.is-5by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,.image.is-4by3 img,#documenter .docs-sidebar .docs-logo>img.is-4by3 img,.image.is-4by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,.image.is-3by2 img,#documenter .docs-sidebar .docs-logo>img.is-3by2 img,.image.is-3by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,.image.is-5by3 img,#documenter .docs-sidebar .docs-logo>img.is-5by3 img,.image.is-5by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,.image.is-16by9 img,#documenter .docs-sidebar .docs-logo>img.is-16by9 img,.image.is-16by9 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,.image.is-2by1 img,#documenter .docs-sidebar .docs-logo>img.is-2by1 img,.image.is-2by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,.image.is-3by1 img,#documenter .docs-sidebar .docs-logo>img.is-3by1 img,.image.is-3by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,.image.is-4by5 img,#documenter .docs-sidebar .docs-logo>img.is-4by5 img,.image.is-4by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,.image.is-3by4 img,#documenter .docs-sidebar .docs-logo>img.is-3by4 img,.image.is-3by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,.image.is-2by3 img,#documenter .docs-sidebar .docs-logo>img.is-2by3 img,.image.is-2by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,.image.is-3by5 img,#documenter .docs-sidebar .docs-logo>img.is-3by5 img,.image.is-3by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,.image.is-9by16 img,#documenter .docs-sidebar .docs-logo>img.is-9by16 img,.image.is-9by16 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,.image.is-1by2 img,#documenter .docs-sidebar .docs-logo>img.is-1by2 img,.image.is-1by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,.image.is-1by3 img,#documenter .docs-sidebar .docs-logo>img.is-1by3 img,.image.is-1by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio,.is-overlay{bottom:0;left:0;position:absolute;right:0;top:0}.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis,.file-cta,.file-name,.select select,.textarea,.input,#documenter .docs-sidebar form.docs-search>input,.button{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:4px;box-shadow:none;display:inline-flex;font-size:1rem;height:2.25em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(0.375em - 1px);padding-left:calc(0.625em - 1px);padding-right:calc(0.625em - 1px);padding-top:calc(0.375em - 1px);position:relative;vertical-align:top}.pagination-previous:focus,.pagination-next:focus,.pagination-link:focus,.pagination-ellipsis:focus,.file-cta:focus,.file-name:focus,.select select:focus,.textarea:focus,.input:focus,#documenter .docs-sidebar form.docs-search>input:focus,.button:focus,.is-focused.pagination-previous,.is-focused.pagination-next,.is-focused.pagination-link,.is-focused.pagination-ellipsis,.is-focused.file-cta,.is-focused.file-name,.select select.is-focused,.is-focused.textarea,.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-focused.button,.pagination-previous:active,.pagination-next:active,.pagination-link:active,.pagination-ellipsis:active,.file-cta:active,.file-name:active,.select select:active,.textarea:active,.input:active,#documenter .docs-sidebar form.docs-search>input:active,.button:active,.is-active.pagination-previous,.is-active.pagination-next,.is-active.pagination-link,.is-active.pagination-ellipsis,.is-active.file-cta,.is-active.file-name,.select select.is-active,.is-active.textarea,.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active,.is-active.button{outline:none}.pagination-previous[disabled],.pagination-next[disabled],.pagination-link[disabled],.pagination-ellipsis[disabled],.file-cta[disabled],.file-name[disabled],.select select[disabled],.textarea[disabled],.input[disabled],#documenter .docs-sidebar form.docs-search>input[disabled],.button[disabled],fieldset[disabled] .pagination-previous,fieldset[disabled] .pagination-next,fieldset[disabled] .pagination-link,fieldset[disabled] .pagination-ellipsis,fieldset[disabled] .file-cta,fieldset[disabled] .file-name,fieldset[disabled] .select select,.select fieldset[disabled] select,fieldset[disabled] .textarea,fieldset[disabled] .input,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input,fieldset[disabled] .button{cursor:not-allowed}/*! minireset.css v0.0.4 | MIT License | github.com/jgthms/minireset.css */html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,embed,iframe,object,video{height:auto;max-width:100%}audio{max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:left}html{background-color:#fff;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,select,textarea{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}body{color:#222;font-size:1em;font-weight:400;line-height:1.5}a{color:#2e63b8;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:rgba(0,0,0,0.05);color:#000;font-size:.875em;font-weight:normal;padding:.1em}hr{background-color:#f5f5f5;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type="checkbox"],input[type="radio"]{vertical-align:baseline}small{font-size:.875em}span{font-style:inherit;font-weight:inherit}strong{color:#222;font-weight:700}fieldset{border:none}pre{-webkit-overflow-scrolling:touch;background-color:#f5f5f5;color:#222;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{vertical-align:top}table td:not([align]),table th:not([align]){text-align:left}table th{color:#222}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left !important}.is-pulled-right{float:right !important}.is-clipped{overflow:hidden !important}.is-size-1{font-size:3rem !important}.is-size-2{font-size:2.5rem !important}.is-size-3{font-size:2rem !important}.is-size-4{font-size:1.5rem !important}.is-size-5{font-size:1.25rem !important}.is-size-6{font-size:1rem !important}.is-size-7,.docstring>section>a.docs-sourcelink{font-size:.75rem !important}@media screen and (max-width: 768px){.is-size-1-mobile{font-size:3rem !important}.is-size-2-mobile{font-size:2.5rem !important}.is-size-3-mobile{font-size:2rem !important}.is-size-4-mobile{font-size:1.5rem !important}.is-size-5-mobile{font-size:1.25rem !important}.is-size-6-mobile{font-size:1rem !important}.is-size-7-mobile{font-size:.75rem !important}}@media screen and (min-width: 769px),print{.is-size-1-tablet{font-size:3rem !important}.is-size-2-tablet{font-size:2.5rem !important}.is-size-3-tablet{font-size:2rem !important}.is-size-4-tablet{font-size:1.5rem !important}.is-size-5-tablet{font-size:1.25rem !important}.is-size-6-tablet{font-size:1rem !important}.is-size-7-tablet{font-size:.75rem !important}}@media screen and (max-width: 1055px){.is-size-1-touch{font-size:3rem !important}.is-size-2-touch{font-size:2.5rem !important}.is-size-3-touch{font-size:2rem !important}.is-size-4-touch{font-size:1.5rem !important}.is-size-5-touch{font-size:1.25rem !important}.is-size-6-touch{font-size:1rem !important}.is-size-7-touch{font-size:.75rem !important}}@media screen and (min-width: 1056px){.is-size-1-desktop{font-size:3rem !important}.is-size-2-desktop{font-size:2.5rem !important}.is-size-3-desktop{font-size:2rem !important}.is-size-4-desktop{font-size:1.5rem !important}.is-size-5-desktop{font-size:1.25rem !important}.is-size-6-desktop{font-size:1rem !important}.is-size-7-desktop{font-size:.75rem !important}}@media screen and (min-width: 1216px){.is-size-1-widescreen{font-size:3rem !important}.is-size-2-widescreen{font-size:2.5rem !important}.is-size-3-widescreen{font-size:2rem !important}.is-size-4-widescreen{font-size:1.5rem !important}.is-size-5-widescreen{font-size:1.25rem !important}.is-size-6-widescreen{font-size:1rem !important}.is-size-7-widescreen{font-size:.75rem !important}}@media screen and (min-width: 1408px){.is-size-1-fullhd{font-size:3rem !important}.is-size-2-fullhd{font-size:2.5rem !important}.is-size-3-fullhd{font-size:2rem !important}.is-size-4-fullhd{font-size:1.5rem !important}.is-size-5-fullhd{font-size:1.25rem !important}.is-size-6-fullhd{font-size:1rem !important}.is-size-7-fullhd{font-size:.75rem !important}}.has-text-centered{text-align:center !important}.has-text-justified{text-align:justify !important}.has-text-left{text-align:left !important}.has-text-right{text-align:right !important}@media screen and (max-width: 768px){.has-text-centered-mobile{text-align:center !important}}@media screen and (min-width: 769px),print{.has-text-centered-tablet{text-align:center !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-centered-tablet-only{text-align:center !important}}@media screen and (max-width: 1055px){.has-text-centered-touch{text-align:center !important}}@media screen and (min-width: 1056px){.has-text-centered-desktop{text-align:center !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-centered-desktop-only{text-align:center !important}}@media screen and (min-width: 1216px){.has-text-centered-widescreen{text-align:center !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-centered-widescreen-only{text-align:center !important}}@media screen and (min-width: 1408px){.has-text-centered-fullhd{text-align:center !important}}@media screen and (max-width: 768px){.has-text-justified-mobile{text-align:justify !important}}@media screen and (min-width: 769px),print{.has-text-justified-tablet{text-align:justify !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-justified-tablet-only{text-align:justify !important}}@media screen and (max-width: 1055px){.has-text-justified-touch{text-align:justify !important}}@media screen and (min-width: 1056px){.has-text-justified-desktop{text-align:justify !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-justified-desktop-only{text-align:justify !important}}@media screen and (min-width: 1216px){.has-text-justified-widescreen{text-align:justify !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-justified-widescreen-only{text-align:justify !important}}@media screen and (min-width: 1408px){.has-text-justified-fullhd{text-align:justify !important}}@media screen and (max-width: 768px){.has-text-left-mobile{text-align:left !important}}@media screen and (min-width: 769px),print{.has-text-left-tablet{text-align:left !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-left-tablet-only{text-align:left !important}}@media screen and (max-width: 1055px){.has-text-left-touch{text-align:left !important}}@media screen and (min-width: 1056px){.has-text-left-desktop{text-align:left !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-left-desktop-only{text-align:left !important}}@media screen and (min-width: 1216px){.has-text-left-widescreen{text-align:left !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-left-widescreen-only{text-align:left !important}}@media screen and (min-width: 1408px){.has-text-left-fullhd{text-align:left !important}}@media screen and (max-width: 768px){.has-text-right-mobile{text-align:right !important}}@media screen and (min-width: 769px),print{.has-text-right-tablet{text-align:right !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-right-tablet-only{text-align:right !important}}@media screen and (max-width: 1055px){.has-text-right-touch{text-align:right !important}}@media screen and (min-width: 1056px){.has-text-right-desktop{text-align:right !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-right-desktop-only{text-align:right !important}}@media screen and (min-width: 1216px){.has-text-right-widescreen{text-align:right !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-right-widescreen-only{text-align:right !important}}@media screen and (min-width: 1408px){.has-text-right-fullhd{text-align:right !important}}.is-capitalized{text-transform:capitalize !important}.is-lowercase{text-transform:lowercase !important}.is-uppercase{text-transform:uppercase !important}.is-italic{font-style:italic !important}.has-text-white{color:#fff !important}a.has-text-white:hover,a.has-text-white:focus{color:#e6e6e6 !important}.has-background-white{background-color:#fff !important}.has-text-black{color:#0a0a0a !important}a.has-text-black:hover,a.has-text-black:focus{color:#000 !important}.has-background-black{background-color:#0a0a0a !important}.has-text-light{color:#f5f5f5 !important}a.has-text-light:hover,a.has-text-light:focus{color:#dbdbdb !important}.has-background-light{background-color:#f5f5f5 !important}.has-text-dark{color:#363636 !important}a.has-text-dark:hover,a.has-text-dark:focus{color:#1c1c1c !important}.has-background-dark{background-color:#363636 !important}.has-text-primary{color:#4eb5de !important}a.has-text-primary:hover,a.has-text-primary:focus{color:#27a1d2 !important}.has-background-primary{background-color:#4eb5de !important}.has-text-link{color:#2e63b8 !important}a.has-text-link:hover,a.has-text-link:focus{color:#244d8f !important}.has-background-link{background-color:#2e63b8 !important}.has-text-info{color:#209cee !important}a.has-text-info:hover,a.has-text-info:focus{color:#1081cb !important}.has-background-info{background-color:#209cee !important}.has-text-success{color:#22c35b !important}a.has-text-success:hover,a.has-text-success:focus{color:#1a9847 !important}.has-background-success{background-color:#22c35b !important}.has-text-warning{color:#ffdd57 !important}a.has-text-warning:hover,a.has-text-warning:focus{color:#ffd324 !important}.has-background-warning{background-color:#ffdd57 !important}.has-text-danger{color:#da0b00 !important}a.has-text-danger:hover,a.has-text-danger:focus{color:#a70800 !important}.has-background-danger{background-color:#da0b00 !important}.has-text-black-bis{color:#121212 !important}.has-background-black-bis{background-color:#121212 !important}.has-text-black-ter{color:#242424 !important}.has-background-black-ter{background-color:#242424 !important}.has-text-grey-darker{color:#363636 !important}.has-background-grey-darker{background-color:#363636 !important}.has-text-grey-dark{color:#4a4a4a !important}.has-background-grey-dark{background-color:#4a4a4a !important}.has-text-grey{color:#6b6b6b !important}.has-background-grey{background-color:#6b6b6b !important}.has-text-grey-light{color:#b5b5b5 !important}.has-background-grey-light{background-color:#b5b5b5 !important}.has-text-grey-lighter{color:#dbdbdb !important}.has-background-grey-lighter{background-color:#dbdbdb !important}.has-text-white-ter{color:#f5f5f5 !important}.has-background-white-ter{background-color:#f5f5f5 !important}.has-text-white-bis{color:#fafafa !important}.has-background-white-bis{background-color:#fafafa !important}.has-text-weight-light{font-weight:300 !important}.has-text-weight-normal{font-weight:400 !important}.has-text-weight-medium{font-weight:500 !important}.has-text-weight-semibold{font-weight:600 !important}.has-text-weight-bold{font-weight:700 !important}.is-family-primary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-secondary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-sans-serif{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-monospace{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-family-code{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-block{display:block !important}@media screen and (max-width: 768px){.is-block-mobile{display:block !important}}@media screen and (min-width: 769px),print{.is-block-tablet{display:block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-block-tablet-only{display:block !important}}@media screen and (max-width: 1055px){.is-block-touch{display:block !important}}@media screen and (min-width: 1056px){.is-block-desktop{display:block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-block-desktop-only{display:block !important}}@media screen and (min-width: 1216px){.is-block-widescreen{display:block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-block-widescreen-only{display:block !important}}@media screen and (min-width: 1408px){.is-block-fullhd{display:block !important}}.is-flex{display:flex !important}@media screen and (max-width: 768px){.is-flex-mobile{display:flex !important}}@media screen and (min-width: 769px),print{.is-flex-tablet{display:flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-flex-tablet-only{display:flex !important}}@media screen and (max-width: 1055px){.is-flex-touch{display:flex !important}}@media screen and (min-width: 1056px){.is-flex-desktop{display:flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-flex-desktop-only{display:flex !important}}@media screen and (min-width: 1216px){.is-flex-widescreen{display:flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-flex-widescreen-only{display:flex !important}}@media screen and (min-width: 1408px){.is-flex-fullhd{display:flex !important}}.is-inline{display:inline !important}@media screen and (max-width: 768px){.is-inline-mobile{display:inline !important}}@media screen and (min-width: 769px),print{.is-inline-tablet{display:inline !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-tablet-only{display:inline !important}}@media screen and (max-width: 1055px){.is-inline-touch{display:inline !important}}@media screen and (min-width: 1056px){.is-inline-desktop{display:inline !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-desktop-only{display:inline !important}}@media screen and (min-width: 1216px){.is-inline-widescreen{display:inline !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-widescreen-only{display:inline !important}}@media screen and (min-width: 1408px){.is-inline-fullhd{display:inline !important}}.is-inline-block{display:inline-block !important}@media screen and (max-width: 768px){.is-inline-block-mobile{display:inline-block !important}}@media screen and (min-width: 769px),print{.is-inline-block-tablet{display:inline-block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-block-tablet-only{display:inline-block !important}}@media screen and (max-width: 1055px){.is-inline-block-touch{display:inline-block !important}}@media screen and (min-width: 1056px){.is-inline-block-desktop{display:inline-block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-block-desktop-only{display:inline-block !important}}@media screen and (min-width: 1216px){.is-inline-block-widescreen{display:inline-block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-block-widescreen-only{display:inline-block !important}}@media screen and (min-width: 1408px){.is-inline-block-fullhd{display:inline-block !important}}.is-inline-flex{display:inline-flex !important}@media screen and (max-width: 768px){.is-inline-flex-mobile{display:inline-flex !important}}@media screen and (min-width: 769px),print{.is-inline-flex-tablet{display:inline-flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-flex-tablet-only{display:inline-flex !important}}@media screen and (max-width: 1055px){.is-inline-flex-touch{display:inline-flex !important}}@media screen and (min-width: 1056px){.is-inline-flex-desktop{display:inline-flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-flex-desktop-only{display:inline-flex !important}}@media screen and (min-width: 1216px){.is-inline-flex-widescreen{display:inline-flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-flex-widescreen-only{display:inline-flex !important}}@media screen and (min-width: 1408px){.is-inline-flex-fullhd{display:inline-flex !important}}.is-hidden{display:none !important}.is-sr-only{border:none !important;clip:rect(0, 0, 0, 0) !important;height:0.01em !important;overflow:hidden !important;padding:0 !important;position:absolute !important;white-space:nowrap !important;width:0.01em !important}@media screen and (max-width: 768px){.is-hidden-mobile{display:none !important}}@media screen and (min-width: 769px),print{.is-hidden-tablet{display:none !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-hidden-tablet-only{display:none !important}}@media screen and (max-width: 1055px){.is-hidden-touch{display:none !important}}@media screen and (min-width: 1056px){.is-hidden-desktop{display:none !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-hidden-desktop-only{display:none !important}}@media screen and (min-width: 1216px){.is-hidden-widescreen{display:none !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-hidden-widescreen-only{display:none !important}}@media screen and (min-width: 1408px){.is-hidden-fullhd{display:none !important}}.is-invisible{visibility:hidden !important}@media screen and (max-width: 768px){.is-invisible-mobile{visibility:hidden !important}}@media screen and (min-width: 769px),print{.is-invisible-tablet{visibility:hidden !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-invisible-tablet-only{visibility:hidden !important}}@media screen and (max-width: 1055px){.is-invisible-touch{visibility:hidden !important}}@media screen and (min-width: 1056px){.is-invisible-desktop{visibility:hidden !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-invisible-desktop-only{visibility:hidden !important}}@media screen and (min-width: 1216px){.is-invisible-widescreen{visibility:hidden !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-invisible-widescreen-only{visibility:hidden !important}}@media screen and (min-width: 1408px){.is-invisible-fullhd{visibility:hidden !important}}.is-marginless{margin:0 !important}.is-paddingless{padding:0 !important}.is-radiusless{border-radius:0 !important}.is-shadowless{box-shadow:none !important}.is-relative{position:relative !important}.box{background-color:#fff;border-radius:6px;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1);color:#222;display:block;padding:1.25rem}a.box:hover,a.box:focus{box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px #2e63b8}a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2),0 0 0 1px #2e63b8}.button{background-color:#fff;border-color:#dbdbdb;border-width:1px;color:#363636;cursor:pointer;justify-content:center;padding-bottom:calc(0.375em - 1px);padding-left:.75em;padding-right:.75em;padding-top:calc(0.375em - 1px);text-align:center;white-space:nowrap}.button strong{color:inherit}.button .icon,.button .icon.is-small,.button #documenter .docs-sidebar form.docs-search>input.icon,#documenter .docs-sidebar .button form.docs-search>input.icon,.button .icon.is-medium,.button .icon.is-large{height:1.5em;width:1.5em}.button .icon:first-child:not(:last-child){margin-left:calc(-0.375em - 1px);margin-right:0.1875em}.button .icon:last-child:not(:first-child){margin-left:0.1875em;margin-right:calc(-0.375em - 1px)}.button .icon:first-child:last-child{margin-left:calc(-0.375em - 1px);margin-right:calc(-0.375em - 1px)}.button:hover,.button.is-hovered{border-color:#b5b5b5;color:#363636}.button:focus,.button.is-focused{border-color:#3c5dcd;color:#363636}.button:focus:not(:active),.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.button:active,.button.is-active{border-color:#4a4a4a;color:#363636}.button.is-text{background-color:transparent;border-color:transparent;color:#222;text-decoration:underline}.button.is-text:hover,.button.is-text.is-hovered,.button.is-text:focus,.button.is-text.is-focused{background-color:#f5f5f5;color:#222}.button.is-text:active,.button.is-text.is-active{background-color:#e8e8e8;color:#222}.button.is-text[disabled],fieldset[disabled] .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}.button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}.button.is-white:hover,.button.is-white.is-hovered{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.button.is-white:focus,.button.is-white.is-focused{border-color:transparent;color:#0a0a0a}.button.is-white:focus:not(:active),.button.is-white.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}.button.is-white:active,.button.is-white.is-active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.button.is-white[disabled],fieldset[disabled] .button.is-white{background-color:#fff;border-color:transparent;box-shadow:none}.button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted:hover,.button.is-white.is-inverted.is-hovered{background-color:#000}.button.is-white.is-inverted[disabled],fieldset[disabled] .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}.button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-white.is-outlined:hover,.button.is-white.is-outlined.is-hovered,.button.is-white.is-outlined:focus,.button.is-white.is-outlined.is-focused{background-color:#fff;border-color:#fff;color:#0a0a0a}.button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-white.is-outlined.is-loading:hover::after,.button.is-white.is-outlined.is-loading.is-hovered::after,.button.is-white.is-outlined.is-loading:focus::after,.button.is-white.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-white.is-outlined[disabled],fieldset[disabled] .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-white.is-inverted.is-outlined:hover,.button.is-white.is-inverted.is-outlined.is-hovered,.button.is-white.is-inverted.is-outlined:focus,.button.is-white.is-inverted.is-outlined.is-focused{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-outlined.is-loading:hover::after,.button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-white.is-inverted.is-outlined.is-loading:focus::after,.button.is-white.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}.button.is-black:hover,.button.is-black.is-hovered{background-color:#040404;border-color:transparent;color:#fff}.button.is-black:focus,.button.is-black.is-focused{border-color:transparent;color:#fff}.button.is-black:focus:not(:active),.button.is-black.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}.button.is-black:active,.button.is-black.is-active{background-color:#000;border-color:transparent;color:#fff}.button.is-black[disabled],fieldset[disabled] .button.is-black{background-color:#0a0a0a;border-color:transparent;box-shadow:none}.button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted:hover,.button.is-black.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-black.is-inverted[disabled],fieldset[disabled] .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}.button.is-black.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-black.is-outlined:hover,.button.is-black.is-outlined.is-hovered,.button.is-black.is-outlined:focus,.button.is-black.is-outlined.is-focused{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-black.is-outlined.is-loading:hover::after,.button.is-black.is-outlined.is-loading.is-hovered::after,.button.is-black.is-outlined.is-loading:focus::after,.button.is-black.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-black.is-outlined[disabled],fieldset[disabled] .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-black.is-inverted.is-outlined:hover,.button.is-black.is-inverted.is-outlined.is-hovered,.button.is-black.is-inverted.is-outlined:focus,.button.is-black.is-inverted.is-outlined.is-focused{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-outlined.is-loading:hover::after,.button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-black.is-inverted.is-outlined.is-loading:focus::after,.button.is-black.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-light{background-color:#f5f5f5;border-color:transparent;color:#363636}.button.is-light:hover,.button.is-light.is-hovered{background-color:#eee;border-color:transparent;color:#363636}.button.is-light:focus,.button.is-light.is-focused{border-color:transparent;color:#363636}.button.is-light:focus:not(:active),.button.is-light.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(245,245,245,0.25)}.button.is-light:active,.button.is-light.is-active{background-color:#e8e8e8;border-color:transparent;color:#363636}.button.is-light[disabled],fieldset[disabled] .button.is-light{background-color:#f5f5f5;border-color:transparent;box-shadow:none}.button.is-light.is-inverted{background-color:#363636;color:#f5f5f5}.button.is-light.is-inverted:hover,.button.is-light.is-inverted.is-hovered{background-color:#292929}.button.is-light.is-inverted[disabled],fieldset[disabled] .button.is-light.is-inverted{background-color:#363636;border-color:transparent;box-shadow:none;color:#f5f5f5}.button.is-light.is-loading::after{border-color:transparent transparent #363636 #363636 !important}.button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-light.is-outlined:hover,.button.is-light.is-outlined.is-hovered,.button.is-light.is-outlined:focus,.button.is-light.is-outlined.is-focused{background-color:#f5f5f5;border-color:#f5f5f5;color:#363636}.button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5 !important}.button.is-light.is-outlined.is-loading:hover::after,.button.is-light.is-outlined.is-loading.is-hovered::after,.button.is-light.is-outlined.is-loading:focus::after,.button.is-light.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #363636 #363636 !important}.button.is-light.is-outlined[disabled],fieldset[disabled] .button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-light.is-inverted.is-outlined:hover,.button.is-light.is-inverted.is-outlined.is-hovered,.button.is-light.is-inverted.is-outlined:focus,.button.is-light.is-inverted.is-outlined.is-focused{background-color:#363636;color:#f5f5f5}.button.is-light.is-inverted.is-outlined.is-loading:hover::after,.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-light.is-inverted.is-outlined.is-loading:focus::after,.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #f5f5f5 #f5f5f5 !important}.button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark,.content kbd.button{background-color:#363636;border-color:transparent;color:#f5f5f5}.button.is-dark:hover,.content kbd.button:hover,.button.is-dark.is-hovered,.content kbd.button.is-hovered{background-color:#2f2f2f;border-color:transparent;color:#f5f5f5}.button.is-dark:focus,.content kbd.button:focus,.button.is-dark.is-focused,.content kbd.button.is-focused{border-color:transparent;color:#f5f5f5}.button.is-dark:focus:not(:active),.content kbd.button:focus:not(:active),.button.is-dark.is-focused:not(:active),.content kbd.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(54,54,54,0.25)}.button.is-dark:active,.content kbd.button:active,.button.is-dark.is-active,.content kbd.button.is-active{background-color:#292929;border-color:transparent;color:#f5f5f5}.button.is-dark[disabled],.content kbd.button[disabled],fieldset[disabled] .button.is-dark,fieldset[disabled] .content kbd.button,.content fieldset[disabled] kbd.button{background-color:#363636;border-color:transparent;box-shadow:none}.button.is-dark.is-inverted,.content kbd.button.is-inverted{background-color:#f5f5f5;color:#363636}.button.is-dark.is-inverted:hover,.content kbd.button.is-inverted:hover,.button.is-dark.is-inverted.is-hovered,.content kbd.button.is-inverted.is-hovered{background-color:#e8e8e8}.button.is-dark.is-inverted[disabled],.content kbd.button.is-inverted[disabled],fieldset[disabled] .button.is-dark.is-inverted,fieldset[disabled] .content kbd.button.is-inverted,.content fieldset[disabled] kbd.button.is-inverted{background-color:#f5f5f5;border-color:transparent;box-shadow:none;color:#363636}.button.is-dark.is-loading::after,.content kbd.button.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5 !important}.button.is-dark.is-outlined,.content kbd.button.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-dark.is-outlined:hover,.content kbd.button.is-outlined:hover,.button.is-dark.is-outlined.is-hovered,.content kbd.button.is-outlined.is-hovered,.button.is-dark.is-outlined:focus,.content kbd.button.is-outlined:focus,.button.is-dark.is-outlined.is-focused,.content kbd.button.is-outlined.is-focused{background-color:#363636;border-color:#363636;color:#f5f5f5}.button.is-dark.is-outlined.is-loading::after,.content kbd.button.is-outlined.is-loading::after{border-color:transparent transparent #363636 #363636 !important}.button.is-dark.is-outlined.is-loading:hover::after,.content kbd.button.is-outlined.is-loading:hover::after,.button.is-dark.is-outlined.is-loading.is-hovered::after,.content kbd.button.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-outlined.is-loading:focus::after,.content kbd.button.is-outlined.is-loading:focus::after,.button.is-dark.is-outlined.is-loading.is-focused::after,.content kbd.button.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #f5f5f5 #f5f5f5 !important}.button.is-dark.is-outlined[disabled],.content kbd.button.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-outlined,fieldset[disabled] .content kbd.button.is-outlined,.content fieldset[disabled] kbd.button.is-outlined{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark.is-inverted.is-outlined,.content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-dark.is-inverted.is-outlined:hover,.content kbd.button.is-inverted.is-outlined:hover,.button.is-dark.is-inverted.is-outlined.is-hovered,.content kbd.button.is-inverted.is-outlined.is-hovered,.button.is-dark.is-inverted.is-outlined:focus,.content kbd.button.is-inverted.is-outlined:focus,.button.is-dark.is-inverted.is-outlined.is-focused,.content kbd.button.is-inverted.is-outlined.is-focused{background-color:#f5f5f5;color:#363636}.button.is-dark.is-inverted.is-outlined.is-loading:hover::after,.content kbd.button.is-inverted.is-outlined.is-loading:hover::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,.content kbd.button.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-inverted.is-outlined.is-loading:focus::after,.content kbd.button.is-inverted.is-outlined.is-loading:focus::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,.content kbd.button.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #363636 #363636 !important}.button.is-dark.is-inverted.is-outlined[disabled],.content kbd.button.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-inverted.is-outlined,fieldset[disabled] .content kbd.button.is-inverted.is-outlined,.content fieldset[disabled] kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-primary,.docstring>section>a.button.docs-sourcelink{background-color:#4eb5de;border-color:transparent;color:#fff}.button.is-primary:hover,.docstring>section>a.button.docs-sourcelink:hover,.button.is-primary.is-hovered,.docstring>section>a.button.is-hovered.docs-sourcelink{background-color:#43b1dc;border-color:transparent;color:#fff}.button.is-primary:focus,.docstring>section>a.button.docs-sourcelink:focus,.button.is-primary.is-focused,.docstring>section>a.button.is-focused.docs-sourcelink{border-color:transparent;color:#fff}.button.is-primary:focus:not(:active),.docstring>section>a.button.docs-sourcelink:focus:not(:active),.button.is-primary.is-focused:not(:active),.docstring>section>a.button.is-focused.docs-sourcelink:not(:active){box-shadow:0 0 0 0.125em rgba(78,181,222,0.25)}.button.is-primary:active,.docstring>section>a.button.docs-sourcelink:active,.button.is-primary.is-active,.docstring>section>a.button.is-active.docs-sourcelink{background-color:#39acda;border-color:transparent;color:#fff}.button.is-primary[disabled],.docstring>section>a.button.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary,fieldset[disabled] .docstring>section>a.button.docs-sourcelink{background-color:#4eb5de;border-color:transparent;box-shadow:none}.button.is-primary.is-inverted,.docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;color:#4eb5de}.button.is-primary.is-inverted:hover,.docstring>section>a.button.is-inverted.docs-sourcelink:hover,.button.is-primary.is-inverted.is-hovered,.docstring>section>a.button.is-inverted.is-hovered.docs-sourcelink{background-color:#f2f2f2}.button.is-primary.is-inverted[disabled],.docstring>section>a.button.is-inverted.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary.is-inverted,fieldset[disabled] .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;border-color:transparent;box-shadow:none;color:#4eb5de}.button.is-primary.is-loading::after,.docstring>section>a.button.is-loading.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}.button.is-primary.is-outlined,.docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#4eb5de;color:#4eb5de}.button.is-primary.is-outlined:hover,.docstring>section>a.button.is-outlined.docs-sourcelink:hover,.button.is-primary.is-outlined.is-hovered,.docstring>section>a.button.is-outlined.is-hovered.docs-sourcelink,.button.is-primary.is-outlined:focus,.docstring>section>a.button.is-outlined.docs-sourcelink:focus,.button.is-primary.is-outlined.is-focused,.docstring>section>a.button.is-outlined.is-focused.docs-sourcelink{background-color:#4eb5de;border-color:#4eb5de;color:#fff}.button.is-primary.is-outlined.is-loading::after,.docstring>section>a.button.is-outlined.is-loading.docs-sourcelink::after{border-color:transparent transparent #4eb5de #4eb5de !important}.button.is-primary.is-outlined.is-loading:hover::after,.docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:hover::after,.button.is-primary.is-outlined.is-loading.is-hovered::after,.docstring>section>a.button.is-outlined.is-loading.is-hovered.docs-sourcelink::after,.button.is-primary.is-outlined.is-loading:focus::after,.docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:focus::after,.button.is-primary.is-outlined.is-loading.is-focused::after,.docstring>section>a.button.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}.button.is-primary.is-outlined[disabled],.docstring>section>a.button.is-outlined.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary.is-outlined,fieldset[disabled] .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#4eb5de;box-shadow:none;color:#4eb5de}.button.is-primary.is-inverted.is-outlined,.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;color:#fff}.button.is-primary.is-inverted.is-outlined:hover,.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:hover,.button.is-primary.is-inverted.is-outlined.is-hovered,.docstring>section>a.button.is-inverted.is-outlined.is-hovered.docs-sourcelink,.button.is-primary.is-inverted.is-outlined:focus,.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:focus,.button.is-primary.is-inverted.is-outlined.is-focused,.docstring>section>a.button.is-inverted.is-outlined.is-focused.docs-sourcelink{background-color:#fff;color:#4eb5de}.button.is-primary.is-inverted.is-outlined.is-loading:hover::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:hover::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.is-hovered.docs-sourcelink::after,.button.is-primary.is-inverted.is-outlined.is-loading:focus::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:focus::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #4eb5de #4eb5de !important}.button.is-primary.is-inverted.is-outlined[disabled],.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary.is-inverted.is-outlined,fieldset[disabled] .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-link{background-color:#2e63b8;border-color:transparent;color:#fff}.button.is-link:hover,.button.is-link.is-hovered{background-color:#2b5eae;border-color:transparent;color:#fff}.button.is-link:focus,.button.is-link.is-focused{border-color:transparent;color:#fff}.button.is-link:focus:not(:active),.button.is-link.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.button.is-link:active,.button.is-link.is-active{background-color:#2958a4;border-color:transparent;color:#fff}.button.is-link[disabled],fieldset[disabled] .button.is-link{background-color:#2e63b8;border-color:transparent;box-shadow:none}.button.is-link.is-inverted{background-color:#fff;color:#2e63b8}.button.is-link.is-inverted:hover,.button.is-link.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-link.is-inverted[disabled],fieldset[disabled] .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#2e63b8}.button.is-link.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-link.is-outlined{background-color:transparent;border-color:#2e63b8;color:#2e63b8}.button.is-link.is-outlined:hover,.button.is-link.is-outlined.is-hovered,.button.is-link.is-outlined:focus,.button.is-link.is-outlined.is-focused{background-color:#2e63b8;border-color:#2e63b8;color:#fff}.button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #2e63b8 #2e63b8 !important}.button.is-link.is-outlined.is-loading:hover::after,.button.is-link.is-outlined.is-loading.is-hovered::after,.button.is-link.is-outlined.is-loading:focus::after,.button.is-link.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-link.is-outlined[disabled],fieldset[disabled] .button.is-link.is-outlined{background-color:transparent;border-color:#2e63b8;box-shadow:none;color:#2e63b8}.button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-link.is-inverted.is-outlined:hover,.button.is-link.is-inverted.is-outlined.is-hovered,.button.is-link.is-inverted.is-outlined:focus,.button.is-link.is-inverted.is-outlined.is-focused{background-color:#fff;color:#2e63b8}.button.is-link.is-inverted.is-outlined.is-loading:hover::after,.button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-link.is-inverted.is-outlined.is-loading:focus::after,.button.is-link.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #2e63b8 #2e63b8 !important}.button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-info{background-color:#209cee;border-color:transparent;color:#fff}.button.is-info:hover,.button.is-info.is-hovered{background-color:#1497ed;border-color:transparent;color:#fff}.button.is-info:focus,.button.is-info.is-focused{border-color:transparent;color:#fff}.button.is-info:focus:not(:active),.button.is-info.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(32,156,238,0.25)}.button.is-info:active,.button.is-info.is-active{background-color:#1190e3;border-color:transparent;color:#fff}.button.is-info[disabled],fieldset[disabled] .button.is-info{background-color:#209cee;border-color:transparent;box-shadow:none}.button.is-info.is-inverted{background-color:#fff;color:#209cee}.button.is-info.is-inverted:hover,.button.is-info.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-info.is-inverted[disabled],fieldset[disabled] .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#209cee}.button.is-info.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-info.is-outlined{background-color:transparent;border-color:#209cee;color:#209cee}.button.is-info.is-outlined:hover,.button.is-info.is-outlined.is-hovered,.button.is-info.is-outlined:focus,.button.is-info.is-outlined.is-focused{background-color:#209cee;border-color:#209cee;color:#fff}.button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #209cee #209cee !important}.button.is-info.is-outlined.is-loading:hover::after,.button.is-info.is-outlined.is-loading.is-hovered::after,.button.is-info.is-outlined.is-loading:focus::after,.button.is-info.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-info.is-outlined[disabled],fieldset[disabled] .button.is-info.is-outlined{background-color:transparent;border-color:#209cee;box-shadow:none;color:#209cee}.button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-info.is-inverted.is-outlined:hover,.button.is-info.is-inverted.is-outlined.is-hovered,.button.is-info.is-inverted.is-outlined:focus,.button.is-info.is-inverted.is-outlined.is-focused{background-color:#fff;color:#209cee}.button.is-info.is-inverted.is-outlined.is-loading:hover::after,.button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-info.is-inverted.is-outlined.is-loading:focus::after,.button.is-info.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #209cee #209cee !important}.button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-success{background-color:#22c35b;border-color:transparent;color:#fff}.button.is-success:hover,.button.is-success.is-hovered{background-color:#20b856;border-color:transparent;color:#fff}.button.is-success:focus,.button.is-success.is-focused{border-color:transparent;color:#fff}.button.is-success:focus:not(:active),.button.is-success.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(34,195,91,0.25)}.button.is-success:active,.button.is-success.is-active{background-color:#1ead51;border-color:transparent;color:#fff}.button.is-success[disabled],fieldset[disabled] .button.is-success{background-color:#22c35b;border-color:transparent;box-shadow:none}.button.is-success.is-inverted{background-color:#fff;color:#22c35b}.button.is-success.is-inverted:hover,.button.is-success.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-success.is-inverted[disabled],fieldset[disabled] .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#22c35b}.button.is-success.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-success.is-outlined{background-color:transparent;border-color:#22c35b;color:#22c35b}.button.is-success.is-outlined:hover,.button.is-success.is-outlined.is-hovered,.button.is-success.is-outlined:focus,.button.is-success.is-outlined.is-focused{background-color:#22c35b;border-color:#22c35b;color:#fff}.button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #22c35b #22c35b !important}.button.is-success.is-outlined.is-loading:hover::after,.button.is-success.is-outlined.is-loading.is-hovered::after,.button.is-success.is-outlined.is-loading:focus::after,.button.is-success.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-success.is-outlined[disabled],fieldset[disabled] .button.is-success.is-outlined{background-color:transparent;border-color:#22c35b;box-shadow:none;color:#22c35b}.button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-success.is-inverted.is-outlined:hover,.button.is-success.is-inverted.is-outlined.is-hovered,.button.is-success.is-inverted.is-outlined:focus,.button.is-success.is-inverted.is-outlined.is-focused{background-color:#fff;color:#22c35b}.button.is-success.is-inverted.is-outlined.is-loading:hover::after,.button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-success.is-inverted.is-outlined.is-loading:focus::after,.button.is-success.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #22c35b #22c35b !important}.button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-warning{background-color:#ffdd57;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning:hover,.button.is-warning.is-hovered{background-color:#ffda4a;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning:focus,.button.is-warning.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning:focus:not(:active),.button.is-warning.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,221,87,0.25)}.button.is-warning:active,.button.is-warning.is-active{background-color:#ffd83e;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning[disabled],fieldset[disabled] .button.is-warning{background-color:#ffdd57;border-color:transparent;box-shadow:none}.button.is-warning.is-inverted{background-color:rgba(0,0,0,0.7);color:#ffdd57}.button.is-warning.is-inverted:hover,.button.is-warning.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}.button.is-warning.is-inverted[disabled],fieldset[disabled] .button.is-warning.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#ffdd57}.button.is-warning.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-warning.is-outlined{background-color:transparent;border-color:#ffdd57;color:#ffdd57}.button.is-warning.is-outlined:hover,.button.is-warning.is-outlined.is-hovered,.button.is-warning.is-outlined:focus,.button.is-warning.is-outlined.is-focused{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,0.7)}.button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ffdd57 #ffdd57 !important}.button.is-warning.is-outlined.is-loading:hover::after,.button.is-warning.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-outlined.is-loading:focus::after,.button.is-warning.is-outlined.is-loading.is-focused::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-warning.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-outlined{background-color:transparent;border-color:#ffdd57;box-shadow:none;color:#ffdd57}.button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}.button.is-warning.is-inverted.is-outlined:hover,.button.is-warning.is-inverted.is-outlined.is-hovered,.button.is-warning.is-inverted.is-outlined:focus,.button.is-warning.is-inverted.is-outlined.is-focused{background-color:rgba(0,0,0,0.7);color:#ffdd57}.button.is-warning.is-inverted.is-outlined.is-loading:hover::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-inverted.is-outlined.is-loading:focus::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ffdd57 #ffdd57 !important}.button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}.button.is-danger{background-color:#da0b00;border-color:transparent;color:#fff}.button.is-danger:hover,.button.is-danger.is-hovered{background-color:#cd0a00;border-color:transparent;color:#fff}.button.is-danger:focus,.button.is-danger.is-focused{border-color:transparent;color:#fff}.button.is-danger:focus:not(:active),.button.is-danger.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(218,11,0,0.25)}.button.is-danger:active,.button.is-danger.is-active{background-color:#c10a00;border-color:transparent;color:#fff}.button.is-danger[disabled],fieldset[disabled] .button.is-danger{background-color:#da0b00;border-color:transparent;box-shadow:none}.button.is-danger.is-inverted{background-color:#fff;color:#da0b00}.button.is-danger.is-inverted:hover,.button.is-danger.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-danger.is-inverted[disabled],fieldset[disabled] .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#da0b00}.button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-danger.is-outlined{background-color:transparent;border-color:#da0b00;color:#da0b00}.button.is-danger.is-outlined:hover,.button.is-danger.is-outlined.is-hovered,.button.is-danger.is-outlined:focus,.button.is-danger.is-outlined.is-focused{background-color:#da0b00;border-color:#da0b00;color:#fff}.button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #da0b00 #da0b00 !important}.button.is-danger.is-outlined.is-loading:hover::after,.button.is-danger.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-outlined.is-loading:focus::after,.button.is-danger.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-danger.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-outlined{background-color:transparent;border-color:#da0b00;box-shadow:none;color:#da0b00}.button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-danger.is-inverted.is-outlined:hover,.button.is-danger.is-inverted.is-outlined.is-hovered,.button.is-danger.is-inverted.is-outlined:focus,.button.is-danger.is-inverted.is-outlined.is-focused{background-color:#fff;color:#da0b00}.button.is-danger.is-inverted.is-outlined.is-loading:hover::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-inverted.is-outlined.is-loading:focus::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #da0b00 #da0b00 !important}.button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-small,#documenter .docs-sidebar form.docs-search>input.button{border-radius:2px;font-size:.75rem}.button.is-normal{font-size:1rem}.button.is-medium{font-size:1.25rem}.button.is-large{font-size:1.5rem}.button[disabled],fieldset[disabled] .button{background-color:#fff;border-color:#dbdbdb;box-shadow:none;opacity:.5}.button.is-fullwidth{display:flex;width:100%}.button.is-loading{color:transparent !important;pointer-events:none}.button.is-loading::after{position:absolute;left:calc(50% - (1em / 2));top:calc(50% - (1em / 2));position:absolute !important}.button.is-static{background-color:#f5f5f5;border-color:#dbdbdb;color:#6b6b6b;box-shadow:none;pointer-events:none}.button.is-rounded,#documenter .docs-sidebar form.docs-search>input.button{border-radius:290486px;padding-left:1em;padding-right:1em}.buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.buttons .button{margin-bottom:0.5rem}.buttons .button:not(:last-child):not(.is-fullwidth){margin-right:0.5rem}.buttons:last-child{margin-bottom:-0.5rem}.buttons:not(:last-child){margin-bottom:1rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){border-radius:2px;font-size:.75rem}.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}.buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}.buttons.has-addons .button:last-child{margin-right:0}.buttons.has-addons .button:hover,.buttons.has-addons .button.is-hovered{z-index:2}.buttons.has-addons .button:focus,.buttons.has-addons .button.is-focused,.buttons.has-addons .button:active,.buttons.has-addons .button.is-active,.buttons.has-addons .button.is-selected{z-index:3}.buttons.has-addons .button:focus:hover,.buttons.has-addons .button.is-focused:hover,.buttons.has-addons .button:active:hover,.buttons.has-addons .button.is-active:hover,.buttons.has-addons .button.is-selected:hover{z-index:4}.buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}.buttons.is-centered{justify-content:center}.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}.buttons.is-right{justify-content:flex-end}.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}.container{flex-grow:1;margin:0 auto;position:relative;width:auto}@media screen and (min-width: 1056px){.container{max-width:992px}.container.is-fluid{margin-left:32px;margin-right:32px;max-width:none}}@media screen and (max-width: 1215px){.container.is-widescreen{max-width:1152px}}@media screen and (max-width: 1407px){.container.is-fullhd{max-width:1344px}}@media screen and (min-width: 1216px){.container{max-width:1152px}}@media screen and (min-width: 1408px){.container{max-width:1344px}}.content li+li{margin-top:0.25em}.content p:not(:last-child),.content dl:not(:last-child),.content ol:not(:last-child),.content ul:not(:last-child),.content blockquote:not(:last-child),.content pre:not(:last-child),.content table:not(:last-child){margin-bottom:1em}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{color:#222;font-weight:600;line-height:1.125}.content h1{font-size:2em;margin-bottom:0.5em}.content h1:not(:first-child){margin-top:1em}.content h2{font-size:1.75em;margin-bottom:0.5714em}.content h2:not(:first-child){margin-top:1.1428em}.content h3{font-size:1.5em;margin-bottom:0.6666em}.content h3:not(:first-child){margin-top:1.3333em}.content h4{font-size:1.25em;margin-bottom:0.8em}.content h5{font-size:1.125em;margin-bottom:0.8888em}.content h6{font-size:1em;margin-bottom:1em}.content blockquote{background-color:#f5f5f5;border-left:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol{list-style-position:outside;margin-left:2em;margin-top:1em}.content ol:not([type]){list-style-type:decimal}.content ol.is-lower-alpha:not([type]){list-style-type:lower-alpha}.content ol.is-lower-roman:not([type]){list-style-type:lower-roman}.content ol.is-upper-alpha:not([type]){list-style-type:upper-alpha}.content ol.is-upper-roman:not([type]){list-style-type:upper-roman}.content ul{list-style:disc outside;margin-left:2em;margin-top:1em}.content ul ul{list-style-type:circle;margin-top:0.5em}.content ul ul ul{list-style-type:square}.content dd{margin-left:2em}.content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child){margin-bottom:2em}.content figure img{display:inline-block}.content figure figcaption{font-style:italic}.content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:0;white-space:pre;word-wrap:normal}.content sup,.content sub{font-size:75%}.content table{width:100%}.content table td,.content table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}.content table th{color:#222}.content table th:not([align]){text-align:left}.content table thead td,.content table thead th{border-width:0 0 2px;color:#222}.content table tfoot td,.content table tfoot th{border-width:2px 0 0;color:#222}.content table tbody tr:last-child td,.content table tbody tr:last-child th{border-bottom-width:0}.content .tabs li+li{margin-top:0}.content.is-small,#documenter .docs-sidebar form.docs-search>input.content{font-size:.75rem}.content.is-medium{font-size:1.25rem}.content.is-large{font-size:1.5rem}.icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}.icon.is-small,#documenter .docs-sidebar form.docs-search>input.icon{height:1rem;width:1rem}.icon.is-medium{height:2rem;width:2rem}.icon.is-large{height:3rem;width:3rem}.image,#documenter .docs-sidebar .docs-logo>img{display:block;position:relative}.image img,#documenter .docs-sidebar .docs-logo>img img{display:block;height:auto;width:100%}.image img.is-rounded,#documenter .docs-sidebar .docs-logo>img img.is-rounded{border-radius:290486px}.image.is-square img,#documenter .docs-sidebar .docs-logo>img.is-square img,.image.is-square .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,.image.is-1by1 img,#documenter .docs-sidebar .docs-logo>img.is-1by1 img,.image.is-1by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,.image.is-5by4 img,#documenter .docs-sidebar .docs-logo>img.is-5by4 img,.image.is-5by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,.image.is-4by3 img,#documenter .docs-sidebar .docs-logo>img.is-4by3 img,.image.is-4by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,.image.is-3by2 img,#documenter .docs-sidebar .docs-logo>img.is-3by2 img,.image.is-3by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,.image.is-5by3 img,#documenter .docs-sidebar .docs-logo>img.is-5by3 img,.image.is-5by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,.image.is-16by9 img,#documenter .docs-sidebar .docs-logo>img.is-16by9 img,.image.is-16by9 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,.image.is-2by1 img,#documenter .docs-sidebar .docs-logo>img.is-2by1 img,.image.is-2by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,.image.is-3by1 img,#documenter .docs-sidebar .docs-logo>img.is-3by1 img,.image.is-3by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,.image.is-4by5 img,#documenter .docs-sidebar .docs-logo>img.is-4by5 img,.image.is-4by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,.image.is-3by4 img,#documenter .docs-sidebar .docs-logo>img.is-3by4 img,.image.is-3by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,.image.is-2by3 img,#documenter .docs-sidebar .docs-logo>img.is-2by3 img,.image.is-2by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,.image.is-3by5 img,#documenter .docs-sidebar .docs-logo>img.is-3by5 img,.image.is-3by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,.image.is-9by16 img,#documenter .docs-sidebar .docs-logo>img.is-9by16 img,.image.is-9by16 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,.image.is-1by2 img,#documenter .docs-sidebar .docs-logo>img.is-1by2 img,.image.is-1by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,.image.is-1by3 img,#documenter .docs-sidebar .docs-logo>img.is-1by3 img,.image.is-1by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio{height:100%;width:100%}.image.is-square,#documenter .docs-sidebar .docs-logo>img.is-square,.image.is-1by1,#documenter .docs-sidebar .docs-logo>img.is-1by1{padding-top:100%}.image.is-5by4,#documenter .docs-sidebar .docs-logo>img.is-5by4{padding-top:80%}.image.is-4by3,#documenter .docs-sidebar .docs-logo>img.is-4by3{padding-top:75%}.image.is-3by2,#documenter .docs-sidebar .docs-logo>img.is-3by2{padding-top:66.6666%}.image.is-5by3,#documenter .docs-sidebar .docs-logo>img.is-5by3{padding-top:60%}.image.is-16by9,#documenter .docs-sidebar .docs-logo>img.is-16by9{padding-top:56.25%}.image.is-2by1,#documenter .docs-sidebar .docs-logo>img.is-2by1{padding-top:50%}.image.is-3by1,#documenter .docs-sidebar .docs-logo>img.is-3by1{padding-top:33.3333%}.image.is-4by5,#documenter .docs-sidebar .docs-logo>img.is-4by5{padding-top:125%}.image.is-3by4,#documenter .docs-sidebar .docs-logo>img.is-3by4{padding-top:133.3333%}.image.is-2by3,#documenter .docs-sidebar .docs-logo>img.is-2by3{padding-top:150%}.image.is-3by5,#documenter .docs-sidebar .docs-logo>img.is-3by5{padding-top:166.6666%}.image.is-9by16,#documenter .docs-sidebar .docs-logo>img.is-9by16{padding-top:177.7777%}.image.is-1by2,#documenter .docs-sidebar .docs-logo>img.is-1by2{padding-top:200%}.image.is-1by3,#documenter .docs-sidebar .docs-logo>img.is-1by3{padding-top:300%}.image.is-16x16,#documenter .docs-sidebar .docs-logo>img.is-16x16{height:16px;width:16px}.image.is-24x24,#documenter .docs-sidebar .docs-logo>img.is-24x24{height:24px;width:24px}.image.is-32x32,#documenter .docs-sidebar .docs-logo>img.is-32x32{height:32px;width:32px}.image.is-48x48,#documenter .docs-sidebar .docs-logo>img.is-48x48{height:48px;width:48px}.image.is-64x64,#documenter .docs-sidebar .docs-logo>img.is-64x64{height:64px;width:64px}.image.is-96x96,#documenter .docs-sidebar .docs-logo>img.is-96x96{height:96px;width:96px}.image.is-128x128,#documenter .docs-sidebar .docs-logo>img.is-128x128{height:128px;width:128px}.notification{background-color:#f5f5f5;border-radius:4px;padding:1.25rem 2.5rem 1.25rem 1.5rem;position:relative}.notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}.notification strong{color:currentColor}.notification code,.notification pre{background:#fff}.notification pre code{background:transparent}.notification>.delete{position:absolute;right:0.5rem;top:0.5rem}.notification .title,.notification .subtitle,.notification .content{color:currentColor}.notification.is-white{background-color:#fff;color:#0a0a0a}.notification.is-black{background-color:#0a0a0a;color:#fff}.notification.is-light{background-color:#f5f5f5;color:#363636}.notification.is-dark,.content kbd.notification{background-color:#363636;color:#f5f5f5}.notification.is-primary,.docstring>section>a.notification.docs-sourcelink{background-color:#4eb5de;color:#fff}.notification.is-link{background-color:#2e63b8;color:#fff}.notification.is-info{background-color:#209cee;color:#fff}.notification.is-success{background-color:#22c35b;color:#fff}.notification.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.notification.is-danger{background-color:#da0b00;color:#fff}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:290486px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#dbdbdb}.progress::-webkit-progress-value{background-color:#222}.progress::-moz-progress-bar{background-color:#222}.progress::-ms-fill{background-color:#222;border:none}.progress.is-white::-webkit-progress-value{background-color:#fff}.progress.is-white::-moz-progress-bar{background-color:#fff}.progress.is-white::-ms-fill{background-color:#fff}.progress.is-white:indeterminate{background-image:linear-gradient(to right, #fff 30%, #dbdbdb 30%)}.progress.is-black::-webkit-progress-value{background-color:#0a0a0a}.progress.is-black::-moz-progress-bar{background-color:#0a0a0a}.progress.is-black::-ms-fill{background-color:#0a0a0a}.progress.is-black:indeterminate{background-image:linear-gradient(to right, #0a0a0a 30%, #dbdbdb 30%)}.progress.is-light::-webkit-progress-value{background-color:#f5f5f5}.progress.is-light::-moz-progress-bar{background-color:#f5f5f5}.progress.is-light::-ms-fill{background-color:#f5f5f5}.progress.is-light:indeterminate{background-image:linear-gradient(to right, #f5f5f5 30%, #dbdbdb 30%)}.progress.is-dark::-webkit-progress-value,.content kbd.progress::-webkit-progress-value{background-color:#363636}.progress.is-dark::-moz-progress-bar,.content kbd.progress::-moz-progress-bar{background-color:#363636}.progress.is-dark::-ms-fill,.content kbd.progress::-ms-fill{background-color:#363636}.progress.is-dark:indeterminate,.content kbd.progress:indeterminate{background-image:linear-gradient(to right, #363636 30%, #dbdbdb 30%)}.progress.is-primary::-webkit-progress-value,.docstring>section>a.progress.docs-sourcelink::-webkit-progress-value{background-color:#4eb5de}.progress.is-primary::-moz-progress-bar,.docstring>section>a.progress.docs-sourcelink::-moz-progress-bar{background-color:#4eb5de}.progress.is-primary::-ms-fill,.docstring>section>a.progress.docs-sourcelink::-ms-fill{background-color:#4eb5de}.progress.is-primary:indeterminate,.docstring>section>a.progress.docs-sourcelink:indeterminate{background-image:linear-gradient(to right, #4eb5de 30%, #dbdbdb 30%)}.progress.is-link::-webkit-progress-value{background-color:#2e63b8}.progress.is-link::-moz-progress-bar{background-color:#2e63b8}.progress.is-link::-ms-fill{background-color:#2e63b8}.progress.is-link:indeterminate{background-image:linear-gradient(to right, #2e63b8 30%, #dbdbdb 30%)}.progress.is-info::-webkit-progress-value{background-color:#209cee}.progress.is-info::-moz-progress-bar{background-color:#209cee}.progress.is-info::-ms-fill{background-color:#209cee}.progress.is-info:indeterminate{background-image:linear-gradient(to right, #209cee 30%, #dbdbdb 30%)}.progress.is-success::-webkit-progress-value{background-color:#22c35b}.progress.is-success::-moz-progress-bar{background-color:#22c35b}.progress.is-success::-ms-fill{background-color:#22c35b}.progress.is-success:indeterminate{background-image:linear-gradient(to right, #22c35b 30%, #dbdbdb 30%)}.progress.is-warning::-webkit-progress-value{background-color:#ffdd57}.progress.is-warning::-moz-progress-bar{background-color:#ffdd57}.progress.is-warning::-ms-fill{background-color:#ffdd57}.progress.is-warning:indeterminate{background-image:linear-gradient(to right, #ffdd57 30%, #dbdbdb 30%)}.progress.is-danger::-webkit-progress-value{background-color:#da0b00}.progress.is-danger::-moz-progress-bar{background-color:#da0b00}.progress.is-danger::-ms-fill{background-color:#da0b00}.progress.is-danger:indeterminate{background-image:linear-gradient(to right, #da0b00 30%, #dbdbdb 30%)}.progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#dbdbdb;background-image:linear-gradient(to right, #222 30%, #dbdbdb 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}.progress:indeterminate::-webkit-progress-bar{background-color:transparent}.progress:indeterminate::-moz-progress-bar{background-color:transparent}.progress.is-small,#documenter .docs-sidebar form.docs-search>input.progress{height:.75rem}.progress.is-medium{height:1.25rem}.progress.is-large{height:1.5rem}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}.table{background-color:#fff;color:#363636}.table td,.table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}.table td.is-white,.table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.table td.is-black,.table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.table td.is-light,.table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:#363636}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#f5f5f5}.table td.is-primary,.table th.is-primary{background-color:#4eb5de;border-color:#4eb5de;color:#fff}.table td.is-link,.table th.is-link{background-color:#2e63b8;border-color:#2e63b8;color:#fff}.table td.is-info,.table th.is-info{background-color:#209cee;border-color:#209cee;color:#fff}.table td.is-success,.table th.is-success{background-color:#22c35b;border-color:#22c35b;color:#fff}.table td.is-warning,.table th.is-warning{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,0.7)}.table td.is-danger,.table th.is-danger{background-color:#da0b00;border-color:#da0b00;color:#fff}.table td.is-narrow,.table th.is-narrow{white-space:nowrap;width:1%}.table td.is-selected,.table th.is-selected{background-color:#4eb5de;color:#fff}.table td.is-selected a,.table td.is-selected strong,.table th.is-selected a,.table th.is-selected strong{color:currentColor}.table th{color:#222}.table th:not([align]){text-align:left}.table tr.is-selected{background-color:#4eb5de;color:#fff}.table tr.is-selected a,.table tr.is-selected strong{color:currentColor}.table tr.is-selected td,.table tr.is-selected th{border-color:#fff;color:currentColor}.table thead{background-color:rgba(0,0,0,0)}.table thead td,.table thead th{border-width:0 0 2px;color:#222}.table tfoot{background-color:rgba(0,0,0,0)}.table tfoot td,.table tfoot th{border-width:2px 0 0;color:#222}.table tbody{background-color:rgba(0,0,0,0)}.table tbody tr:last-child td,.table tbody tr:last-child th{border-bottom-width:0}.table.is-bordered td,.table.is-bordered th{border-width:1px}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th{border-bottom-width:1px}.table.is-fullwidth{width:100%}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#f5f5f5}.table.is-narrow td,.table.is-narrow th{padding:0.25em 0.5em}.table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#fafafa}.table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}.tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.tags .tag,.tags .content kbd,.content .tags kbd,.tags .docstring>section>a.docs-sourcelink{margin-bottom:0.5rem}.tags .tag:not(:last-child),.tags .content kbd:not(:last-child),.content .tags kbd:not(:last-child),.tags .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0.5rem}.tags:last-child{margin-bottom:-0.5rem}.tags:not(:last-child){margin-bottom:1rem}.tags.are-medium .tag:not(.is-normal):not(.is-large),.tags.are-medium .content kbd:not(.is-normal):not(.is-large),.content .tags.are-medium kbd:not(.is-normal):not(.is-large),.tags.are-medium .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-large){font-size:1rem}.tags.are-large .tag:not(.is-normal):not(.is-medium),.tags.are-large .content kbd:not(.is-normal):not(.is-medium),.content .tags.are-large kbd:not(.is-normal):not(.is-medium),.tags.are-large .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-medium){font-size:1.25rem}.tags.is-centered{justify-content:center}.tags.is-centered .tag,.tags.is-centered .content kbd,.content .tags.is-centered kbd,.tags.is-centered .docstring>section>a.docs-sourcelink{margin-right:0.25rem;margin-left:0.25rem}.tags.is-right{justify-content:flex-end}.tags.is-right .tag:not(:first-child),.tags.is-right .content kbd:not(:first-child),.content .tags.is-right kbd:not(:first-child),.tags.is-right .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0.5rem}.tags.is-right .tag:not(:last-child),.tags.is-right .content kbd:not(:last-child),.content .tags.is-right kbd:not(:last-child),.tags.is-right .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0}.tags.has-addons .tag,.tags.has-addons .content kbd,.content .tags.has-addons kbd,.tags.has-addons .docstring>section>a.docs-sourcelink{margin-right:0}.tags.has-addons .tag:not(:first-child),.tags.has-addons .content kbd:not(:first-child),.content .tags.has-addons kbd:not(:first-child),.tags.has-addons .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0;border-bottom-left-radius:0;border-top-left-radius:0}.tags.has-addons .tag:not(:last-child),.tags.has-addons .content kbd:not(:last-child),.content .tags.has-addons kbd:not(:last-child),.tags.has-addons .docstring>section>a.docs-sourcelink:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.tag:not(body),.content kbd:not(body),.docstring>section>a.docs-sourcelink:not(body){align-items:center;background-color:#f5f5f5;border-radius:4px;color:#222;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:0.75em;padding-right:0.75em;white-space:nowrap}.tag:not(body) .delete,.content kbd:not(body) .delete,.docstring>section>a.docs-sourcelink:not(body) .delete{margin-left:0.25rem;margin-right:-0.375rem}.tag.is-white:not(body),.content kbd.is-white:not(body),.docstring>section>a.docs-sourcelink.is-white:not(body){background-color:#fff;color:#0a0a0a}.tag.is-black:not(body),.content kbd.is-black:not(body),.docstring>section>a.docs-sourcelink.is-black:not(body){background-color:#0a0a0a;color:#fff}.tag.is-light:not(body),.content kbd.is-light:not(body),.docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#f5f5f5;color:#363636}.tag.is-dark:not(body),.content kbd:not(body),.docstring>section>a.docs-sourcelink.is-dark:not(body),.content .docstring>section>kbd:not(body){background-color:#363636;color:#f5f5f5}.tag.is-primary:not(body),.content kbd.is-primary:not(body),.docstring>section>a.docs-sourcelink:not(body){background-color:#4eb5de;color:#fff}.tag.is-link:not(body),.content kbd.is-link:not(body),.docstring>section>a.docs-sourcelink.is-link:not(body){background-color:#2e63b8;color:#fff}.tag.is-info:not(body),.content kbd.is-info:not(body),.docstring>section>a.docs-sourcelink.is-info:not(body){background-color:#209cee;color:#fff}.tag.is-success:not(body),.content kbd.is-success:not(body),.docstring>section>a.docs-sourcelink.is-success:not(body){background-color:#22c35b;color:#fff}.tag.is-warning:not(body),.content kbd.is-warning:not(body),.docstring>section>a.docs-sourcelink.is-warning:not(body){background-color:#ffdd57;color:rgba(0,0,0,0.7)}.tag.is-danger:not(body),.content kbd.is-danger:not(body),.docstring>section>a.docs-sourcelink.is-danger:not(body){background-color:#da0b00;color:#fff}.tag.is-normal:not(body),.content kbd.is-normal:not(body),.docstring>section>a.docs-sourcelink.is-normal:not(body){font-size:.75rem}.tag.is-medium:not(body),.content kbd.is-medium:not(body),.docstring>section>a.docs-sourcelink.is-medium:not(body){font-size:1rem}.tag.is-large:not(body),.content kbd.is-large:not(body),.docstring>section>a.docs-sourcelink.is-large:not(body){font-size:1.25rem}.tag:not(body) .icon:first-child:not(:last-child),.content kbd:not(body) .icon:first-child:not(:last-child),.docstring>section>a.docs-sourcelink:not(body) .icon:first-child:not(:last-child){margin-left:-0.375em;margin-right:0.1875em}.tag:not(body) .icon:last-child:not(:first-child),.content kbd:not(body) .icon:last-child:not(:first-child),.docstring>section>a.docs-sourcelink:not(body) .icon:last-child:not(:first-child){margin-left:0.1875em;margin-right:-0.375em}.tag:not(body) .icon:first-child:last-child,.content kbd:not(body) .icon:first-child:last-child,.docstring>section>a.docs-sourcelink:not(body) .icon:first-child:last-child{margin-left:-0.375em;margin-right:-0.375em}.tag.is-delete:not(body),.content kbd.is-delete:not(body),.docstring>section>a.docs-sourcelink.is-delete:not(body){margin-left:1px;padding:0;position:relative;width:2em}.tag.is-delete:not(body)::before,.content kbd.is-delete:not(body)::before,.docstring>section>a.docs-sourcelink.is-delete:not(body)::before,.tag.is-delete:not(body)::after,.content kbd.is-delete:not(body)::after,.docstring>section>a.docs-sourcelink.is-delete:not(body)::after{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.tag.is-delete:not(body)::before,.content kbd.is-delete:not(body)::before,.docstring>section>a.docs-sourcelink.is-delete:not(body)::before{height:1px;width:50%}.tag.is-delete:not(body)::after,.content kbd.is-delete:not(body)::after,.docstring>section>a.docs-sourcelink.is-delete:not(body)::after{height:50%;width:1px}.tag.is-delete:not(body):hover,.content kbd.is-delete:not(body):hover,.docstring>section>a.docs-sourcelink.is-delete:not(body):hover,.tag.is-delete:not(body):focus,.content kbd.is-delete:not(body):focus,.docstring>section>a.docs-sourcelink.is-delete:not(body):focus{background-color:#e8e8e8}.tag.is-delete:not(body):active,.content kbd.is-delete:not(body):active,.docstring>section>a.docs-sourcelink.is-delete:not(body):active{background-color:#dbdbdb}.tag.is-rounded:not(body),#documenter .docs-sidebar form.docs-search>input:not(body),.content kbd.is-rounded:not(body),#documenter .docs-sidebar .content form.docs-search>input:not(body),.docstring>section>a.docs-sourcelink.is-rounded:not(body){border-radius:290486px}a.tag:hover,.docstring>section>a.docs-sourcelink:hover{text-decoration:underline}.title,.subtitle{word-break:break-word}.title em,.title span,.subtitle em,.subtitle span{font-weight:inherit}.title sub,.subtitle sub{font-size:.75em}.title sup,.subtitle sup{font-size:.75em}.title .tag,.title .content kbd,.content .title kbd,.title .docstring>section>a.docs-sourcelink,.subtitle .tag,.subtitle .content kbd,.content .subtitle kbd,.subtitle .docstring>section>a.docs-sourcelink{vertical-align:middle}.title{color:#363636;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.title+.highlight{margin-top:-0.75rem}.title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}.title.is-1{font-size:3rem}.title.is-2{font-size:2.5rem}.title.is-3{font-size:2rem}.title.is-4{font-size:1.5rem}.title.is-5{font-size:1.25rem}.title.is-6{font-size:1rem}.title.is-7{font-size:.75rem}.subtitle{color:#4a4a4a;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#363636;font-weight:600}.subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}.subtitle.is-1{font-size:3rem}.subtitle.is-2{font-size:2.5rem}.subtitle.is-3{font-size:2rem}.subtitle.is-4{font-size:1.5rem}.subtitle.is-5{font-size:1.25rem}.subtitle.is-6{font-size:1rem}.subtitle.is-7{font-size:.75rem}.heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}.highlight{font-weight:400;max-width:100%;overflow:hidden;padding:0}.highlight pre{overflow:auto;max-width:100%}.number{align-items:center;background-color:#f5f5f5;border-radius:290486px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:0.25rem 0.5rem;text-align:center;vertical-align:top}.select select,.textarea,.input,#documenter .docs-sidebar form.docs-search>input{background-color:#fff;border-color:#dbdbdb;border-radius:4px;color:#363636}.select select::-moz-placeholder,.textarea::-moz-placeholder,.input::-moz-placeholder,#documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:rgba(54,54,54,0.3)}.select select::-webkit-input-placeholder,.textarea::-webkit-input-placeholder,.input::-webkit-input-placeholder,#documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:rgba(54,54,54,0.3)}.select select:-moz-placeholder,.textarea:-moz-placeholder,.input:-moz-placeholder,#documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:rgba(54,54,54,0.3)}.select select:-ms-input-placeholder,.textarea:-ms-input-placeholder,.input:-ms-input-placeholder,#documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:rgba(54,54,54,0.3)}.select select:hover,.textarea:hover,.input:hover,#documenter .docs-sidebar form.docs-search>input:hover,.select select.is-hovered,.is-hovered.textarea,.is-hovered.input,#documenter .docs-sidebar form.docs-search>input.is-hovered{border-color:#b5b5b5}.select select:focus,.textarea:focus,.input:focus,#documenter .docs-sidebar form.docs-search>input:focus,.select select.is-focused,.is-focused.textarea,.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.select select:active,.textarea:active,.input:active,#documenter .docs-sidebar form.docs-search>input:active,.select select.is-active,.is-active.textarea,.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{border-color:#2e63b8;box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.select select[disabled],.textarea[disabled],.input[disabled],#documenter .docs-sidebar form.docs-search>input[disabled],fieldset[disabled] .select select,.select fieldset[disabled] select,fieldset[disabled] .textarea,fieldset[disabled] .input,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none;color:#6b6b6b}.select select[disabled]::-moz-placeholder,.textarea[disabled]::-moz-placeholder,.input[disabled]::-moz-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]::-moz-placeholder,fieldset[disabled] .select select::-moz-placeholder,.select fieldset[disabled] select::-moz-placeholder,fieldset[disabled] .textarea::-moz-placeholder,fieldset[disabled] .input::-moz-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input::-moz-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input::-moz-placeholder{color:rgba(107,107,107,0.3)}.select select[disabled]::-webkit-input-placeholder,.textarea[disabled]::-webkit-input-placeholder,.input[disabled]::-webkit-input-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]::-webkit-input-placeholder,fieldset[disabled] .select select::-webkit-input-placeholder,.select fieldset[disabled] select::-webkit-input-placeholder,fieldset[disabled] .textarea::-webkit-input-placeholder,fieldset[disabled] .input::-webkit-input-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input::-webkit-input-placeholder{color:rgba(107,107,107,0.3)}.select select[disabled]:-moz-placeholder,.textarea[disabled]:-moz-placeholder,.input[disabled]:-moz-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]:-moz-placeholder,fieldset[disabled] .select select:-moz-placeholder,.select fieldset[disabled] select:-moz-placeholder,fieldset[disabled] .textarea:-moz-placeholder,fieldset[disabled] .input:-moz-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input:-moz-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input:-moz-placeholder{color:rgba(107,107,107,0.3)}.select select[disabled]:-ms-input-placeholder,.textarea[disabled]:-ms-input-placeholder,.input[disabled]:-ms-input-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]:-ms-input-placeholder,fieldset[disabled] .select select:-ms-input-placeholder,.select fieldset[disabled] select:-ms-input-placeholder,fieldset[disabled] .textarea:-ms-input-placeholder,fieldset[disabled] .input:-ms-input-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input:-ms-input-placeholder{color:rgba(107,107,107,0.3)}.textarea,.input,#documenter .docs-sidebar form.docs-search>input{box-shadow:inset 0 1px 2px rgba(10,10,10,0.1);max-width:100%;width:100%}.textarea[readonly],.input[readonly],#documenter .docs-sidebar form.docs-search>input[readonly]{box-shadow:none}.is-white.textarea,.is-white.input,#documenter .docs-sidebar form.docs-search>input.is-white{border-color:#fff}.is-white.textarea:focus,.is-white.input:focus,#documenter .docs-sidebar form.docs-search>input.is-white:focus,.is-white.is-focused.textarea,.is-white.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-white.textarea:active,.is-white.input:active,#documenter .docs-sidebar form.docs-search>input.is-white:active,.is-white.is-active.textarea,.is-white.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}.is-black.textarea,.is-black.input,#documenter .docs-sidebar form.docs-search>input.is-black{border-color:#0a0a0a}.is-black.textarea:focus,.is-black.input:focus,#documenter .docs-sidebar form.docs-search>input.is-black:focus,.is-black.is-focused.textarea,.is-black.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-black.textarea:active,.is-black.input:active,#documenter .docs-sidebar form.docs-search>input.is-black:active,.is-black.is-active.textarea,.is-black.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}.is-light.textarea,.is-light.input,#documenter .docs-sidebar form.docs-search>input.is-light{border-color:#f5f5f5}.is-light.textarea:focus,.is-light.input:focus,#documenter .docs-sidebar form.docs-search>input.is-light:focus,.is-light.is-focused.textarea,.is-light.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-light.textarea:active,.is-light.input:active,#documenter .docs-sidebar form.docs-search>input.is-light:active,.is-light.is-active.textarea,.is-light.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(245,245,245,0.25)}.is-dark.textarea,.content kbd.textarea,.is-dark.input,#documenter .docs-sidebar form.docs-search>input.is-dark,.content kbd.input{border-color:#363636}.is-dark.textarea:focus,.content kbd.textarea:focus,.is-dark.input:focus,#documenter .docs-sidebar form.docs-search>input.is-dark:focus,.content kbd.input:focus,.is-dark.is-focused.textarea,.content kbd.is-focused.textarea,.is-dark.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.content kbd.is-focused.input,#documenter .docs-sidebar .content form.docs-search>input.is-focused,.is-dark.textarea:active,.content kbd.textarea:active,.is-dark.input:active,#documenter .docs-sidebar form.docs-search>input.is-dark:active,.content kbd.input:active,.is-dark.is-active.textarea,.content kbd.is-active.textarea,.is-dark.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active,.content kbd.is-active.input,#documenter .docs-sidebar .content form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(54,54,54,0.25)}.is-primary.textarea,.docstring>section>a.textarea.docs-sourcelink,.is-primary.input,#documenter .docs-sidebar form.docs-search>input.is-primary,.docstring>section>a.input.docs-sourcelink{border-color:#4eb5de}.is-primary.textarea:focus,.docstring>section>a.textarea.docs-sourcelink:focus,.is-primary.input:focus,#documenter .docs-sidebar form.docs-search>input.is-primary:focus,.docstring>section>a.input.docs-sourcelink:focus,.is-primary.is-focused.textarea,.docstring>section>a.is-focused.textarea.docs-sourcelink,.is-primary.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.docstring>section>a.is-focused.input.docs-sourcelink,.is-primary.textarea:active,.docstring>section>a.textarea.docs-sourcelink:active,.is-primary.input:active,#documenter .docs-sidebar form.docs-search>input.is-primary:active,.docstring>section>a.input.docs-sourcelink:active,.is-primary.is-active.textarea,.docstring>section>a.is-active.textarea.docs-sourcelink,.is-primary.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active,.docstring>section>a.is-active.input.docs-sourcelink{box-shadow:0 0 0 0.125em rgba(78,181,222,0.25)}.is-link.textarea,.is-link.input,#documenter .docs-sidebar form.docs-search>input.is-link{border-color:#2e63b8}.is-link.textarea:focus,.is-link.input:focus,#documenter .docs-sidebar form.docs-search>input.is-link:focus,.is-link.is-focused.textarea,.is-link.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-link.textarea:active,.is-link.input:active,#documenter .docs-sidebar form.docs-search>input.is-link:active,.is-link.is-active.textarea,.is-link.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.is-info.textarea,.is-info.input,#documenter .docs-sidebar form.docs-search>input.is-info{border-color:#209cee}.is-info.textarea:focus,.is-info.input:focus,#documenter .docs-sidebar form.docs-search>input.is-info:focus,.is-info.is-focused.textarea,.is-info.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-info.textarea:active,.is-info.input:active,#documenter .docs-sidebar form.docs-search>input.is-info:active,.is-info.is-active.textarea,.is-info.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(32,156,238,0.25)}.is-success.textarea,.is-success.input,#documenter .docs-sidebar form.docs-search>input.is-success{border-color:#22c35b}.is-success.textarea:focus,.is-success.input:focus,#documenter .docs-sidebar form.docs-search>input.is-success:focus,.is-success.is-focused.textarea,.is-success.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-success.textarea:active,.is-success.input:active,#documenter .docs-sidebar form.docs-search>input.is-success:active,.is-success.is-active.textarea,.is-success.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(34,195,91,0.25)}.is-warning.textarea,.is-warning.input,#documenter .docs-sidebar form.docs-search>input.is-warning{border-color:#ffdd57}.is-warning.textarea:focus,.is-warning.input:focus,#documenter .docs-sidebar form.docs-search>input.is-warning:focus,.is-warning.is-focused.textarea,.is-warning.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-warning.textarea:active,.is-warning.input:active,#documenter .docs-sidebar form.docs-search>input.is-warning:active,.is-warning.is-active.textarea,.is-warning.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,221,87,0.25)}.is-danger.textarea,.is-danger.input,#documenter .docs-sidebar form.docs-search>input.is-danger{border-color:#da0b00}.is-danger.textarea:focus,.is-danger.input:focus,#documenter .docs-sidebar form.docs-search>input.is-danger:focus,.is-danger.is-focused.textarea,.is-danger.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-danger.textarea:active,.is-danger.input:active,#documenter .docs-sidebar form.docs-search>input.is-danger:active,.is-danger.is-active.textarea,.is-danger.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(218,11,0,0.25)}.is-small.textarea,.is-small.input,#documenter .docs-sidebar form.docs-search>input{border-radius:2px;font-size:.75rem}.is-medium.textarea,.is-medium.input,#documenter .docs-sidebar form.docs-search>input.is-medium{font-size:1.25rem}.is-large.textarea,.is-large.input,#documenter .docs-sidebar form.docs-search>input.is-large{font-size:1.5rem}.is-fullwidth.textarea,.is-fullwidth.input,#documenter .docs-sidebar form.docs-search>input.is-fullwidth{display:block;width:100%}.is-inline.textarea,.is-inline.input,#documenter .docs-sidebar form.docs-search>input.is-inline{display:inline;width:auto}.input.is-rounded,#documenter .docs-sidebar form.docs-search>input{border-radius:290486px;padding-left:1em;padding-right:1em}.input.is-static,#documenter .docs-sidebar form.docs-search>input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.textarea{display:block;max-width:100%;min-width:100%;padding:0.625em;resize:vertical}.textarea:not([rows]){max-height:600px;min-height:120px}.textarea[rows]{height:initial}.textarea.has-fixed-size{resize:none}.radio,.checkbox{cursor:pointer;display:inline-block;line-height:1.25;position:relative}.radio input,.checkbox input{cursor:pointer}.radio:hover,.checkbox:hover{color:#363636}.radio[disabled],.checkbox[disabled],fieldset[disabled] .radio,fieldset[disabled] .checkbox{color:#6b6b6b;cursor:not-allowed}.radio+.radio{margin-left:0.5em}.select{display:inline-block;max-width:100%;position:relative;vertical-align:top}.select:not(.is-multiple){height:2.25em}.select:not(.is-multiple):not(.is-loading)::after{border-color:#2e63b8;right:1.125em;z-index:4}.select.is-rounded select,#documenter .docs-sidebar form.docs-search>input.select select{border-radius:290486px;padding-left:1em}.select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:none}.select select::-ms-expand{display:none}.select select[disabled]:hover,fieldset[disabled] .select select:hover{border-color:#f5f5f5}.select select:not([multiple]){padding-right:2.5em}.select select[multiple]{height:auto;padding:0}.select select[multiple] option{padding:0.5em 1em}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#363636}.select.is-white:not(:hover)::after{border-color:#fff}.select.is-white select{border-color:#fff}.select.is-white select:hover,.select.is-white select.is-hovered{border-color:#f2f2f2}.select.is-white select:focus,.select.is-white select.is-focused,.select.is-white select:active,.select.is-white select.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}.select.is-black:not(:hover)::after{border-color:#0a0a0a}.select.is-black select{border-color:#0a0a0a}.select.is-black select:hover,.select.is-black select.is-hovered{border-color:#000}.select.is-black select:focus,.select.is-black select.is-focused,.select.is-black select:active,.select.is-black select.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}.select.is-light:not(:hover)::after{border-color:#f5f5f5}.select.is-light select{border-color:#f5f5f5}.select.is-light select:hover,.select.is-light select.is-hovered{border-color:#e8e8e8}.select.is-light select:focus,.select.is-light select.is-focused,.select.is-light select:active,.select.is-light select.is-active{box-shadow:0 0 0 0.125em rgba(245,245,245,0.25)}.select.is-dark:not(:hover)::after,.content kbd.select:not(:hover)::after{border-color:#363636}.select.is-dark select,.content kbd.select select{border-color:#363636}.select.is-dark select:hover,.content kbd.select select:hover,.select.is-dark select.is-hovered,.content kbd.select select.is-hovered{border-color:#292929}.select.is-dark select:focus,.content kbd.select select:focus,.select.is-dark select.is-focused,.content kbd.select select.is-focused,.select.is-dark select:active,.content kbd.select select:active,.select.is-dark select.is-active,.content kbd.select select.is-active{box-shadow:0 0 0 0.125em rgba(54,54,54,0.25)}.select.is-primary:not(:hover)::after,.docstring>section>a.select.docs-sourcelink:not(:hover)::after{border-color:#4eb5de}.select.is-primary select,.docstring>section>a.select.docs-sourcelink select{border-color:#4eb5de}.select.is-primary select:hover,.docstring>section>a.select.docs-sourcelink select:hover,.select.is-primary select.is-hovered,.docstring>section>a.select.docs-sourcelink select.is-hovered{border-color:#39acda}.select.is-primary select:focus,.docstring>section>a.select.docs-sourcelink select:focus,.select.is-primary select.is-focused,.docstring>section>a.select.docs-sourcelink select.is-focused,.select.is-primary select:active,.docstring>section>a.select.docs-sourcelink select:active,.select.is-primary select.is-active,.docstring>section>a.select.docs-sourcelink select.is-active{box-shadow:0 0 0 0.125em rgba(78,181,222,0.25)}.select.is-link:not(:hover)::after{border-color:#2e63b8}.select.is-link select{border-color:#2e63b8}.select.is-link select:hover,.select.is-link select.is-hovered{border-color:#2958a4}.select.is-link select:focus,.select.is-link select.is-focused,.select.is-link select:active,.select.is-link select.is-active{box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.select.is-info:not(:hover)::after{border-color:#209cee}.select.is-info select{border-color:#209cee}.select.is-info select:hover,.select.is-info select.is-hovered{border-color:#1190e3}.select.is-info select:focus,.select.is-info select.is-focused,.select.is-info select:active,.select.is-info select.is-active{box-shadow:0 0 0 0.125em rgba(32,156,238,0.25)}.select.is-success:not(:hover)::after{border-color:#22c35b}.select.is-success select{border-color:#22c35b}.select.is-success select:hover,.select.is-success select.is-hovered{border-color:#1ead51}.select.is-success select:focus,.select.is-success select.is-focused,.select.is-success select:active,.select.is-success select.is-active{box-shadow:0 0 0 0.125em rgba(34,195,91,0.25)}.select.is-warning:not(:hover)::after{border-color:#ffdd57}.select.is-warning select{border-color:#ffdd57}.select.is-warning select:hover,.select.is-warning select.is-hovered{border-color:#ffd83e}.select.is-warning select:focus,.select.is-warning select.is-focused,.select.is-warning select:active,.select.is-warning select.is-active{box-shadow:0 0 0 0.125em rgba(255,221,87,0.25)}.select.is-danger:not(:hover)::after{border-color:#da0b00}.select.is-danger select{border-color:#da0b00}.select.is-danger select:hover,.select.is-danger select.is-hovered{border-color:#c10a00}.select.is-danger select:focus,.select.is-danger select.is-focused,.select.is-danger select:active,.select.is-danger select.is-active{box-shadow:0 0 0 0.125em rgba(218,11,0,0.25)}.select.is-small,#documenter .docs-sidebar form.docs-search>input.select{border-radius:2px;font-size:.75rem}.select.is-medium{font-size:1.25rem}.select.is-large{font-size:1.5rem}.select.is-disabled::after{border-color:#6b6b6b}.select.is-fullwidth{width:100%}.select.is-fullwidth select{width:100%}.select.is-loading::after{margin-top:0;position:absolute;right:0.625em;top:0.625em;transform:none}.select.is-loading.is-small:after,#documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}.select.is-loading.is-medium:after{font-size:1.25rem}.select.is-loading.is-large:after{font-size:1.5rem}.file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}.file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}.file.is-white:hover .file-cta,.file.is-white.is-hovered .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.file.is-white:focus .file-cta,.file.is-white.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,255,255,0.25);color:#0a0a0a}.file.is-white:active .file-cta,.file.is-white.is-active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}.file.is-black:hover .file-cta,.file.is-black.is-hovered .file-cta{background-color:#040404;border-color:transparent;color:#fff}.file.is-black:focus .file-cta,.file.is-black.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(10,10,10,0.25);color:#fff}.file.is-black:active .file-cta,.file.is-black.is-active .file-cta{background-color:#000;border-color:transparent;color:#fff}.file.is-light .file-cta{background-color:#f5f5f5;border-color:transparent;color:#363636}.file.is-light:hover .file-cta,.file.is-light.is-hovered .file-cta{background-color:#eee;border-color:transparent;color:#363636}.file.is-light:focus .file-cta,.file.is-light.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(245,245,245,0.25);color:#363636}.file.is-light:active .file-cta,.file.is-light.is-active .file-cta{background-color:#e8e8e8;border-color:transparent;color:#363636}.file.is-dark .file-cta,.content kbd.file .file-cta{background-color:#363636;border-color:transparent;color:#f5f5f5}.file.is-dark:hover .file-cta,.content kbd.file:hover .file-cta,.file.is-dark.is-hovered .file-cta,.content kbd.file.is-hovered .file-cta{background-color:#2f2f2f;border-color:transparent;color:#f5f5f5}.file.is-dark:focus .file-cta,.content kbd.file:focus .file-cta,.file.is-dark.is-focused .file-cta,.content kbd.file.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(54,54,54,0.25);color:#f5f5f5}.file.is-dark:active .file-cta,.content kbd.file:active .file-cta,.file.is-dark.is-active .file-cta,.content kbd.file.is-active .file-cta{background-color:#292929;border-color:transparent;color:#f5f5f5}.file.is-primary .file-cta,.docstring>section>a.file.docs-sourcelink .file-cta{background-color:#4eb5de;border-color:transparent;color:#fff}.file.is-primary:hover .file-cta,.docstring>section>a.file.docs-sourcelink:hover .file-cta,.file.is-primary.is-hovered .file-cta,.docstring>section>a.file.is-hovered.docs-sourcelink .file-cta{background-color:#43b1dc;border-color:transparent;color:#fff}.file.is-primary:focus .file-cta,.docstring>section>a.file.docs-sourcelink:focus .file-cta,.file.is-primary.is-focused .file-cta,.docstring>section>a.file.is-focused.docs-sourcelink .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(78,181,222,0.25);color:#fff}.file.is-primary:active .file-cta,.docstring>section>a.file.docs-sourcelink:active .file-cta,.file.is-primary.is-active .file-cta,.docstring>section>a.file.is-active.docs-sourcelink .file-cta{background-color:#39acda;border-color:transparent;color:#fff}.file.is-link .file-cta{background-color:#2e63b8;border-color:transparent;color:#fff}.file.is-link:hover .file-cta,.file.is-link.is-hovered .file-cta{background-color:#2b5eae;border-color:transparent;color:#fff}.file.is-link:focus .file-cta,.file.is-link.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(46,99,184,0.25);color:#fff}.file.is-link:active .file-cta,.file.is-link.is-active .file-cta{background-color:#2958a4;border-color:transparent;color:#fff}.file.is-info .file-cta{background-color:#209cee;border-color:transparent;color:#fff}.file.is-info:hover .file-cta,.file.is-info.is-hovered .file-cta{background-color:#1497ed;border-color:transparent;color:#fff}.file.is-info:focus .file-cta,.file.is-info.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(32,156,238,0.25);color:#fff}.file.is-info:active .file-cta,.file.is-info.is-active .file-cta{background-color:#1190e3;border-color:transparent;color:#fff}.file.is-success .file-cta{background-color:#22c35b;border-color:transparent;color:#fff}.file.is-success:hover .file-cta,.file.is-success.is-hovered .file-cta{background-color:#20b856;border-color:transparent;color:#fff}.file.is-success:focus .file-cta,.file.is-success.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(34,195,91,0.25);color:#fff}.file.is-success:active .file-cta,.file.is-success.is-active .file-cta{background-color:#1ead51;border-color:transparent;color:#fff}.file.is-warning .file-cta{background-color:#ffdd57;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-warning:hover .file-cta,.file.is-warning.is-hovered .file-cta{background-color:#ffda4a;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-warning:focus .file-cta,.file.is-warning.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,221,87,0.25);color:rgba(0,0,0,0.7)}.file.is-warning:active .file-cta,.file.is-warning.is-active .file-cta{background-color:#ffd83e;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-danger .file-cta{background-color:#da0b00;border-color:transparent;color:#fff}.file.is-danger:hover .file-cta,.file.is-danger.is-hovered .file-cta{background-color:#cd0a00;border-color:transparent;color:#fff}.file.is-danger:focus .file-cta,.file.is-danger.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(218,11,0,0.25);color:#fff}.file.is-danger:active .file-cta,.file.is-danger.is-active .file-cta{background-color:#c10a00;border-color:transparent;color:#fff}.file.is-small,#documenter .docs-sidebar form.docs-search>input.file{font-size:.75rem}.file.is-medium{font-size:1.25rem}.file.is-medium .file-icon .fa{font-size:21px}.file.is-large{font-size:1.5rem}.file.is-large .file-icon .fa{font-size:28px}.file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}.file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}.file.has-name.is-empty .file-cta{border-radius:4px}.file.has-name.is-empty .file-name{display:none}.file.is-boxed .file-label{flex-direction:column}.file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}.file.is-boxed .file-name{border-width:0 1px 1px}.file.is-boxed .file-icon{height:1.5em;width:1.5em}.file.is-boxed .file-icon .fa{font-size:21px}.file.is-boxed.is-small .file-icon .fa,#documenter .docs-sidebar form.docs-search>input.is-boxed .file-icon .fa{font-size:14px}.file.is-boxed.is-medium .file-icon .fa{font-size:28px}.file.is-boxed.is-large .file-icon .fa{font-size:35px}.file.is-boxed.has-name .file-cta{border-radius:4px 4px 0 0}.file.is-boxed.has-name .file-name{border-radius:0 0 4px 4px;border-width:0 1px 1px}.file.is-centered{justify-content:center}.file.is-fullwidth .file-label{width:100%}.file.is-fullwidth .file-name{flex-grow:1;max-width:none}.file.is-right{justify-content:flex-end}.file.is-right .file-cta{border-radius:0 4px 4px 0}.file.is-right .file-name{border-radius:4px 0 0 4px;border-width:1px 0 1px 1px;order:-1}.file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}.file-label:hover .file-cta{background-color:#eee;color:#363636}.file-label:hover .file-name{border-color:#d5d5d5}.file-label:active .file-cta{background-color:#e8e8e8;color:#363636}.file-label:active .file-name{border-color:#cfcfcf}.file-input{height:100%;left:0;opacity:0;outline:none;position:absolute;top:0;width:100%}.file-cta,.file-name{border-color:#dbdbdb;border-radius:4px;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}.file-cta{background-color:#f5f5f5;color:#4a4a4a}.file-name{border-color:#dbdbdb;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:left;text-overflow:ellipsis}.file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:0.5em;width:1em}.file-icon .fa{font-size:14px}.label{color:#363636;display:block;font-size:1rem;font-weight:700}.label:not(:last-child){margin-bottom:0.5em}.label.is-small,#documenter .docs-sidebar form.docs-search>input.label{font-size:.75rem}.label.is-medium{font-size:1.25rem}.label.is-large{font-size:1.5rem}.help{display:block;font-size:.75rem;margin-top:0.25rem}.help.is-white{color:#fff}.help.is-black{color:#0a0a0a}.help.is-light{color:#f5f5f5}.help.is-dark,.content kbd.help{color:#363636}.help.is-primary,.docstring>section>a.help.docs-sourcelink{color:#4eb5de}.help.is-link{color:#2e63b8}.help.is-info{color:#209cee}.help.is-success{color:#22c35b}.help.is-warning{color:#ffdd57}.help.is-danger{color:#da0b00}.field:not(:last-child){margin-bottom:0.75rem}.field.has-addons{display:flex;justify-content:flex-start}.field.has-addons .control:not(:last-child){margin-right:-1px}.field.has-addons .control:not(:first-child):not(:last-child) .button,.field.has-addons .control:not(:first-child):not(:last-child) .input,.field.has-addons .control:not(:first-child):not(:last-child) #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .field.has-addons .control:not(:first-child):not(:last-child) form.docs-search>input,.field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}.field.has-addons .control:first-child:not(:only-child) .button,.field.has-addons .control:first-child:not(:only-child) .input,.field.has-addons .control:first-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .field.has-addons .control:first-child:not(:only-child) form.docs-search>input,.field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}.field.has-addons .control:last-child:not(:only-child) .button,.field.has-addons .control:last-child:not(:only-child) .input,.field.has-addons .control:last-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .field.has-addons .control:last-child:not(:only-child) form.docs-search>input,.field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}.field.has-addons .control .button:not([disabled]):hover,.field.has-addons .control .button.is-hovered:not([disabled]),.field.has-addons .control .input:not([disabled]):hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):hover,.field.has-addons .control .input.is-hovered:not([disabled]),.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-hovered:not([disabled]),#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-hovered:not([disabled]),.field.has-addons .control .select select:not([disabled]):hover,.field.has-addons .control .select select.is-hovered:not([disabled]){z-index:2}.field.has-addons .control .button:not([disabled]):focus,.field.has-addons .control .button.is-focused:not([disabled]),.field.has-addons .control .button:not([disabled]):active,.field.has-addons .control .button.is-active:not([disabled]),.field.has-addons .control .input:not([disabled]):focus,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus,.field.has-addons .control .input.is-focused:not([disabled]),.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]),#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]),.field.has-addons .control .input:not([disabled]):active,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active,.field.has-addons .control .input.is-active:not([disabled]),.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]),#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]),.field.has-addons .control .select select:not([disabled]):focus,.field.has-addons .control .select select.is-focused:not([disabled]),.field.has-addons .control .select select:not([disabled]):active,.field.has-addons .control .select select.is-active:not([disabled]){z-index:3}.field.has-addons .control .button:not([disabled]):focus:hover,.field.has-addons .control .button.is-focused:not([disabled]):hover,.field.has-addons .control .button:not([disabled]):active:hover,.field.has-addons .control .button.is-active:not([disabled]):hover,.field.has-addons .control .input:not([disabled]):focus:hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus:hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus:hover,.field.has-addons .control .input.is-focused:not([disabled]):hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]):hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]):hover,.field.has-addons .control .input:not([disabled]):active:hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active:hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active:hover,.field.has-addons .control .input.is-active:not([disabled]):hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]):hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]):focus:hover,.field.has-addons .control .select select.is-focused:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]):active:hover,.field.has-addons .control .select select.is-active:not([disabled]):hover{z-index:4}.field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}.field.has-addons.has-addons-centered{justify-content:center}.field.has-addons.has-addons-right{justify-content:flex-end}.field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}.field.is-grouped{display:flex;justify-content:flex-start}.field.is-grouped>.control{flex-shrink:0}.field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:0.75rem}.field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}.field.is-grouped.is-grouped-centered{justify-content:center}.field.is-grouped.is-grouped-right{justify-content:flex-end}.field.is-grouped.is-grouped-multiline{flex-wrap:wrap}.field.is-grouped.is-grouped-multiline>.control:last-child,.field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:0.75rem}.field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-0.75rem}.field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width: 769px),print{.field.is-horizontal{display:flex}}.field-label .label{font-size:inherit}@media screen and (max-width: 768px){.field-label{margin-bottom:0.5rem}}@media screen and (min-width: 769px),print{.field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}.field-label.is-small,#documenter .docs-sidebar form.docs-search>input.field-label{font-size:.75rem;padding-top:0.375em}.field-label.is-normal{padding-top:0.375em}.field-label.is-medium{font-size:1.25rem;padding-top:0.375em}.field-label.is-large{font-size:1.5rem;padding-top:0.375em}}.field-body .field .field{margin-bottom:0}@media screen and (min-width: 769px),print{.field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}.field-body .field{margin-bottom:0}.field-body>.field{flex-shrink:1}.field-body>.field:not(.is-narrow){flex-grow:1}.field-body>.field:not(:last-child){margin-right:0.75rem}}.control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:left}.control.has-icons-left .input:focus~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input:focus~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input:focus~.icon,.control.has-icons-left .select:focus~.icon,.control.has-icons-right .input:focus~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input:focus~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input:focus~.icon,.control.has-icons-right .select:focus~.icon{color:#6b6b6b}.control.has-icons-left .input.is-small~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input~.icon,.control.has-icons-left .select.is-small~.icon,.control.has-icons-right .input.is-small~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input~.icon,.control.has-icons-right .select.is-small~.icon{font-size:.75rem}.control.has-icons-left .input.is-medium~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-medium~.icon,.control.has-icons-left .select.is-medium~.icon,.control.has-icons-right .input.is-medium~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-medium~.icon,.control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}.control.has-icons-left .input.is-large~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-large~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-large~.icon,.control.has-icons-left .select.is-large~.icon,.control.has-icons-right .input.is-large~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-large~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-large~.icon,.control.has-icons-right .select.is-large~.icon{font-size:1.5rem}.control.has-icons-left .icon,.control.has-icons-right .icon{color:#dbdbdb;height:2.25em;pointer-events:none;position:absolute;top:0;width:2.25em;z-index:4}.control.has-icons-left .input,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input,.control.has-icons-left .select select{padding-left:2.25em}.control.has-icons-left .icon.is-left{left:0}.control.has-icons-right .input,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input,.control.has-icons-right .select select{padding-right:2.25em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute !important;right:0.625em;top:0.625em;z-index:4}.control.is-loading.is-small:after,#documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}.control.is-loading.is-medium:after{font-size:1.25rem}.control.is-loading.is-large:after{font-size:1.5rem}.breadcrumb{font-size:1rem;white-space:nowrap}.breadcrumb a{align-items:center;color:#2e63b8;display:flex;justify-content:center;padding:0 .75em}.breadcrumb a:hover{color:#363636}.breadcrumb li{align-items:center;display:flex}.breadcrumb li:first-child a{padding-left:0}.breadcrumb li.is-active a{color:#222;cursor:default;pointer-events:none}.breadcrumb li+li::before{color:#b5b5b5;content:"\0002f"}.breadcrumb ul,.breadcrumb ol{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.breadcrumb .icon:first-child{margin-right:0.5em}.breadcrumb .icon:last-child{margin-left:0.5em}.breadcrumb.is-centered ol,.breadcrumb.is-centered ul{justify-content:center}.breadcrumb.is-right ol,.breadcrumb.is-right ul{justify-content:flex-end}.breadcrumb.is-small,#documenter .docs-sidebar form.docs-search>input.breadcrumb{font-size:.75rem}.breadcrumb.is-medium{font-size:1.25rem}.breadcrumb.is-large{font-size:1.5rem}.breadcrumb.has-arrow-separator li+li::before{content:"\02192"}.breadcrumb.has-bullet-separator li+li::before{content:"\02022"}.breadcrumb.has-dot-separator li+li::before{content:"\000b7"}.breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}.card{background-color:#fff;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1);color:#222;max-width:100%;position:relative}.card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 1px 2px rgba(10,10,10,0.1);display:flex}.card-header-title{align-items:center;color:#222;display:flex;flex-grow:1;font-weight:700;padding:.75rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{align-items:center;cursor:pointer;display:flex;justify-content:center;padding:.75rem}.card-image{display:block;position:relative}.card-content{background-color:rgba(0,0,0,0);padding:1.5rem}.card-footer{background-color:rgba(0,0,0,0);border-top:1px solid #dbdbdb;align-items:stretch;display:flex}.card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}.card-footer-item:not(:last-child){border-right:1px solid #dbdbdb}.card .media:not(:last-child){margin-bottom:1.5rem}.dropdown{display:inline-flex;position:relative;vertical-align:top}.dropdown.is-active .dropdown-menu,.dropdown.is-hoverable:hover .dropdown-menu{display:block}.dropdown.is-right .dropdown-menu{left:auto;right:0}.dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}.dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}.dropdown-content{background-color:#fff;border-radius:4px;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1);padding-bottom:.5rem;padding-top:.5rem}.dropdown-item{color:#4a4a4a;display:block;font-size:0.875rem;line-height:1.5;padding:0.375rem 1rem;position:relative}a.dropdown-item,button.dropdown-item{padding-right:3rem;text-align:left;white-space:nowrap;width:100%}a.dropdown-item:hover,button.dropdown-item:hover{background-color:#f5f5f5;color:#0a0a0a}a.dropdown-item.is-active,button.dropdown-item.is-active{background-color:#2e63b8;color:#fff}.dropdown-divider{background-color:#dbdbdb;border:none;display:block;height:1px;margin:0.5rem 0}.level{align-items:center;justify-content:space-between}.level code{border-radius:4px}.level img{display:inline-block;vertical-align:top}.level.is-mobile{display:flex}.level.is-mobile .level-left,.level.is-mobile .level-right{display:flex}.level.is-mobile .level-left+.level-right{margin-top:0}.level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}.level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width: 769px),print{.level{display:flex}.level>.level-item:not(.is-narrow){flex-grow:1}}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-item .title,.level-item .subtitle{margin-bottom:0}@media screen and (max-width: 768px){.level-item:not(:last-child){margin-bottom:.75rem}}.level-left,.level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.level-left .level-item.is-flexible,.level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width: 769px),print{.level-left .level-item:not(:last-child),.level-right .level-item:not(:last-child){margin-right:.75rem}}.level-left{align-items:center;justify-content:flex-start}@media screen and (max-width: 768px){.level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width: 769px),print{.level-left{display:flex}}.level-right{align-items:center;justify-content:flex-end}@media screen and (min-width: 769px),print{.level-right{display:flex}}.list{background-color:#fff;border-radius:4px;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1)}.list-item{display:block;padding:0.5em 1em}.list-item:not(a){color:#222}.list-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-item:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px}.list-item:not(:last-child){border-bottom:1px solid #dbdbdb}.list-item.is-active{background-color:#2e63b8;color:#fff}a.list-item{background-color:#f5f5f5;cursor:pointer}.media{align-items:flex-start;display:flex;text-align:left}.media .content:not(:last-child){margin-bottom:0.75rem}.media .media{border-top:1px solid rgba(219,219,219,0.5);display:flex;padding-top:0.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:0.5rem}.media .media .media{padding-top:0.5rem}.media .media .media+.media{margin-top:0.5rem}.media+.media{border-top:1px solid rgba(219,219,219,0.5);margin-top:1rem;padding-top:1rem}.media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}.media-left,.media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.media-left{margin-right:1rem}.media-right{margin-left:1rem}.media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:left}@media screen and (max-width: 768px){.media-content{overflow-x:auto}}.menu{font-size:1rem}.menu.is-small,#documenter .docs-sidebar form.docs-search>input.menu{font-size:.75rem}.menu.is-medium{font-size:1.25rem}.menu.is-large{font-size:1.5rem}.menu-list{line-height:1.25}.menu-list a{border-radius:2px;color:#222;display:block;padding:0.5em 0.75em}.menu-list a:hover{background-color:#f5f5f5;color:#222}.menu-list a.is-active{background-color:#2e63b8;color:#fff}.menu-list li ul{border-left:1px solid #dbdbdb;margin:.75em;padding-left:.75em}.menu-label{color:#6b6b6b;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}.menu-label:not(:first-child){margin-top:1em}.menu-label:not(:last-child){margin-bottom:1em}.message{background-color:#f5f5f5;border-radius:4px;font-size:1rem}.message strong{color:currentColor}.message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}.message.is-small,#documenter .docs-sidebar form.docs-search>input.message{font-size:.75rem}.message.is-medium{font-size:1.25rem}.message.is-large{font-size:1.5rem}.message.is-white{background-color:#fff}.message.is-white .message-header{background-color:#fff;color:#0a0a0a}.message.is-white .message-body{border-color:#fff;color:#4d4d4d}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a;color:#090909}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:#363636}.message.is-light .message-body{border-color:#f5f5f5;color:#505050}.message.is-dark,.content kbd.message{background-color:#fafafa}.message.is-dark .message-header,.content kbd.message .message-header{background-color:#363636;color:#f5f5f5}.message.is-dark .message-body,.content kbd.message .message-body{border-color:#363636;color:#2a2a2a}.message.is-primary,.docstring>section>a.message.docs-sourcelink{background-color:#f6fbfd}.message.is-primary .message-header,.docstring>section>a.message.docs-sourcelink .message-header{background-color:#4eb5de;color:#fff}.message.is-primary .message-body,.docstring>section>a.message.docs-sourcelink .message-body{border-color:#4eb5de;color:#1f556a}.message.is-link{background-color:#f7f9fd}.message.is-link .message-header{background-color:#2e63b8;color:#fff}.message.is-link .message-body{border-color:#2e63b8;color:#264981}.message.is-info{background-color:#f6fbfe}.message.is-info .message-header{background-color:#209cee;color:#fff}.message.is-info .message-body{border-color:#209cee;color:#12537d}.message.is-success{background-color:#f6fdf9}.message.is-success .message-header{background-color:#22c35b;color:#fff}.message.is-success .message-body{border-color:#22c35b;color:#0f361d}.message.is-warning{background-color:#fffdf5}.message.is-warning .message-header{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.message.is-warning .message-body{border-color:#ffdd57;color:#3c3108}.message.is-danger{background-color:#fff5f5}.message.is-danger .message-header{background-color:#da0b00;color:#fff}.message.is-danger .message-body{border-color:#da0b00;color:#9b0c04}.message-header{align-items:center;background-color:#222;border-radius:4px 4px 0 0;color:#fff;display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.75em 1em;position:relative}.message-header .delete{flex-grow:0;flex-shrink:0;margin-left:0.75em}.message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}.message-body{border-color:#dbdbdb;border-radius:4px;border-style:solid;border-width:0 0 0 4px;color:#222;padding:1.25em 1.5em}.message-body code,.message-body pre{background-color:#fff}.message-body pre code{background-color:rgba(0,0,0,0)}.modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}.modal.is-active{display:flex}.modal-background{background-color:rgba(10,10,10,0.86)}.modal-content,.modal-card{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width: 769px),print{.modal-content,.modal-card{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}.modal-close{background:none;height:40px;position:fixed;right:20px;top:20px;width:40px}.modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}.modal-card-head,.modal-card-foot{align-items:center;background-color:#f5f5f5;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}.modal-card-head{border-bottom:1px solid #dbdbdb;border-top-left-radius:6px;border-top-right-radius:6px}.modal-card-title{color:#222;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}.modal-card-foot{border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:1px solid #dbdbdb}.modal-card-foot .button:not(:last-child){margin-right:0.5em}.modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}.navbar{background-color:#fff;min-height:3.25rem;position:relative;z-index:30}.navbar.is-white{background-color:#fff;color:#0a0a0a}.navbar.is-white .navbar-brand>.navbar-item,.navbar.is-white .navbar-brand .navbar-link{color:#0a0a0a}.navbar.is-white .navbar-brand>a.navbar-item:focus,.navbar.is-white .navbar-brand>a.navbar-item:hover,.navbar.is-white .navbar-brand>a.navbar-item.is-active,.navbar.is-white .navbar-brand .navbar-link:focus,.navbar.is-white .navbar-brand .navbar-link:hover,.navbar.is-white .navbar-brand .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width: 1056px){.navbar.is-white .navbar-start>.navbar-item,.navbar.is-white .navbar-start .navbar-link,.navbar.is-white .navbar-end>.navbar-item,.navbar.is-white .navbar-end .navbar-link{color:#0a0a0a}.navbar.is-white .navbar-start>a.navbar-item:focus,.navbar.is-white .navbar-start>a.navbar-item:hover,.navbar.is-white .navbar-start>a.navbar-item.is-active,.navbar.is-white .navbar-start .navbar-link:focus,.navbar.is-white .navbar-start .navbar-link:hover,.navbar.is-white .navbar-start .navbar-link.is-active,.navbar.is-white .navbar-end>a.navbar-item:focus,.navbar.is-white .navbar-end>a.navbar-item:hover,.navbar.is-white .navbar-end>a.navbar-item.is-active,.navbar.is-white .navbar-end .navbar-link:focus,.navbar.is-white .navbar-end .navbar-link:hover,.navbar.is-white .navbar-end .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-start .navbar-link::after,.navbar.is-white .navbar-end .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-white .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}.navbar.is-black{background-color:#0a0a0a;color:#fff}.navbar.is-black .navbar-brand>.navbar-item,.navbar.is-black .navbar-brand .navbar-link{color:#fff}.navbar.is-black .navbar-brand>a.navbar-item:focus,.navbar.is-black .navbar-brand>a.navbar-item:hover,.navbar.is-black .navbar-brand>a.navbar-item.is-active,.navbar.is-black .navbar-brand .navbar-link:focus,.navbar.is-black .navbar-brand .navbar-link:hover,.navbar.is-black .navbar-brand .navbar-link.is-active{background-color:#000;color:#fff}.navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-black .navbar-start>.navbar-item,.navbar.is-black .navbar-start .navbar-link,.navbar.is-black .navbar-end>.navbar-item,.navbar.is-black .navbar-end .navbar-link{color:#fff}.navbar.is-black .navbar-start>a.navbar-item:focus,.navbar.is-black .navbar-start>a.navbar-item:hover,.navbar.is-black .navbar-start>a.navbar-item.is-active,.navbar.is-black .navbar-start .navbar-link:focus,.navbar.is-black .navbar-start .navbar-link:hover,.navbar.is-black .navbar-start .navbar-link.is-active,.navbar.is-black .navbar-end>a.navbar-item:focus,.navbar.is-black .navbar-end>a.navbar-item:hover,.navbar.is-black .navbar-end>a.navbar-item.is-active,.navbar.is-black .navbar-end .navbar-link:focus,.navbar.is-black .navbar-end .navbar-link:hover,.navbar.is-black .navbar-end .navbar-link.is-active{background-color:#000;color:#fff}.navbar.is-black .navbar-start .navbar-link::after,.navbar.is-black .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-black .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link{background-color:#000;color:#fff}.navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}.navbar.is-light{background-color:#f5f5f5;color:#363636}.navbar.is-light .navbar-brand>.navbar-item,.navbar.is-light .navbar-brand .navbar-link{color:#363636}.navbar.is-light .navbar-brand>a.navbar-item:focus,.navbar.is-light .navbar-brand>a.navbar-item:hover,.navbar.is-light .navbar-brand>a.navbar-item.is-active,.navbar.is-light .navbar-brand .navbar-link:focus,.navbar.is-light .navbar-brand .navbar-link:hover,.navbar.is-light .navbar-brand .navbar-link.is-active{background-color:#e8e8e8;color:#363636}.navbar.is-light .navbar-brand .navbar-link::after{border-color:#363636}.navbar.is-light .navbar-burger{color:#363636}@media screen and (min-width: 1056px){.navbar.is-light .navbar-start>.navbar-item,.navbar.is-light .navbar-start .navbar-link,.navbar.is-light .navbar-end>.navbar-item,.navbar.is-light .navbar-end .navbar-link{color:#363636}.navbar.is-light .navbar-start>a.navbar-item:focus,.navbar.is-light .navbar-start>a.navbar-item:hover,.navbar.is-light .navbar-start>a.navbar-item.is-active,.navbar.is-light .navbar-start .navbar-link:focus,.navbar.is-light .navbar-start .navbar-link:hover,.navbar.is-light .navbar-start .navbar-link.is-active,.navbar.is-light .navbar-end>a.navbar-item:focus,.navbar.is-light .navbar-end>a.navbar-item:hover,.navbar.is-light .navbar-end>a.navbar-item.is-active,.navbar.is-light .navbar-end .navbar-link:focus,.navbar.is-light .navbar-end .navbar-link:hover,.navbar.is-light .navbar-end .navbar-link.is-active{background-color:#e8e8e8;color:#363636}.navbar.is-light .navbar-start .navbar-link::after,.navbar.is-light .navbar-end .navbar-link::after{border-color:#363636}.navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-light .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link{background-color:#e8e8e8;color:#363636}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#363636}}.navbar.is-dark,.content kbd.navbar{background-color:#363636;color:#f5f5f5}.navbar.is-dark .navbar-brand>.navbar-item,.content kbd.navbar .navbar-brand>.navbar-item,.navbar.is-dark .navbar-brand .navbar-link,.content kbd.navbar .navbar-brand .navbar-link{color:#f5f5f5}.navbar.is-dark .navbar-brand>a.navbar-item:focus,.content kbd.navbar .navbar-brand>a.navbar-item:focus,.navbar.is-dark .navbar-brand>a.navbar-item:hover,.content kbd.navbar .navbar-brand>a.navbar-item:hover,.navbar.is-dark .navbar-brand>a.navbar-item.is-active,.content kbd.navbar .navbar-brand>a.navbar-item.is-active,.navbar.is-dark .navbar-brand .navbar-link:focus,.content kbd.navbar .navbar-brand .navbar-link:focus,.navbar.is-dark .navbar-brand .navbar-link:hover,.content kbd.navbar .navbar-brand .navbar-link:hover,.navbar.is-dark .navbar-brand .navbar-link.is-active,.content kbd.navbar .navbar-brand .navbar-link.is-active{background-color:#292929;color:#f5f5f5}.navbar.is-dark .navbar-brand .navbar-link::after,.content kbd.navbar .navbar-brand .navbar-link::after{border-color:#f5f5f5}.navbar.is-dark .navbar-burger,.content kbd.navbar .navbar-burger{color:#f5f5f5}@media screen and (min-width: 1056px){.navbar.is-dark .navbar-start>.navbar-item,.content kbd.navbar .navbar-start>.navbar-item,.navbar.is-dark .navbar-start .navbar-link,.content kbd.navbar .navbar-start .navbar-link,.navbar.is-dark .navbar-end>.navbar-item,.content kbd.navbar .navbar-end>.navbar-item,.navbar.is-dark .navbar-end .navbar-link,.content kbd.navbar .navbar-end .navbar-link{color:#f5f5f5}.navbar.is-dark .navbar-start>a.navbar-item:focus,.content kbd.navbar .navbar-start>a.navbar-item:focus,.navbar.is-dark .navbar-start>a.navbar-item:hover,.content kbd.navbar .navbar-start>a.navbar-item:hover,.navbar.is-dark .navbar-start>a.navbar-item.is-active,.content kbd.navbar .navbar-start>a.navbar-item.is-active,.navbar.is-dark .navbar-start .navbar-link:focus,.content kbd.navbar .navbar-start .navbar-link:focus,.navbar.is-dark .navbar-start .navbar-link:hover,.content kbd.navbar .navbar-start .navbar-link:hover,.navbar.is-dark .navbar-start .navbar-link.is-active,.content kbd.navbar .navbar-start .navbar-link.is-active,.navbar.is-dark .navbar-end>a.navbar-item:focus,.content kbd.navbar .navbar-end>a.navbar-item:focus,.navbar.is-dark .navbar-end>a.navbar-item:hover,.content kbd.navbar .navbar-end>a.navbar-item:hover,.navbar.is-dark .navbar-end>a.navbar-item.is-active,.content kbd.navbar .navbar-end>a.navbar-item.is-active,.navbar.is-dark .navbar-end .navbar-link:focus,.content kbd.navbar .navbar-end .navbar-link:focus,.navbar.is-dark .navbar-end .navbar-link:hover,.content kbd.navbar .navbar-end .navbar-link:hover,.navbar.is-dark .navbar-end .navbar-link.is-active,.content kbd.navbar .navbar-end .navbar-link.is-active{background-color:#292929;color:#f5f5f5}.navbar.is-dark .navbar-start .navbar-link::after,.content kbd.navbar .navbar-start .navbar-link::after,.navbar.is-dark .navbar-end .navbar-link::after,.content kbd.navbar .navbar-end .navbar-link::after{border-color:#f5f5f5}.navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,.content kbd.navbar .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link,.content kbd.navbar .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,.content kbd.navbar .navbar-item.has-dropdown.is-active .navbar-link{background-color:#292929;color:#f5f5f5}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active,.content kbd.navbar .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#f5f5f5}}.navbar.is-primary,.docstring>section>a.navbar.docs-sourcelink{background-color:#4eb5de;color:#fff}.navbar.is-primary .navbar-brand>.navbar-item,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>.navbar-item,.navbar.is-primary .navbar-brand .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link{color:#fff}.navbar.is-primary .navbar-brand>a.navbar-item:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:focus,.navbar.is-primary .navbar-brand>a.navbar-item:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:hover,.navbar.is-primary .navbar-brand>a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item.is-active,.navbar.is-primary .navbar-brand .navbar-link:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:focus,.navbar.is-primary .navbar-brand .navbar-link:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:hover,.navbar.is-primary .navbar-brand .navbar-link.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link.is-active{background-color:#39acda;color:#fff}.navbar.is-primary .navbar-brand .navbar-link::after,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-burger,.docstring>section>a.navbar.docs-sourcelink .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-primary .navbar-start>.navbar-item,.docstring>section>a.navbar.docs-sourcelink .navbar-start>.navbar-item,.navbar.is-primary .navbar-start .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link,.navbar.is-primary .navbar-end>.navbar-item,.docstring>section>a.navbar.docs-sourcelink .navbar-end>.navbar-item,.navbar.is-primary .navbar-end .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link{color:#fff}.navbar.is-primary .navbar-start>a.navbar-item:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:focus,.navbar.is-primary .navbar-start>a.navbar-item:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:hover,.navbar.is-primary .navbar-start>a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item.is-active,.navbar.is-primary .navbar-start .navbar-link:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:focus,.navbar.is-primary .navbar-start .navbar-link:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:hover,.navbar.is-primary .navbar-start .navbar-link.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link.is-active,.navbar.is-primary .navbar-end>a.navbar-item:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:focus,.navbar.is-primary .navbar-end>a.navbar-item:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:hover,.navbar.is-primary .navbar-end>a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item.is-active,.navbar.is-primary .navbar-end .navbar-link:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:focus,.navbar.is-primary .navbar-end .navbar-link:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:hover,.navbar.is-primary .navbar-end .navbar-link.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link.is-active{background-color:#39acda;color:#fff}.navbar.is-primary .navbar-start .navbar-link::after,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link::after,.navbar.is-primary .navbar-end .navbar-link::after,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown.is-active .navbar-link{background-color:#39acda;color:#fff}.navbar.is-primary .navbar-dropdown a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#4eb5de;color:#fff}}.navbar.is-link{background-color:#2e63b8;color:#fff}.navbar.is-link .navbar-brand>.navbar-item,.navbar.is-link .navbar-brand .navbar-link{color:#fff}.navbar.is-link .navbar-brand>a.navbar-item:focus,.navbar.is-link .navbar-brand>a.navbar-item:hover,.navbar.is-link .navbar-brand>a.navbar-item.is-active,.navbar.is-link .navbar-brand .navbar-link:focus,.navbar.is-link .navbar-brand .navbar-link:hover,.navbar.is-link .navbar-brand .navbar-link.is-active{background-color:#2958a4;color:#fff}.navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-link .navbar-start>.navbar-item,.navbar.is-link .navbar-start .navbar-link,.navbar.is-link .navbar-end>.navbar-item,.navbar.is-link .navbar-end .navbar-link{color:#fff}.navbar.is-link .navbar-start>a.navbar-item:focus,.navbar.is-link .navbar-start>a.navbar-item:hover,.navbar.is-link .navbar-start>a.navbar-item.is-active,.navbar.is-link .navbar-start .navbar-link:focus,.navbar.is-link .navbar-start .navbar-link:hover,.navbar.is-link .navbar-start .navbar-link.is-active,.navbar.is-link .navbar-end>a.navbar-item:focus,.navbar.is-link .navbar-end>a.navbar-item:hover,.navbar.is-link .navbar-end>a.navbar-item.is-active,.navbar.is-link .navbar-end .navbar-link:focus,.navbar.is-link .navbar-end .navbar-link:hover,.navbar.is-link .navbar-end .navbar-link.is-active{background-color:#2958a4;color:#fff}.navbar.is-link .navbar-start .navbar-link::after,.navbar.is-link .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-link .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link{background-color:#2958a4;color:#fff}.navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#2e63b8;color:#fff}}.navbar.is-info{background-color:#209cee;color:#fff}.navbar.is-info .navbar-brand>.navbar-item,.navbar.is-info .navbar-brand .navbar-link{color:#fff}.navbar.is-info .navbar-brand>a.navbar-item:focus,.navbar.is-info .navbar-brand>a.navbar-item:hover,.navbar.is-info .navbar-brand>a.navbar-item.is-active,.navbar.is-info .navbar-brand .navbar-link:focus,.navbar.is-info .navbar-brand .navbar-link:hover,.navbar.is-info .navbar-brand .navbar-link.is-active{background-color:#1190e3;color:#fff}.navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-info .navbar-start>.navbar-item,.navbar.is-info .navbar-start .navbar-link,.navbar.is-info .navbar-end>.navbar-item,.navbar.is-info .navbar-end .navbar-link{color:#fff}.navbar.is-info .navbar-start>a.navbar-item:focus,.navbar.is-info .navbar-start>a.navbar-item:hover,.navbar.is-info .navbar-start>a.navbar-item.is-active,.navbar.is-info .navbar-start .navbar-link:focus,.navbar.is-info .navbar-start .navbar-link:hover,.navbar.is-info .navbar-start .navbar-link.is-active,.navbar.is-info .navbar-end>a.navbar-item:focus,.navbar.is-info .navbar-end>a.navbar-item:hover,.navbar.is-info .navbar-end>a.navbar-item.is-active,.navbar.is-info .navbar-end .navbar-link:focus,.navbar.is-info .navbar-end .navbar-link:hover,.navbar.is-info .navbar-end .navbar-link.is-active{background-color:#1190e3;color:#fff}.navbar.is-info .navbar-start .navbar-link::after,.navbar.is-info .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-info .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1190e3;color:#fff}.navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#209cee;color:#fff}}.navbar.is-success{background-color:#22c35b;color:#fff}.navbar.is-success .navbar-brand>.navbar-item,.navbar.is-success .navbar-brand .navbar-link{color:#fff}.navbar.is-success .navbar-brand>a.navbar-item:focus,.navbar.is-success .navbar-brand>a.navbar-item:hover,.navbar.is-success .navbar-brand>a.navbar-item.is-active,.navbar.is-success .navbar-brand .navbar-link:focus,.navbar.is-success .navbar-brand .navbar-link:hover,.navbar.is-success .navbar-brand .navbar-link.is-active{background-color:#1ead51;color:#fff}.navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-success .navbar-start>.navbar-item,.navbar.is-success .navbar-start .navbar-link,.navbar.is-success .navbar-end>.navbar-item,.navbar.is-success .navbar-end .navbar-link{color:#fff}.navbar.is-success .navbar-start>a.navbar-item:focus,.navbar.is-success .navbar-start>a.navbar-item:hover,.navbar.is-success .navbar-start>a.navbar-item.is-active,.navbar.is-success .navbar-start .navbar-link:focus,.navbar.is-success .navbar-start .navbar-link:hover,.navbar.is-success .navbar-start .navbar-link.is-active,.navbar.is-success .navbar-end>a.navbar-item:focus,.navbar.is-success .navbar-end>a.navbar-item:hover,.navbar.is-success .navbar-end>a.navbar-item.is-active,.navbar.is-success .navbar-end .navbar-link:focus,.navbar.is-success .navbar-end .navbar-link:hover,.navbar.is-success .navbar-end .navbar-link.is-active{background-color:#1ead51;color:#fff}.navbar.is-success .navbar-start .navbar-link::after,.navbar.is-success .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-success .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1ead51;color:#fff}.navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#22c35b;color:#fff}}.navbar.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand>.navbar-item,.navbar.is-warning .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand>a.navbar-item:focus,.navbar.is-warning .navbar-brand>a.navbar-item:hover,.navbar.is-warning .navbar-brand>a.navbar-item.is-active,.navbar.is-warning .navbar-brand .navbar-link:focus,.navbar.is-warning .navbar-brand .navbar-link:hover,.navbar.is-warning .navbar-brand .navbar-link.is-active{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1056px){.navbar.is-warning .navbar-start>.navbar-item,.navbar.is-warning .navbar-start .navbar-link,.navbar.is-warning .navbar-end>.navbar-item,.navbar.is-warning .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-start>a.navbar-item:focus,.navbar.is-warning .navbar-start>a.navbar-item:hover,.navbar.is-warning .navbar-start>a.navbar-item.is-active,.navbar.is-warning .navbar-start .navbar-link:focus,.navbar.is-warning .navbar-start .navbar-link:hover,.navbar.is-warning .navbar-start .navbar-link.is-active,.navbar.is-warning .navbar-end>a.navbar-item:focus,.navbar.is-warning .navbar-end>a.navbar-item:hover,.navbar.is-warning .navbar-end>a.navbar-item.is-active,.navbar.is-warning .navbar-end .navbar-link:focus,.navbar.is-warning .navbar-end .navbar-link:hover,.navbar.is-warning .navbar-end .navbar-link.is-active{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-start .navbar-link::after,.navbar.is-warning .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ffdd57;color:rgba(0,0,0,0.7)}}.navbar.is-danger{background-color:#da0b00;color:#fff}.navbar.is-danger .navbar-brand>.navbar-item,.navbar.is-danger .navbar-brand .navbar-link{color:#fff}.navbar.is-danger .navbar-brand>a.navbar-item:focus,.navbar.is-danger .navbar-brand>a.navbar-item:hover,.navbar.is-danger .navbar-brand>a.navbar-item.is-active,.navbar.is-danger .navbar-brand .navbar-link:focus,.navbar.is-danger .navbar-brand .navbar-link:hover,.navbar.is-danger .navbar-brand .navbar-link.is-active{background-color:#c10a00;color:#fff}.navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-danger .navbar-start>.navbar-item,.navbar.is-danger .navbar-start .navbar-link,.navbar.is-danger .navbar-end>.navbar-item,.navbar.is-danger .navbar-end .navbar-link{color:#fff}.navbar.is-danger .navbar-start>a.navbar-item:focus,.navbar.is-danger .navbar-start>a.navbar-item:hover,.navbar.is-danger .navbar-start>a.navbar-item.is-active,.navbar.is-danger .navbar-start .navbar-link:focus,.navbar.is-danger .navbar-start .navbar-link:hover,.navbar.is-danger .navbar-start .navbar-link.is-active,.navbar.is-danger .navbar-end>a.navbar-item:focus,.navbar.is-danger .navbar-end>a.navbar-item:hover,.navbar.is-danger .navbar-end>a.navbar-item.is-active,.navbar.is-danger .navbar-end .navbar-link:focus,.navbar.is-danger .navbar-end .navbar-link:hover,.navbar.is-danger .navbar-end .navbar-link.is-active{background-color:#c10a00;color:#fff}.navbar.is-danger .navbar-start .navbar-link::after,.navbar.is-danger .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link{background-color:#c10a00;color:#fff}.navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#da0b00;color:#fff}}.navbar>.container{align-items:stretch;display:flex;min-height:3.25rem;width:100%}.navbar.has-shadow{box-shadow:0 2px 0 0 #f5f5f5}.navbar.is-fixed-bottom,.navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom{bottom:0}.navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #f5f5f5}.navbar.is-fixed-top{top:0}html.has-navbar-fixed-top,body.has-navbar-fixed-top{padding-top:3.25rem}html.has-navbar-fixed-bottom,body.has-navbar-fixed-bottom{padding-bottom:3.25rem}.navbar-brand,.navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:3.25rem}.navbar-brand a.navbar-item:focus,.navbar-brand a.navbar-item:hover{background-color:transparent}.navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}.navbar-burger{color:#4a4a4a;cursor:pointer;display:block;height:3.25rem;position:relative;width:3.25rem;margin-left:auto}.navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color, opacity, transform;transition-timing-function:ease-out;width:16px}.navbar-burger span:nth-child(1){top:calc(50% - 6px)}.navbar-burger span:nth-child(2){top:calc(50% - 1px)}.navbar-burger span:nth-child(3){top:calc(50% + 4px)}.navbar-burger:hover{background-color:rgba(0,0,0,0.05)}.navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}.navbar-burger.is-active span:nth-child(2){opacity:0}.navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}.navbar-menu{display:none}.navbar-item,.navbar-link{color:#4a4a4a;display:block;line-height:1.5;padding:0.5rem 0.75rem;position:relative}.navbar-item .icon:only-child,.navbar-link .icon:only-child{margin-left:-0.25rem;margin-right:-0.25rem}a.navbar-item,.navbar-link{cursor:pointer}a.navbar-item:focus,a.navbar-item:focus-within,a.navbar-item:hover,a.navbar-item.is-active,.navbar-link:focus,.navbar-link:focus-within,.navbar-link:hover,.navbar-link.is-active{background-color:#fafafa;color:#2e63b8}.navbar-item{display:block;flex-grow:0;flex-shrink:0}.navbar-item img{max-height:1.75rem}.navbar-item.has-dropdown{padding:0}.navbar-item.is-expanded{flex-grow:1;flex-shrink:1}.navbar-item.is-tab{border-bottom:1px solid transparent;min-height:3.25rem;padding-bottom:calc(0.5rem - 1px)}.navbar-item.is-tab:focus,.navbar-item.is-tab:hover{background-color:rgba(0,0,0,0);border-bottom-color:#2e63b8}.navbar-item.is-tab.is-active{background-color:rgba(0,0,0,0);border-bottom-color:#2e63b8;border-bottom-style:solid;border-bottom-width:3px;color:#2e63b8;padding-bottom:calc(0.5rem - 3px)}.navbar-content{flex-grow:1;flex-shrink:1}.navbar-link:not(.is-arrowless){padding-right:2.5em}.navbar-link:not(.is-arrowless)::after{border-color:#2e63b8;margin-top:-0.375em;right:1.125em}.navbar-dropdown{font-size:0.875rem;padding-bottom:0.5rem;padding-top:0.5rem}.navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}.navbar-divider{background-color:#f5f5f5;border:none;display:none;height:2px;margin:0.5rem 0}@media screen and (max-width: 1055px){.navbar>.container{display:block}.navbar-brand .navbar-item,.navbar-tabs .navbar-item{align-items:center;display:flex}.navbar-link::after{display:none}.navbar-menu{background-color:#fff;box-shadow:0 8px 16px rgba(10,10,10,0.1);padding:0.5rem 0}.navbar-menu.is-active{display:block}.navbar.is-fixed-bottom-touch,.navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-touch{bottom:0}.navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}.navbar.is-fixed-top-touch{top:0}.navbar.is-fixed-top .navbar-menu,.navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 3.25rem);overflow:auto}html.has-navbar-fixed-top-touch,body.has-navbar-fixed-top-touch{padding-top:3.25rem}html.has-navbar-fixed-bottom-touch,body.has-navbar-fixed-bottom-touch{padding-bottom:3.25rem}}@media screen and (min-width: 1056px){.navbar,.navbar-menu,.navbar-start,.navbar-end{align-items:stretch;display:flex}.navbar{min-height:3.25rem}.navbar.is-spaced{padding:1rem 2rem}.navbar.is-spaced .navbar-start,.navbar.is-spaced .navbar-end{align-items:center}.navbar.is-spaced a.navbar-item,.navbar.is-spaced .navbar-link{border-radius:4px}.navbar.is-transparent a.navbar-item:focus,.navbar.is-transparent a.navbar-item:hover,.navbar.is-transparent a.navbar-item.is-active,.navbar.is-transparent .navbar-link:focus,.navbar.is-transparent .navbar-link:hover,.navbar.is-transparent .navbar-link.is-active{background-color:transparent !important}.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent !important}.navbar.is-transparent .navbar-dropdown a.navbar-item:focus,.navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#2e63b8}.navbar-burger{display:none}.navbar-item,.navbar-link{align-items:center;display:flex}.navbar-item{display:flex}.navbar-item.has-dropdown{align-items:stretch}.navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(0.25em, -0.25em)}.navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:2px solid #dbdbdb;border-radius:6px 6px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,0.1);top:auto}.navbar-item.is-active .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar.is-spaced .navbar-item.is-active .navbar-dropdown,.navbar-item.is-active .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed{opacity:1;pointer-events:auto;transform:translateY(0)}.navbar-menu{flex-grow:1;flex-shrink:0}.navbar-start{justify-content:flex-start;margin-right:auto}.navbar-end{justify-content:flex-end;margin-left:auto}.navbar-dropdown{background-color:#fff;border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:2px solid #dbdbdb;box-shadow:0 8px 8px rgba(10,10,10,0.1);display:none;font-size:0.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}.navbar-dropdown .navbar-item{padding:0.375rem 1rem;white-space:nowrap}.navbar-dropdown a.navbar-item{padding-right:3rem}.navbar-dropdown a.navbar-item:focus,.navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#2e63b8}.navbar.is-spaced .navbar-dropdown,.navbar-dropdown.is-boxed{border-radius:6px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity, transform}.navbar-dropdown.is-right{left:auto;right:0}.navbar-divider{display:block}.navbar>.container .navbar-brand,.container>.navbar .navbar-brand{margin-left:-.75rem}.navbar>.container .navbar-menu,.container>.navbar .navbar-menu{margin-right:-.75rem}.navbar.is-fixed-bottom-desktop,.navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-desktop{bottom:0}.navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}.navbar.is-fixed-top-desktop{top:0}html.has-navbar-fixed-top-desktop,body.has-navbar-fixed-top-desktop{padding-top:3.25rem}html.has-navbar-fixed-bottom-desktop,body.has-navbar-fixed-bottom-desktop{padding-bottom:3.25rem}html.has-spaced-navbar-fixed-top,body.has-spaced-navbar-fixed-top{padding-top:5.25rem}html.has-spaced-navbar-fixed-bottom,body.has-spaced-navbar-fixed-bottom{padding-bottom:5.25rem}a.navbar-item.is-active,.navbar-link.is-active{color:#0a0a0a}a.navbar-item.is-active:not(:focus):not(:hover),.navbar-link.is-active:not(:focus):not(:hover){background-color:rgba(0,0,0,0)}.navbar-item.has-dropdown:focus .navbar-link,.navbar-item.has-dropdown:hover .navbar-link,.navbar-item.has-dropdown.is-active .navbar-link{background-color:#fafafa}}.hero.is-fullheight-with-navbar{min-height:calc(100vh - 3.25rem)}.pagination{font-size:1rem;margin:-.25rem}.pagination.is-small,#documenter .docs-sidebar form.docs-search>input.pagination{font-size:.75rem}.pagination.is-medium{font-size:1.25rem}.pagination.is-large{font-size:1.5rem}.pagination.is-rounded .pagination-previous,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-previous,.pagination.is-rounded .pagination-next,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-next{padding-left:1em;padding-right:1em;border-radius:290486px}.pagination.is-rounded .pagination-link,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-link{border-radius:290486px}.pagination,.pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}.pagination-previous,.pagination-next,.pagination-link{border-color:#dbdbdb;color:#363636;min-width:2.25em}.pagination-previous:hover,.pagination-next:hover,.pagination-link:hover{border-color:#b5b5b5;color:#363636}.pagination-previous:focus,.pagination-next:focus,.pagination-link:focus{border-color:#3c5dcd}.pagination-previous:active,.pagination-next:active,.pagination-link:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2)}.pagination-previous[disabled],.pagination-next[disabled],.pagination-link[disabled]{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#6b6b6b;opacity:0.5}.pagination-previous,.pagination-next{padding-left:0.75em;padding-right:0.75em;white-space:nowrap}.pagination-link.is-current{background-color:#2e63b8;border-color:#2e63b8;color:#fff}.pagination-ellipsis{color:#b5b5b5;pointer-events:none}.pagination-list{flex-wrap:wrap}@media screen and (max-width: 768px){.pagination{flex-wrap:wrap}.pagination-previous,.pagination-next{flex-grow:1;flex-shrink:1}.pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width: 769px),print{.pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between}.pagination.is-centered .pagination-previous{order:1}.pagination.is-centered .pagination-list{justify-content:center;order:2}.pagination.is-centered .pagination-next{order:3}.pagination.is-right .pagination-previous{order:1}.pagination.is-right .pagination-next{order:2}.pagination.is-right .pagination-list{justify-content:flex-end;order:3}}.panel{font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel-heading,.panel-tabs,.panel-block{border-bottom:1px solid #dbdbdb;border-left:1px solid #dbdbdb;border-right:1px solid #dbdbdb}.panel-heading:first-child,.panel-tabs:first-child,.panel-block:first-child{border-top:1px solid #dbdbdb}.panel-heading{background-color:#f5f5f5;border-radius:4px 4px 0 0;color:#222;font-size:1.25em;font-weight:300;line-height:1.25;padding:0.5em 0.75em}.panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}.panel-tabs a{border-bottom:1px solid #dbdbdb;margin-bottom:-1px;padding:0.5em}.panel-tabs a.is-active{border-bottom-color:#4a4a4a;color:#363636}.panel-list a{color:#222}.panel-list a:hover{color:#2e63b8}.panel-block{align-items:center;color:#222;display:flex;justify-content:flex-start;padding:0.5em 0.75em}.panel-block input[type="checkbox"]{margin-right:0.75em}.panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}.panel-block.is-wrapped{flex-wrap:wrap}.panel-block.is-active{border-left-color:#2e63b8;color:#363636}.panel-block.is-active .panel-icon{color:#2e63b8}a.panel-block,label.panel-block{cursor:pointer}a.panel-block:hover,label.panel-block:hover{background-color:#f5f5f5}.panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#6b6b6b;margin-right:0.75em}.panel-icon .fa{font-size:inherit;line-height:inherit}.tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}.tabs a{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;color:#222;display:flex;justify-content:center;margin-bottom:-1px;padding:0.5em 1em;vertical-align:top}.tabs a:hover{border-bottom-color:#222;color:#222}.tabs li{display:block}.tabs li.is-active a{border-bottom-color:#2e63b8;color:#2e63b8}.tabs ul{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}.tabs ul.is-left{padding-right:0.75em}.tabs ul.is-center{flex:none;justify-content:center;padding-left:0.75em;padding-right:0.75em}.tabs ul.is-right{justify-content:flex-end;padding-left:0.75em}.tabs .icon:first-child{margin-right:0.5em}.tabs .icon:last-child{margin-left:0.5em}.tabs.is-centered ul{justify-content:center}.tabs.is-right ul{justify-content:flex-end}.tabs.is-boxed a{border:1px solid transparent;border-radius:4px 4px 0 0}.tabs.is-boxed a:hover{background-color:#f5f5f5;border-bottom-color:#dbdbdb}.tabs.is-boxed li.is-active a{background-color:#fff;border-color:#dbdbdb;border-bottom-color:rgba(0,0,0,0) !important}.tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}.tabs.is-toggle a{border-color:#dbdbdb;border-style:solid;border-width:1px;margin-bottom:0;position:relative}.tabs.is-toggle a:hover{background-color:#f5f5f5;border-color:#b5b5b5;z-index:2}.tabs.is-toggle li+li{margin-left:-1px}.tabs.is-toggle li:first-child a{border-radius:4px 0 0 4px}.tabs.is-toggle li:last-child a{border-radius:0 4px 4px 0}.tabs.is-toggle li.is-active a{background-color:#2e63b8;border-color:#2e63b8;color:#fff;z-index:1}.tabs.is-toggle ul{border-bottom:none}.tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:290486px;border-top-left-radius:290486px;padding-left:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:290486px;border-top-right-radius:290486px;padding-right:1.25em}.tabs.is-small,#documenter .docs-sidebar form.docs-search>input.tabs{font-size:.75rem}.tabs.is-medium{font-size:1.25rem}.tabs.is-large{font-size:1.5rem}.column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>.column.is-narrow{flex:none}.columns.is-mobile>.column.is-full{flex:none;width:100%}.columns.is-mobile>.column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>.column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>.column.is-half{flex:none;width:50%}.columns.is-mobile>.column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>.column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>.column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>.column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>.column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>.column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>.column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>.column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>.column.is-offset-half{margin-left:50%}.columns.is-mobile>.column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>.column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>.column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>.column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>.column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>.column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>.column.is-0{flex:none;width:0%}.columns.is-mobile>.column.is-offset-0{margin-left:0%}.columns.is-mobile>.column.is-1{flex:none;width:8.3333333333%}.columns.is-mobile>.column.is-offset-1{margin-left:8.3333333333%}.columns.is-mobile>.column.is-2{flex:none;width:16.6666666667%}.columns.is-mobile>.column.is-offset-2{margin-left:16.6666666667%}.columns.is-mobile>.column.is-3{flex:none;width:25%}.columns.is-mobile>.column.is-offset-3{margin-left:25%}.columns.is-mobile>.column.is-4{flex:none;width:33.3333333333%}.columns.is-mobile>.column.is-offset-4{margin-left:33.3333333333%}.columns.is-mobile>.column.is-5{flex:none;width:41.6666666667%}.columns.is-mobile>.column.is-offset-5{margin-left:41.6666666667%}.columns.is-mobile>.column.is-6{flex:none;width:50%}.columns.is-mobile>.column.is-offset-6{margin-left:50%}.columns.is-mobile>.column.is-7{flex:none;width:58.3333333333%}.columns.is-mobile>.column.is-offset-7{margin-left:58.3333333333%}.columns.is-mobile>.column.is-8{flex:none;width:66.6666666667%}.columns.is-mobile>.column.is-offset-8{margin-left:66.6666666667%}.columns.is-mobile>.column.is-9{flex:none;width:75%}.columns.is-mobile>.column.is-offset-9{margin-left:75%}.columns.is-mobile>.column.is-10{flex:none;width:83.3333333333%}.columns.is-mobile>.column.is-offset-10{margin-left:83.3333333333%}.columns.is-mobile>.column.is-11{flex:none;width:91.6666666667%}.columns.is-mobile>.column.is-offset-11{margin-left:91.6666666667%}.columns.is-mobile>.column.is-12{flex:none;width:100%}.columns.is-mobile>.column.is-offset-12{margin-left:100%}@media screen and (max-width: 768px){.column.is-narrow-mobile{flex:none}.column.is-full-mobile{flex:none;width:100%}.column.is-three-quarters-mobile{flex:none;width:75%}.column.is-two-thirds-mobile{flex:none;width:66.6666%}.column.is-half-mobile{flex:none;width:50%}.column.is-one-third-mobile{flex:none;width:33.3333%}.column.is-one-quarter-mobile{flex:none;width:25%}.column.is-one-fifth-mobile{flex:none;width:20%}.column.is-two-fifths-mobile{flex:none;width:40%}.column.is-three-fifths-mobile{flex:none;width:60%}.column.is-four-fifths-mobile{flex:none;width:80%}.column.is-offset-three-quarters-mobile{margin-left:75%}.column.is-offset-two-thirds-mobile{margin-left:66.6666%}.column.is-offset-half-mobile{margin-left:50%}.column.is-offset-one-third-mobile{margin-left:33.3333%}.column.is-offset-one-quarter-mobile{margin-left:25%}.column.is-offset-one-fifth-mobile{margin-left:20%}.column.is-offset-two-fifths-mobile{margin-left:40%}.column.is-offset-three-fifths-mobile{margin-left:60%}.column.is-offset-four-fifths-mobile{margin-left:80%}.column.is-0-mobile{flex:none;width:0%}.column.is-offset-0-mobile{margin-left:0%}.column.is-1-mobile{flex:none;width:8.3333333333%}.column.is-offset-1-mobile{margin-left:8.3333333333%}.column.is-2-mobile{flex:none;width:16.6666666667%}.column.is-offset-2-mobile{margin-left:16.6666666667%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-left:25%}.column.is-4-mobile{flex:none;width:33.3333333333%}.column.is-offset-4-mobile{margin-left:33.3333333333%}.column.is-5-mobile{flex:none;width:41.6666666667%}.column.is-offset-5-mobile{margin-left:41.6666666667%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-left:50%}.column.is-7-mobile{flex:none;width:58.3333333333%}.column.is-offset-7-mobile{margin-left:58.3333333333%}.column.is-8-mobile{flex:none;width:66.6666666667%}.column.is-offset-8-mobile{margin-left:66.6666666667%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-left:75%}.column.is-10-mobile{flex:none;width:83.3333333333%}.column.is-offset-10-mobile{margin-left:83.3333333333%}.column.is-11-mobile{flex:none;width:91.6666666667%}.column.is-offset-11-mobile{margin-left:91.6666666667%}.column.is-12-mobile{flex:none;width:100%}.column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width: 769px),print{.column.is-narrow,.column.is-narrow-tablet{flex:none}.column.is-full,.column.is-full-tablet{flex:none;width:100%}.column.is-three-quarters,.column.is-three-quarters-tablet{flex:none;width:75%}.column.is-two-thirds,.column.is-two-thirds-tablet{flex:none;width:66.6666%}.column.is-half,.column.is-half-tablet{flex:none;width:50%}.column.is-one-third,.column.is-one-third-tablet{flex:none;width:33.3333%}.column.is-one-quarter,.column.is-one-quarter-tablet{flex:none;width:25%}.column.is-one-fifth,.column.is-one-fifth-tablet{flex:none;width:20%}.column.is-two-fifths,.column.is-two-fifths-tablet{flex:none;width:40%}.column.is-three-fifths,.column.is-three-fifths-tablet{flex:none;width:60%}.column.is-four-fifths,.column.is-four-fifths-tablet{flex:none;width:80%}.column.is-offset-three-quarters,.column.is-offset-three-quarters-tablet{margin-left:75%}.column.is-offset-two-thirds,.column.is-offset-two-thirds-tablet{margin-left:66.6666%}.column.is-offset-half,.column.is-offset-half-tablet{margin-left:50%}.column.is-offset-one-third,.column.is-offset-one-third-tablet{margin-left:33.3333%}.column.is-offset-one-quarter,.column.is-offset-one-quarter-tablet{margin-left:25%}.column.is-offset-one-fifth,.column.is-offset-one-fifth-tablet{margin-left:20%}.column.is-offset-two-fifths,.column.is-offset-two-fifths-tablet{margin-left:40%}.column.is-offset-three-fifths,.column.is-offset-three-fifths-tablet{margin-left:60%}.column.is-offset-four-fifths,.column.is-offset-four-fifths-tablet{margin-left:80%}.column.is-0,.column.is-0-tablet{flex:none;width:0%}.column.is-offset-0,.column.is-offset-0-tablet{margin-left:0%}.column.is-1,.column.is-1-tablet{flex:none;width:8.3333333333%}.column.is-offset-1,.column.is-offset-1-tablet{margin-left:8.3333333333%}.column.is-2,.column.is-2-tablet{flex:none;width:16.6666666667%}.column.is-offset-2,.column.is-offset-2-tablet{margin-left:16.6666666667%}.column.is-3,.column.is-3-tablet{flex:none;width:25%}.column.is-offset-3,.column.is-offset-3-tablet{margin-left:25%}.column.is-4,.column.is-4-tablet{flex:none;width:33.3333333333%}.column.is-offset-4,.column.is-offset-4-tablet{margin-left:33.3333333333%}.column.is-5,.column.is-5-tablet{flex:none;width:41.6666666667%}.column.is-offset-5,.column.is-offset-5-tablet{margin-left:41.6666666667%}.column.is-6,.column.is-6-tablet{flex:none;width:50%}.column.is-offset-6,.column.is-offset-6-tablet{margin-left:50%}.column.is-7,.column.is-7-tablet{flex:none;width:58.3333333333%}.column.is-offset-7,.column.is-offset-7-tablet{margin-left:58.3333333333%}.column.is-8,.column.is-8-tablet{flex:none;width:66.6666666667%}.column.is-offset-8,.column.is-offset-8-tablet{margin-left:66.6666666667%}.column.is-9,.column.is-9-tablet{flex:none;width:75%}.column.is-offset-9,.column.is-offset-9-tablet{margin-left:75%}.column.is-10,.column.is-10-tablet{flex:none;width:83.3333333333%}.column.is-offset-10,.column.is-offset-10-tablet{margin-left:83.3333333333%}.column.is-11,.column.is-11-tablet{flex:none;width:91.6666666667%}.column.is-offset-11,.column.is-offset-11-tablet{margin-left:91.6666666667%}.column.is-12,.column.is-12-tablet{flex:none;width:100%}.column.is-offset-12,.column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width: 1055px){.column.is-narrow-touch{flex:none}.column.is-full-touch{flex:none;width:100%}.column.is-three-quarters-touch{flex:none;width:75%}.column.is-two-thirds-touch{flex:none;width:66.6666%}.column.is-half-touch{flex:none;width:50%}.column.is-one-third-touch{flex:none;width:33.3333%}.column.is-one-quarter-touch{flex:none;width:25%}.column.is-one-fifth-touch{flex:none;width:20%}.column.is-two-fifths-touch{flex:none;width:40%}.column.is-three-fifths-touch{flex:none;width:60%}.column.is-four-fifths-touch{flex:none;width:80%}.column.is-offset-three-quarters-touch{margin-left:75%}.column.is-offset-two-thirds-touch{margin-left:66.6666%}.column.is-offset-half-touch{margin-left:50%}.column.is-offset-one-third-touch{margin-left:33.3333%}.column.is-offset-one-quarter-touch{margin-left:25%}.column.is-offset-one-fifth-touch{margin-left:20%}.column.is-offset-two-fifths-touch{margin-left:40%}.column.is-offset-three-fifths-touch{margin-left:60%}.column.is-offset-four-fifths-touch{margin-left:80%}.column.is-0-touch{flex:none;width:0%}.column.is-offset-0-touch{margin-left:0%}.column.is-1-touch{flex:none;width:8.3333333333%}.column.is-offset-1-touch{margin-left:8.3333333333%}.column.is-2-touch{flex:none;width:16.6666666667%}.column.is-offset-2-touch{margin-left:16.6666666667%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-left:25%}.column.is-4-touch{flex:none;width:33.3333333333%}.column.is-offset-4-touch{margin-left:33.3333333333%}.column.is-5-touch{flex:none;width:41.6666666667%}.column.is-offset-5-touch{margin-left:41.6666666667%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-left:50%}.column.is-7-touch{flex:none;width:58.3333333333%}.column.is-offset-7-touch{margin-left:58.3333333333%}.column.is-8-touch{flex:none;width:66.6666666667%}.column.is-offset-8-touch{margin-left:66.6666666667%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-left:75%}.column.is-10-touch{flex:none;width:83.3333333333%}.column.is-offset-10-touch{margin-left:83.3333333333%}.column.is-11-touch{flex:none;width:91.6666666667%}.column.is-offset-11-touch{margin-left:91.6666666667%}.column.is-12-touch{flex:none;width:100%}.column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width: 1056px){.column.is-narrow-desktop{flex:none}.column.is-full-desktop{flex:none;width:100%}.column.is-three-quarters-desktop{flex:none;width:75%}.column.is-two-thirds-desktop{flex:none;width:66.6666%}.column.is-half-desktop{flex:none;width:50%}.column.is-one-third-desktop{flex:none;width:33.3333%}.column.is-one-quarter-desktop{flex:none;width:25%}.column.is-one-fifth-desktop{flex:none;width:20%}.column.is-two-fifths-desktop{flex:none;width:40%}.column.is-three-fifths-desktop{flex:none;width:60%}.column.is-four-fifths-desktop{flex:none;width:80%}.column.is-offset-three-quarters-desktop{margin-left:75%}.column.is-offset-two-thirds-desktop{margin-left:66.6666%}.column.is-offset-half-desktop{margin-left:50%}.column.is-offset-one-third-desktop{margin-left:33.3333%}.column.is-offset-one-quarter-desktop{margin-left:25%}.column.is-offset-one-fifth-desktop{margin-left:20%}.column.is-offset-two-fifths-desktop{margin-left:40%}.column.is-offset-three-fifths-desktop{margin-left:60%}.column.is-offset-four-fifths-desktop{margin-left:80%}.column.is-0-desktop{flex:none;width:0%}.column.is-offset-0-desktop{margin-left:0%}.column.is-1-desktop{flex:none;width:8.3333333333%}.column.is-offset-1-desktop{margin-left:8.3333333333%}.column.is-2-desktop{flex:none;width:16.6666666667%}.column.is-offset-2-desktop{margin-left:16.6666666667%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-left:25%}.column.is-4-desktop{flex:none;width:33.3333333333%}.column.is-offset-4-desktop{margin-left:33.3333333333%}.column.is-5-desktop{flex:none;width:41.6666666667%}.column.is-offset-5-desktop{margin-left:41.6666666667%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-left:50%}.column.is-7-desktop{flex:none;width:58.3333333333%}.column.is-offset-7-desktop{margin-left:58.3333333333%}.column.is-8-desktop{flex:none;width:66.6666666667%}.column.is-offset-8-desktop{margin-left:66.6666666667%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-left:75%}.column.is-10-desktop{flex:none;width:83.3333333333%}.column.is-offset-10-desktop{margin-left:83.3333333333%}.column.is-11-desktop{flex:none;width:91.6666666667%}.column.is-offset-11-desktop{margin-left:91.6666666667%}.column.is-12-desktop{flex:none;width:100%}.column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width: 1216px){.column.is-narrow-widescreen{flex:none}.column.is-full-widescreen{flex:none;width:100%}.column.is-three-quarters-widescreen{flex:none;width:75%}.column.is-two-thirds-widescreen{flex:none;width:66.6666%}.column.is-half-widescreen{flex:none;width:50%}.column.is-one-third-widescreen{flex:none;width:33.3333%}.column.is-one-quarter-widescreen{flex:none;width:25%}.column.is-one-fifth-widescreen{flex:none;width:20%}.column.is-two-fifths-widescreen{flex:none;width:40%}.column.is-three-fifths-widescreen{flex:none;width:60%}.column.is-four-fifths-widescreen{flex:none;width:80%}.column.is-offset-three-quarters-widescreen{margin-left:75%}.column.is-offset-two-thirds-widescreen{margin-left:66.6666%}.column.is-offset-half-widescreen{margin-left:50%}.column.is-offset-one-third-widescreen{margin-left:33.3333%}.column.is-offset-one-quarter-widescreen{margin-left:25%}.column.is-offset-one-fifth-widescreen{margin-left:20%}.column.is-offset-two-fifths-widescreen{margin-left:40%}.column.is-offset-three-fifths-widescreen{margin-left:60%}.column.is-offset-four-fifths-widescreen{margin-left:80%}.column.is-0-widescreen{flex:none;width:0%}.column.is-offset-0-widescreen{margin-left:0%}.column.is-1-widescreen{flex:none;width:8.3333333333%}.column.is-offset-1-widescreen{margin-left:8.3333333333%}.column.is-2-widescreen{flex:none;width:16.6666666667%}.column.is-offset-2-widescreen{margin-left:16.6666666667%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-left:25%}.column.is-4-widescreen{flex:none;width:33.3333333333%}.column.is-offset-4-widescreen{margin-left:33.3333333333%}.column.is-5-widescreen{flex:none;width:41.6666666667%}.column.is-offset-5-widescreen{margin-left:41.6666666667%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-left:50%}.column.is-7-widescreen{flex:none;width:58.3333333333%}.column.is-offset-7-widescreen{margin-left:58.3333333333%}.column.is-8-widescreen{flex:none;width:66.6666666667%}.column.is-offset-8-widescreen{margin-left:66.6666666667%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-left:75%}.column.is-10-widescreen{flex:none;width:83.3333333333%}.column.is-offset-10-widescreen{margin-left:83.3333333333%}.column.is-11-widescreen{flex:none;width:91.6666666667%}.column.is-offset-11-widescreen{margin-left:91.6666666667%}.column.is-12-widescreen{flex:none;width:100%}.column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width: 1408px){.column.is-narrow-fullhd{flex:none}.column.is-full-fullhd{flex:none;width:100%}.column.is-three-quarters-fullhd{flex:none;width:75%}.column.is-two-thirds-fullhd{flex:none;width:66.6666%}.column.is-half-fullhd{flex:none;width:50%}.column.is-one-third-fullhd{flex:none;width:33.3333%}.column.is-one-quarter-fullhd{flex:none;width:25%}.column.is-one-fifth-fullhd{flex:none;width:20%}.column.is-two-fifths-fullhd{flex:none;width:40%}.column.is-three-fifths-fullhd{flex:none;width:60%}.column.is-four-fifths-fullhd{flex:none;width:80%}.column.is-offset-three-quarters-fullhd{margin-left:75%}.column.is-offset-two-thirds-fullhd{margin-left:66.6666%}.column.is-offset-half-fullhd{margin-left:50%}.column.is-offset-one-third-fullhd{margin-left:33.3333%}.column.is-offset-one-quarter-fullhd{margin-left:25%}.column.is-offset-one-fifth-fullhd{margin-left:20%}.column.is-offset-two-fifths-fullhd{margin-left:40%}.column.is-offset-three-fifths-fullhd{margin-left:60%}.column.is-offset-four-fifths-fullhd{margin-left:80%}.column.is-0-fullhd{flex:none;width:0%}.column.is-offset-0-fullhd{margin-left:0%}.column.is-1-fullhd{flex:none;width:8.3333333333%}.column.is-offset-1-fullhd{margin-left:8.3333333333%}.column.is-2-fullhd{flex:none;width:16.6666666667%}.column.is-offset-2-fullhd{margin-left:16.6666666667%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-left:25%}.column.is-4-fullhd{flex:none;width:33.3333333333%}.column.is-offset-4-fullhd{margin-left:33.3333333333%}.column.is-5-fullhd{flex:none;width:41.6666666667%}.column.is-offset-5-fullhd{margin-left:41.6666666667%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-left:50%}.column.is-7-fullhd{flex:none;width:58.3333333333%}.column.is-offset-7-fullhd{margin-left:58.3333333333%}.column.is-8-fullhd{flex:none;width:66.6666666667%}.column.is-offset-8-fullhd{margin-left:66.6666666667%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-left:75%}.column.is-10-fullhd{flex:none;width:83.3333333333%}.column.is-offset-10-fullhd{margin-left:83.3333333333%}.column.is-11-fullhd{flex:none;width:91.6666666667%}.column.is-offset-11-fullhd{margin-left:91.6666666667%}.column.is-12-fullhd{flex:none;width:100%}.column.is-offset-12-fullhd{margin-left:100%}}.columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.columns:last-child{margin-bottom:-.75rem}.columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}.columns.is-centered{justify-content:center}.columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}.columns.is-gapless>.column{margin:0;padding:0 !important}.columns.is-gapless:not(:last-child){margin-bottom:1.5rem}.columns.is-gapless:last-child{margin-bottom:0}.columns.is-mobile{display:flex}.columns.is-multiline{flex-wrap:wrap}.columns.is-vcentered{align-items:center}@media screen and (min-width: 769px),print{.columns:not(.is-desktop){display:flex}}@media screen and (min-width: 1056px){.columns.is-desktop{display:flex}}.columns.is-variable{--columnGap: 0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}.columns.is-variable .column{padding-left:var(--columnGap);padding-right:var(--columnGap)}.columns.is-variable.is-0{--columnGap: 0rem}@media screen and (max-width: 768px){.columns.is-variable.is-0-mobile{--columnGap: 0rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-0-tablet{--columnGap: 0rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-0-tablet-only{--columnGap: 0rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-0-touch{--columnGap: 0rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-0-desktop{--columnGap: 0rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-0-desktop-only{--columnGap: 0rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-0-widescreen{--columnGap: 0rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-0-widescreen-only{--columnGap: 0rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-0-fullhd{--columnGap: 0rem}}.columns.is-variable.is-1{--columnGap: .25rem}@media screen and (max-width: 768px){.columns.is-variable.is-1-mobile{--columnGap: .25rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-1-tablet{--columnGap: .25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-1-tablet-only{--columnGap: .25rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-1-touch{--columnGap: .25rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-1-desktop{--columnGap: .25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-1-desktop-only{--columnGap: .25rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-1-widescreen{--columnGap: .25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-1-widescreen-only{--columnGap: .25rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-1-fullhd{--columnGap: .25rem}}.columns.is-variable.is-2{--columnGap: .5rem}@media screen and (max-width: 768px){.columns.is-variable.is-2-mobile{--columnGap: .5rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-2-tablet{--columnGap: .5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-2-tablet-only{--columnGap: .5rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-2-touch{--columnGap: .5rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-2-desktop{--columnGap: .5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-2-desktop-only{--columnGap: .5rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-2-widescreen{--columnGap: .5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-2-widescreen-only{--columnGap: .5rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-2-fullhd{--columnGap: .5rem}}.columns.is-variable.is-3{--columnGap: .75rem}@media screen and (max-width: 768px){.columns.is-variable.is-3-mobile{--columnGap: .75rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-3-tablet{--columnGap: .75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-3-tablet-only{--columnGap: .75rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-3-touch{--columnGap: .75rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-3-desktop{--columnGap: .75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-3-desktop-only{--columnGap: .75rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-3-widescreen{--columnGap: .75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-3-widescreen-only{--columnGap: .75rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-3-fullhd{--columnGap: .75rem}}.columns.is-variable.is-4{--columnGap: 1rem}@media screen and (max-width: 768px){.columns.is-variable.is-4-mobile{--columnGap: 1rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-4-tablet{--columnGap: 1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-4-tablet-only{--columnGap: 1rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-4-touch{--columnGap: 1rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-4-desktop{--columnGap: 1rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-4-desktop-only{--columnGap: 1rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-4-widescreen{--columnGap: 1rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-4-widescreen-only{--columnGap: 1rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-4-fullhd{--columnGap: 1rem}}.columns.is-variable.is-5{--columnGap: 1.25rem}@media screen and (max-width: 768px){.columns.is-variable.is-5-mobile{--columnGap: 1.25rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-5-tablet{--columnGap: 1.25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-5-tablet-only{--columnGap: 1.25rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-5-touch{--columnGap: 1.25rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-5-desktop{--columnGap: 1.25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-5-desktop-only{--columnGap: 1.25rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-5-widescreen{--columnGap: 1.25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-5-widescreen-only{--columnGap: 1.25rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-5-fullhd{--columnGap: 1.25rem}}.columns.is-variable.is-6{--columnGap: 1.5rem}@media screen and (max-width: 768px){.columns.is-variable.is-6-mobile{--columnGap: 1.5rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-6-tablet{--columnGap: 1.5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-6-tablet-only{--columnGap: 1.5rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-6-touch{--columnGap: 1.5rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-6-desktop{--columnGap: 1.5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-6-desktop-only{--columnGap: 1.5rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-6-widescreen{--columnGap: 1.5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-6-widescreen-only{--columnGap: 1.5rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-6-fullhd{--columnGap: 1.5rem}}.columns.is-variable.is-7{--columnGap: 1.75rem}@media screen and (max-width: 768px){.columns.is-variable.is-7-mobile{--columnGap: 1.75rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-7-tablet{--columnGap: 1.75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-7-tablet-only{--columnGap: 1.75rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-7-touch{--columnGap: 1.75rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-7-desktop{--columnGap: 1.75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-7-desktop-only{--columnGap: 1.75rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-7-widescreen{--columnGap: 1.75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-7-widescreen-only{--columnGap: 1.75rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-7-fullhd{--columnGap: 1.75rem}}.columns.is-variable.is-8{--columnGap: 2rem}@media screen and (max-width: 768px){.columns.is-variable.is-8-mobile{--columnGap: 2rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-8-tablet{--columnGap: 2rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-8-tablet-only{--columnGap: 2rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-8-touch{--columnGap: 2rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-8-desktop{--columnGap: 2rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-8-desktop-only{--columnGap: 2rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-8-widescreen{--columnGap: 2rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-8-widescreen-only{--columnGap: 2rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-8-fullhd{--columnGap: 2rem}}.tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:min-content}.tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.tile.is-ancestor:last-child{margin-bottom:-.75rem}.tile.is-ancestor:not(:last-child){margin-bottom:.75rem}.tile.is-child{margin:0 !important}.tile.is-parent{padding:.75rem}.tile.is-vertical{flex-direction:column}.tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem !important}@media screen and (min-width: 769px),print{.tile:not(.is-child){display:flex}.tile.is-1{flex:none;width:8.3333333333%}.tile.is-2{flex:none;width:16.6666666667%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.3333333333%}.tile.is-5{flex:none;width:41.6666666667%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.3333333333%}.tile.is-8{flex:none;width:66.6666666667%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.3333333333%}.tile.is-11{flex:none;width:91.6666666667%}.tile.is-12{flex:none;width:100%}}.hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}.hero .navbar{background:none}.hero .tabs ul{border-bottom:none}.hero.is-white{background-color:#fff;color:#0a0a0a}.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-white strong{color:inherit}.hero.is-white .title{color:#0a0a0a}.hero.is-white .subtitle{color:rgba(10,10,10,0.9)}.hero.is-white .subtitle a:not(.button),.hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width: 1055px){.hero.is-white .navbar-menu{background-color:#fff}}.hero.is-white .navbar-item,.hero.is-white .navbar-link{color:rgba(10,10,10,0.7)}.hero.is-white a.navbar-item:hover,.hero.is-white a.navbar-item.is-active,.hero.is-white .navbar-link:hover,.hero.is-white .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.hero.is-white .tabs a{color:#0a0a0a;opacity:0.9}.hero.is-white .tabs a:hover{opacity:1}.hero.is-white .tabs li.is-active a{opacity:1}.hero.is-white .tabs.is-boxed a,.hero.is-white .tabs.is-toggle a{color:#0a0a0a}.hero.is-white .tabs.is-boxed a:hover,.hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-white .tabs.is-boxed li.is-active a,.hero.is-white .tabs.is-boxed li.is-active a:hover,.hero.is-white .tabs.is-toggle li.is-active a,.hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.hero.is-white.is-bold{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}@media screen and (max-width: 768px){.hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}}.hero.is-black{background-color:#0a0a0a;color:#fff}.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-black strong{color:inherit}.hero.is-black .title{color:#fff}.hero.is-black .subtitle{color:rgba(255,255,255,0.9)}.hero.is-black .subtitle a:not(.button),.hero.is-black .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-black .navbar-menu{background-color:#0a0a0a}}.hero.is-black .navbar-item,.hero.is-black .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-black a.navbar-item:hover,.hero.is-black a.navbar-item.is-active,.hero.is-black .navbar-link:hover,.hero.is-black .navbar-link.is-active{background-color:#000;color:#fff}.hero.is-black .tabs a{color:#fff;opacity:0.9}.hero.is-black .tabs a:hover{opacity:1}.hero.is-black .tabs li.is-active a{opacity:1}.hero.is-black .tabs.is-boxed a,.hero.is-black .tabs.is-toggle a{color:#fff}.hero.is-black .tabs.is-boxed a:hover,.hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-black .tabs.is-boxed li.is-active a,.hero.is-black .tabs.is-boxed li.is-active a:hover,.hero.is-black .tabs.is-toggle li.is-active a,.hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.hero.is-black.is-bold{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}@media screen and (max-width: 768px){.hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}}.hero.is-light{background-color:#f5f5f5;color:#363636}.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-light strong{color:inherit}.hero.is-light .title{color:#363636}.hero.is-light .subtitle{color:rgba(54,54,54,0.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:#363636}@media screen and (max-width: 1055px){.hero.is-light .navbar-menu{background-color:#f5f5f5}}.hero.is-light .navbar-item,.hero.is-light .navbar-link{color:rgba(54,54,54,0.7)}.hero.is-light a.navbar-item:hover,.hero.is-light a.navbar-item.is-active,.hero.is-light .navbar-link:hover,.hero.is-light .navbar-link.is-active{background-color:#e8e8e8;color:#363636}.hero.is-light .tabs a{color:#363636;opacity:0.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:#363636}.hero.is-light .tabs.is-boxed a:hover,.hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-light .tabs.is-boxed li.is-active a,.hero.is-light .tabs.is-boxed li.is-active a:hover,.hero.is-light .tabs.is-toggle li.is-active a,.hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:#363636;border-color:#363636;color:#f5f5f5}.hero.is-light.is-bold{background-image:linear-gradient(141deg, #dfd8d9 0%, #f5f5f5 71%, #fff 100%)}@media screen and (max-width: 768px){.hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg, #dfd8d9 0%, #f5f5f5 71%, #fff 100%)}}.hero.is-dark,.content kbd.hero{background-color:#363636;color:#f5f5f5}.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.content kbd.hero a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-dark strong,.content kbd.hero strong{color:inherit}.hero.is-dark .title,.content kbd.hero .title{color:#f5f5f5}.hero.is-dark .subtitle,.content kbd.hero .subtitle{color:rgba(245,245,245,0.9)}.hero.is-dark .subtitle a:not(.button),.content kbd.hero .subtitle a:not(.button),.hero.is-dark .subtitle strong,.content kbd.hero .subtitle strong{color:#f5f5f5}@media screen and (max-width: 1055px){.hero.is-dark .navbar-menu,.content kbd.hero .navbar-menu{background-color:#363636}}.hero.is-dark .navbar-item,.content kbd.hero .navbar-item,.hero.is-dark .navbar-link,.content kbd.hero .navbar-link{color:rgba(245,245,245,0.7)}.hero.is-dark a.navbar-item:hover,.content kbd.hero a.navbar-item:hover,.hero.is-dark a.navbar-item.is-active,.content kbd.hero a.navbar-item.is-active,.hero.is-dark .navbar-link:hover,.content kbd.hero .navbar-link:hover,.hero.is-dark .navbar-link.is-active,.content kbd.hero .navbar-link.is-active{background-color:#292929;color:#f5f5f5}.hero.is-dark .tabs a,.content kbd.hero .tabs a{color:#f5f5f5;opacity:0.9}.hero.is-dark .tabs a:hover,.content kbd.hero .tabs a:hover{opacity:1}.hero.is-dark .tabs li.is-active a,.content kbd.hero .tabs li.is-active a{opacity:1}.hero.is-dark .tabs.is-boxed a,.content kbd.hero .tabs.is-boxed a,.hero.is-dark .tabs.is-toggle a,.content kbd.hero .tabs.is-toggle a{color:#f5f5f5}.hero.is-dark .tabs.is-boxed a:hover,.content kbd.hero .tabs.is-boxed a:hover,.hero.is-dark .tabs.is-toggle a:hover,.content kbd.hero .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-dark .tabs.is-boxed li.is-active a,.content kbd.hero .tabs.is-boxed li.is-active a,.hero.is-dark .tabs.is-boxed li.is-active a:hover,.hero.is-dark .tabs.is-toggle li.is-active a,.content kbd.hero .tabs.is-toggle li.is-active a,.hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#f5f5f5;border-color:#f5f5f5;color:#363636}.hero.is-dark.is-bold,.content kbd.hero.is-bold{background-image:linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%)}@media screen and (max-width: 768px){.hero.is-dark.is-bold .navbar-menu,.content kbd.hero.is-bold .navbar-menu{background-image:linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%)}}.hero.is-primary,.docstring>section>a.hero.docs-sourcelink{background-color:#4eb5de;color:#fff}.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.docstring>section>a.hero.docs-sourcelink a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-primary strong,.docstring>section>a.hero.docs-sourcelink strong{color:inherit}.hero.is-primary .title,.docstring>section>a.hero.docs-sourcelink .title{color:#fff}.hero.is-primary .subtitle,.docstring>section>a.hero.docs-sourcelink .subtitle{color:rgba(255,255,255,0.9)}.hero.is-primary .subtitle a:not(.button),.docstring>section>a.hero.docs-sourcelink .subtitle a:not(.button),.hero.is-primary .subtitle strong,.docstring>section>a.hero.docs-sourcelink .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-primary .navbar-menu,.docstring>section>a.hero.docs-sourcelink .navbar-menu{background-color:#4eb5de}}.hero.is-primary .navbar-item,.docstring>section>a.hero.docs-sourcelink .navbar-item,.hero.is-primary .navbar-link,.docstring>section>a.hero.docs-sourcelink .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-primary a.navbar-item:hover,.docstring>section>a.hero.docs-sourcelink a.navbar-item:hover,.hero.is-primary a.navbar-item.is-active,.docstring>section>a.hero.docs-sourcelink a.navbar-item.is-active,.hero.is-primary .navbar-link:hover,.docstring>section>a.hero.docs-sourcelink .navbar-link:hover,.hero.is-primary .navbar-link.is-active,.docstring>section>a.hero.docs-sourcelink .navbar-link.is-active{background-color:#39acda;color:#fff}.hero.is-primary .tabs a,.docstring>section>a.hero.docs-sourcelink .tabs a{color:#fff;opacity:0.9}.hero.is-primary .tabs a:hover,.docstring>section>a.hero.docs-sourcelink .tabs a:hover{opacity:1}.hero.is-primary .tabs li.is-active a,.docstring>section>a.hero.docs-sourcelink .tabs li.is-active a{opacity:1}.hero.is-primary .tabs.is-boxed a,.docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a,.hero.is-primary .tabs.is-toggle a,.docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a{color:#fff}.hero.is-primary .tabs.is-boxed a:hover,.docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a:hover,.hero.is-primary .tabs.is-toggle a:hover,.docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-primary .tabs.is-boxed li.is-active a,.docstring>section>a.hero.docs-sourcelink .tabs.is-boxed li.is-active a,.hero.is-primary .tabs.is-boxed li.is-active a:hover,.hero.is-primary .tabs.is-toggle li.is-active a,.docstring>section>a.hero.docs-sourcelink .tabs.is-toggle li.is-active a,.hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#4eb5de}.hero.is-primary.is-bold,.docstring>section>a.hero.is-bold.docs-sourcelink{background-image:linear-gradient(141deg, #1bc7de 0%, #4eb5de 71%, #5fa9e7 100%)}@media screen and (max-width: 768px){.hero.is-primary.is-bold .navbar-menu,.docstring>section>a.hero.is-bold.docs-sourcelink .navbar-menu{background-image:linear-gradient(141deg, #1bc7de 0%, #4eb5de 71%, #5fa9e7 100%)}}.hero.is-link{background-color:#2e63b8;color:#fff}.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-link strong{color:inherit}.hero.is-link .title{color:#fff}.hero.is-link .subtitle{color:rgba(255,255,255,0.9)}.hero.is-link .subtitle a:not(.button),.hero.is-link .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-link .navbar-menu{background-color:#2e63b8}}.hero.is-link .navbar-item,.hero.is-link .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-link a.navbar-item:hover,.hero.is-link a.navbar-item.is-active,.hero.is-link .navbar-link:hover,.hero.is-link .navbar-link.is-active{background-color:#2958a4;color:#fff}.hero.is-link .tabs a{color:#fff;opacity:0.9}.hero.is-link .tabs a:hover{opacity:1}.hero.is-link .tabs li.is-active a{opacity:1}.hero.is-link .tabs.is-boxed a,.hero.is-link .tabs.is-toggle a{color:#fff}.hero.is-link .tabs.is-boxed a:hover,.hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-link .tabs.is-boxed li.is-active a,.hero.is-link .tabs.is-boxed li.is-active a:hover,.hero.is-link .tabs.is-toggle li.is-active a,.hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#2e63b8}.hero.is-link.is-bold{background-image:linear-gradient(141deg, #1b6098 0%, #2e63b8 71%, #2d51d2 100%)}@media screen and (max-width: 768px){.hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg, #1b6098 0%, #2e63b8 71%, #2d51d2 100%)}}.hero.is-info{background-color:#209cee;color:#fff}.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-info strong{color:inherit}.hero.is-info .title{color:#fff}.hero.is-info .subtitle{color:rgba(255,255,255,0.9)}.hero.is-info .subtitle a:not(.button),.hero.is-info .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-info .navbar-menu{background-color:#209cee}}.hero.is-info .navbar-item,.hero.is-info .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-info a.navbar-item:hover,.hero.is-info a.navbar-item.is-active,.hero.is-info .navbar-link:hover,.hero.is-info .navbar-link.is-active{background-color:#1190e3;color:#fff}.hero.is-info .tabs a{color:#fff;opacity:0.9}.hero.is-info .tabs a:hover{opacity:1}.hero.is-info .tabs li.is-active a{opacity:1}.hero.is-info .tabs.is-boxed a,.hero.is-info .tabs.is-toggle a{color:#fff}.hero.is-info .tabs.is-boxed a:hover,.hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-info .tabs.is-boxed li.is-active a,.hero.is-info .tabs.is-boxed li.is-active a:hover,.hero.is-info .tabs.is-toggle li.is-active a,.hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#209cee}.hero.is-info.is-bold{background-image:linear-gradient(141deg, #05a6d6 0%, #209cee 71%, #3287f5 100%)}@media screen and (max-width: 768px){.hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg, #05a6d6 0%, #209cee 71%, #3287f5 100%)}}.hero.is-success{background-color:#22c35b;color:#fff}.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-success strong{color:inherit}.hero.is-success .title{color:#fff}.hero.is-success .subtitle{color:rgba(255,255,255,0.9)}.hero.is-success .subtitle a:not(.button),.hero.is-success .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-success .navbar-menu{background-color:#22c35b}}.hero.is-success .navbar-item,.hero.is-success .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-success a.navbar-item:hover,.hero.is-success a.navbar-item.is-active,.hero.is-success .navbar-link:hover,.hero.is-success .navbar-link.is-active{background-color:#1ead51;color:#fff}.hero.is-success .tabs a{color:#fff;opacity:0.9}.hero.is-success .tabs a:hover{opacity:1}.hero.is-success .tabs li.is-active a{opacity:1}.hero.is-success .tabs.is-boxed a,.hero.is-success .tabs.is-toggle a{color:#fff}.hero.is-success .tabs.is-boxed a:hover,.hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-success .tabs.is-boxed li.is-active a,.hero.is-success .tabs.is-boxed li.is-active a:hover,.hero.is-success .tabs.is-toggle li.is-active a,.hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#22c35b}.hero.is-success.is-bold{background-image:linear-gradient(141deg, #12a02c 0%, #22c35b 71%, #1fdf83 100%)}@media screen and (max-width: 768px){.hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg, #12a02c 0%, #22c35b 71%, #1fdf83 100%)}}.hero.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-warning strong{color:inherit}.hero.is-warning .title{color:rgba(0,0,0,0.7)}.hero.is-warning .subtitle{color:rgba(0,0,0,0.9)}.hero.is-warning .subtitle a:not(.button),.hero.is-warning .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1055px){.hero.is-warning .navbar-menu{background-color:#ffdd57}}.hero.is-warning .navbar-item,.hero.is-warning .navbar-link{color:rgba(0,0,0,0.7)}.hero.is-warning a.navbar-item:hover,.hero.is-warning a.navbar-item.is-active,.hero.is-warning .navbar-link:hover,.hero.is-warning .navbar-link.is-active{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.hero.is-warning .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}.hero.is-warning .tabs a:hover{opacity:1}.hero.is-warning .tabs li.is-active a{opacity:1}.hero.is-warning .tabs.is-boxed a,.hero.is-warning .tabs.is-toggle a{color:rgba(0,0,0,0.7)}.hero.is-warning .tabs.is-boxed a:hover,.hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-warning .tabs.is-boxed li.is-active a,.hero.is-warning .tabs.is-boxed li.is-active a:hover,.hero.is-warning .tabs.is-toggle li.is-active a,.hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#ffdd57}.hero.is-warning.is-bold{background-image:linear-gradient(141deg, #ffae24 0%, #ffdd57 71%, #fffa71 100%)}@media screen and (max-width: 768px){.hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg, #ffae24 0%, #ffdd57 71%, #fffa71 100%)}}.hero.is-danger{background-color:#da0b00;color:#fff}.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-danger strong{color:inherit}.hero.is-danger .title{color:#fff}.hero.is-danger .subtitle{color:rgba(255,255,255,0.9)}.hero.is-danger .subtitle a:not(.button),.hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-danger .navbar-menu{background-color:#da0b00}}.hero.is-danger .navbar-item,.hero.is-danger .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-danger a.navbar-item:hover,.hero.is-danger a.navbar-item.is-active,.hero.is-danger .navbar-link:hover,.hero.is-danger .navbar-link.is-active{background-color:#c10a00;color:#fff}.hero.is-danger .tabs a{color:#fff;opacity:0.9}.hero.is-danger .tabs a:hover{opacity:1}.hero.is-danger .tabs li.is-active a{opacity:1}.hero.is-danger .tabs.is-boxed a,.hero.is-danger .tabs.is-toggle a{color:#fff}.hero.is-danger .tabs.is-boxed a:hover,.hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-danger .tabs.is-boxed li.is-active a,.hero.is-danger .tabs.is-boxed li.is-active a:hover,.hero.is-danger .tabs.is-toggle li.is-active a,.hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#da0b00}.hero.is-danger.is-bold{background-image:linear-gradient(141deg, #a70013 0%, #da0b00 71%, #f43500 100%)}@media screen and (max-width: 768px){.hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg, #a70013 0%, #da0b00 71%, #f43500 100%)}}.hero.is-small .hero-body,#documenter .docs-sidebar form.docs-search>input.hero .hero-body{padding-bottom:1.5rem;padding-top:1.5rem}@media screen and (min-width: 769px),print{.hero.is-medium .hero-body{padding-bottom:9rem;padding-top:9rem}}@media screen and (min-width: 769px),print{.hero.is-large .hero-body{padding-bottom:18rem;padding-top:18rem}}.hero.is-halfheight .hero-body,.hero.is-fullheight .hero-body,.hero.is-fullheight-with-navbar .hero-body{align-items:center;display:flex}.hero.is-halfheight .hero-body>.container,.hero.is-fullheight .hero-body>.container,.hero.is-fullheight-with-navbar .hero-body>.container{flex-grow:1;flex-shrink:1}.hero.is-halfheight{min-height:50vh}.hero.is-fullheight{min-height:100vh}.hero-video{overflow:hidden}.hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%, -50%, 0)}.hero-video.is-transparent{opacity:0.3}@media screen and (max-width: 768px){.hero-video{display:none}}.hero-buttons{margin-top:1.5rem}@media screen and (max-width: 768px){.hero-buttons .button{display:flex}.hero-buttons .button:not(:last-child){margin-bottom:0.75rem}}@media screen and (min-width: 769px),print{.hero-buttons{display:flex;justify-content:center}.hero-buttons .button:not(:last-child){margin-right:1.5rem}}.hero-head,.hero-foot{flex-grow:0;flex-shrink:0}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}.section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){.section.is-medium{padding:9rem 1.5rem}.section.is-large{padding:18rem 1.5rem}}.footer{background-color:#fafafa;padding:3rem 1.5rem 6rem}h1 .docs-heading-anchor,h1 .docs-heading-anchor:hover,h1 .docs-heading-anchor:visited,h2 .docs-heading-anchor,h2 .docs-heading-anchor:hover,h2 .docs-heading-anchor:visited,h3 .docs-heading-anchor,h3 .docs-heading-anchor:hover,h3 .docs-heading-anchor:visited,h4 .docs-heading-anchor,h4 .docs-heading-anchor:hover,h4 .docs-heading-anchor:visited,h5 .docs-heading-anchor,h5 .docs-heading-anchor:hover,h5 .docs-heading-anchor:visited,h6 .docs-heading-anchor,h6 .docs-heading-anchor:hover,h6 .docs-heading-anchor:visited{color:#222}h1 .docs-heading-anchor-permalink,h2 .docs-heading-anchor-permalink,h3 .docs-heading-anchor-permalink,h4 .docs-heading-anchor-permalink,h5 .docs-heading-anchor-permalink,h6 .docs-heading-anchor-permalink{visibility:hidden;vertical-align:middle;margin-left:0.5em;font-size:0.7rem}h1 .docs-heading-anchor-permalink::before,h2 .docs-heading-anchor-permalink::before,h3 .docs-heading-anchor-permalink::before,h4 .docs-heading-anchor-permalink::before,h5 .docs-heading-anchor-permalink::before,h6 .docs-heading-anchor-permalink::before{font-family:"Font Awesome 5 Free";font-weight:900;content:"\f0c1"}h1:hover .docs-heading-anchor-permalink,h2:hover .docs-heading-anchor-permalink,h3:hover .docs-heading-anchor-permalink,h4:hover .docs-heading-anchor-permalink,h5:hover .docs-heading-anchor-permalink,h6:hover .docs-heading-anchor-permalink{visibility:visible}.docs-dark-only{display:none !important}pre{position:relative;overflow:hidden}pre code,pre code.hljs{padding:0 .75rem !important;overflow:auto;display:block}pre code:first-of-type,pre code.hljs:first-of-type{padding-top:0.5rem !important}pre code:last-of-type,pre code.hljs:last-of-type{padding-bottom:0.5rem !important}pre .copy-button{opacity:0.2;transition:opacity 0.2s;position:absolute;right:0em;top:0em;padding:0.5em;width:2.5em;height:2.5em;background:transparent;border:none;font-family:"Font Awesome 5 Free";color:#222;cursor:pointer;text-align:center}pre .copy-button:focus,pre .copy-button:hover{opacity:1;background:rgba(34,34,34,0.1);color:#2e63b8}pre .copy-button.success{color:#259a12;opacity:1}pre .copy-button.error{color:#cb3c33;opacity:1}pre:hover .copy-button{opacity:1}.admonition{background-color:#b5b5b5;border-style:solid;border-width:1px;border-color:#363636;border-radius:4px;font-size:1rem}.admonition strong{color:currentColor}.admonition.is-small,#documenter .docs-sidebar form.docs-search>input.admonition{font-size:.75rem}.admonition.is-medium{font-size:1.25rem}.admonition.is-large{font-size:1.5rem}.admonition.is-default{background-color:#b5b5b5;border-color:#363636}.admonition.is-default>.admonition-header{background-color:#363636;color:#fff}.admonition.is-default>.admonition-body{color:#fff}.admonition.is-info{background-color:#def0fc;border-color:#209cee}.admonition.is-info>.admonition-header{background-color:#209cee;color:#fff}.admonition.is-info>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-success{background-color:#bdf4d1;border-color:#22c35b}.admonition.is-success>.admonition-header{background-color:#22c35b;color:#fff}.admonition.is-success>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-warning{background-color:#fff3c5;border-color:#ffdd57}.admonition.is-warning>.admonition-header{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.admonition.is-warning>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-danger{background-color:#ffaba7;border-color:#da0b00}.admonition.is-danger>.admonition-header{background-color:#da0b00;color:#fff}.admonition.is-danger>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-compat{background-color:#bdeff5;border-color:#1db5c9}.admonition.is-compat>.admonition-header{background-color:#1db5c9;color:#fff}.admonition.is-compat>.admonition-body{color:rgba(0,0,0,0.7)}.admonition-header{color:#fff;background-color:#363636;align-items:center;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.5rem .75rem;position:relative}.admonition-header:before{font-family:"Font Awesome 5 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}.admonition-body{color:#222;padding:0.5rem .75rem}.admonition-body pre{background-color:#f5f5f5}.admonition-body code{background-color:rgba(0,0,0,0.05)}.docstring{margin-bottom:1em;background-color:rgba(0,0,0,0);border:1px solid #dbdbdb;box-shadow:2px 2px 3px rgba(10,10,10,0.1);max-width:100%}.docstring>header{display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#f5f5f5;box-shadow:0 1px 2px rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #dbdbdb}.docstring>header code{background-color:transparent}.docstring>header .docstring-binding{margin-right:0.3em}.docstring>header .docstring-category{margin-left:0.3em}.docstring>section{position:relative;padding:.75rem .75rem;border-bottom:1px solid #dbdbdb}.docstring>section:last-child{border-bottom:none}.docstring>section>a.docs-sourcelink{transition:opacity 0.3s;opacity:0;position:absolute;right:.375rem;bottom:.375rem}.docstring>section>a.docs-sourcelink:focus{opacity:1 !important}.docstring:hover>section>a.docs-sourcelink{opacity:0.2}.docstring:focus-within>section>a.docs-sourcelink{opacity:0.2}.docstring>section:hover a.docs-sourcelink{opacity:1}.documenter-example-output{background-color:#fff}.outdated-warning-overlay{position:fixed;top:0;left:0;right:0;box-shadow:0 0 10px rgba(0,0,0,0.3);z-index:999;background-color:#ffaba7;color:rgba(0,0,0,0.7);border-bottom:3px solid #da0b00;padding:10px 35px;text-align:center;font-size:15px}.outdated-warning-overlay .outdated-warning-closer{position:absolute;top:calc(50% - 10px);right:18px;cursor:pointer;width:12px}.outdated-warning-overlay a{color:#2e63b8}.outdated-warning-overlay a:hover{color:#363636}.content pre{border:1px solid #dbdbdb}.content code{font-weight:inherit}.content a code{color:#2e63b8}.content h1 code,.content h2 code,.content h3 code,.content h4 code,.content h5 code,.content h6 code{color:#222}.content table{display:block;width:initial;max-width:100%;overflow-x:auto}.content blockquote>ul:first-child,.content blockquote>ol:first-child,.content .admonition-body>ul:first-child,.content .admonition-body>ol:first-child{margin-top:0}pre,code{font-variant-ligatures:no-contextual}.breadcrumb a.is-disabled{cursor:default;pointer-events:none}.breadcrumb a.is-disabled,.breadcrumb a.is-disabled:hover{color:#222}.hljs{background:initial !important}.katex .katex-mathml{top:0;right:0}.katex-display,mjx-container,.MathJax_Display{margin:0.5em 0 !important}html{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto}li.no-marker{list-style:none}#documenter .docs-main>article{overflow-wrap:break-word}#documenter .docs-main>article .math-container{overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1056px){#documenter .docs-main{max-width:52rem;margin-left:20rem;padding-right:1rem}}@media screen and (max-width: 1055px){#documenter .docs-main{width:100%}#documenter .docs-main>article{max-width:52rem;margin-left:auto;margin-right:auto;margin-bottom:1rem;padding:0 1rem}#documenter .docs-main>header,#documenter .docs-main>nav{max-width:100%;width:100%;margin:0}}#documenter .docs-main header.docs-navbar{background-color:#fff;border-bottom:1px solid #dbdbdb;z-index:2;min-height:4rem;margin-bottom:1rem;display:flex}#documenter .docs-main header.docs-navbar .breadcrumb{flex-grow:1}#documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap}#documenter .docs-main header.docs-navbar .docs-right .docs-icon,#documenter .docs-main header.docs-navbar .docs-right .docs-label,#documenter .docs-main header.docs-navbar .docs-right .docs-sidebar-button{display:inline-block}#documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}#documenter .docs-main header.docs-navbar .docs-right .docs-settings-button{margin:auto 0 auto 1rem}#documenter .docs-main header.docs-navbar .docs-right .docs-sidebar-button{font-size:1.5rem;margin:auto 0 auto 1rem}#documenter .docs-main header.docs-navbar>*{margin:auto 0}@media screen and (max-width: 1055px){#documenter .docs-main header.docs-navbar{position:sticky;top:0;padding:0 1rem;transition-property:top, box-shadow;-webkit-transition-property:top, box-shadow;transition-duration:0.3s;-webkit-transition-duration:0.3s}#documenter .docs-main header.docs-navbar.headroom--not-top{box-shadow:.2rem 0rem .4rem #bbb;transition-duration:0.7s;-webkit-transition-duration:0.7s}#documenter .docs-main header.docs-navbar.headroom--unpinned.headroom--not-top.headroom--not-bottom{top:-4.5rem;transition-duration:0.7s;-webkit-transition-duration:0.7s}}#documenter .docs-main section.footnotes{border-top:1px solid #dbdbdb}#documenter .docs-main section.footnotes li .tag:first-child,#documenter .docs-main section.footnotes li .docstring>section>a.docs-sourcelink:first-child,#documenter .docs-main section.footnotes li .content kbd:first-child,.content #documenter .docs-main section.footnotes li kbd:first-child{margin-right:1em;margin-bottom:0.4em}#documenter .docs-main .docs-footer{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;border-top:1px solid #dbdbdb;padding-top:1rem;padding-bottom:1rem}@media screen and (max-width: 1055px){#documenter .docs-main .docs-footer{padding-left:1rem;padding-right:1rem}}#documenter .docs-main .docs-footer .docs-footer-nextpage,#documenter .docs-main .docs-footer .docs-footer-prevpage{flex-grow:1}#documenter .docs-main .docs-footer .docs-footer-nextpage{text-align:right}#documenter .docs-main .docs-footer .flexbox-break{flex-basis:100%;height:0}#documenter .docs-main .docs-footer .footer-message{font-size:0.8em;margin:0.5em auto 0 auto;text-align:center}#documenter .docs-sidebar{display:flex;flex-direction:column;color:#0a0a0a;background-color:#f5f5f5;border-right:1px solid #dbdbdb;padding:0;flex:0 0 18rem;z-index:5;font-size:1rem;position:fixed;left:-18rem;width:18rem;height:100%;transition:left 0.3s}#documenter .docs-sidebar.visible{left:0;box-shadow:.4rem 0rem .8rem #bbb}@media screen and (min-width: 1056px){#documenter .docs-sidebar.visible{box-shadow:none}}@media screen and (min-width: 1056px){#documenter .docs-sidebar{left:0;top:0}}#documenter .docs-sidebar .docs-logo{margin-top:1rem;padding:0 1rem}#documenter .docs-sidebar .docs-logo>img{max-height:6rem;margin:auto}#documenter .docs-sidebar .docs-package-name{flex-shrink:0;font-size:1.5rem;font-weight:700;text-align:center;white-space:nowrap;overflow:hidden;padding:0.5rem 0}#documenter .docs-sidebar .docs-package-name .docs-autofit{max-width:16.2rem}#documenter .docs-sidebar .docs-package-name a,#documenter .docs-sidebar .docs-package-name a:hover{color:#0a0a0a}#documenter .docs-sidebar .docs-version-selector{border-top:1px solid #dbdbdb;display:none;padding:0.5rem}#documenter .docs-sidebar .docs-version-selector.visible{display:flex}#documenter .docs-sidebar ul.docs-menu{flex-grow:1;user-select:none;border-top:1px solid #dbdbdb;padding-bottom:1.5rem}#documenter .docs-sidebar ul.docs-menu>li>.tocitem{font-weight:bold}#documenter .docs-sidebar ul.docs-menu>li li{font-size:.95rem;margin-left:1em;border-left:1px solid #dbdbdb}#documenter .docs-sidebar ul.docs-menu input.collapse-toggle{display:none}#documenter .docs-sidebar ul.docs-menu ul.collapsed{display:none}#documenter .docs-sidebar ul.docs-menu input:checked~ul.collapsed{display:block}#documenter .docs-sidebar ul.docs-menu label.tocitem{display:flex}#documenter .docs-sidebar ul.docs-menu label.tocitem .docs-label{flex-grow:2}#documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;font-size:.75rem;margin-left:1rem;margin-top:auto;margin-bottom:auto}#documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron::before{font-family:"Font Awesome 5 Free";font-weight:900;content:"\f054"}#documenter .docs-sidebar ul.docs-menu input:checked~label.tocitem .docs-chevron::before{content:"\f078"}#documenter .docs-sidebar ul.docs-menu .tocitem{display:block;padding:0.5rem 0.5rem}#documenter .docs-sidebar ul.docs-menu .tocitem,#documenter .docs-sidebar ul.docs-menu .tocitem:hover{color:#0a0a0a;background:#f5f5f5}#documenter .docs-sidebar ul.docs-menu a.tocitem:hover,#documenter .docs-sidebar ul.docs-menu label.tocitem:hover{color:#0a0a0a;background-color:#ebebeb}#documenter .docs-sidebar ul.docs-menu li.is-active{border-top:1px solid #dbdbdb;border-bottom:1px solid #dbdbdb;background-color:#fff}#documenter .docs-sidebar ul.docs-menu li.is-active .tocitem,#documenter .docs-sidebar ul.docs-menu li.is-active .tocitem:hover{background-color:#fff;color:#0a0a0a}#documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem:hover{background-color:#ebebeb;color:#0a0a0a}#documenter .docs-sidebar ul.docs-menu>li.is-active:first-child{border-top:none}#documenter .docs-sidebar ul.docs-menu ul.internal{margin:0 0.5rem 0.5rem;border-top:1px solid #dbdbdb}#documenter .docs-sidebar ul.docs-menu ul.internal li{font-size:.85rem;border-left:none;margin-left:0;margin-top:0.5rem}#documenter .docs-sidebar ul.docs-menu ul.internal .tocitem{width:100%;padding:0}#documenter .docs-sidebar ul.docs-menu ul.internal .tocitem::before{content:"⚬";margin-right:0.4em}#documenter .docs-sidebar form.docs-search{margin:auto;margin-top:0.5rem;margin-bottom:0.5rem}#documenter .docs-sidebar form.docs-search>input{width:14.4rem}@media screen and (min-width: 1056px){#documenter .docs-sidebar ul.docs-menu{overflow-y:auto;-webkit-overflow-scroll:touch}#documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar{width:.3rem;background:none}#documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#e0e0e0}#documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb:hover{background:#ccc}}@media screen and (max-width: 1055px){#documenter .docs-sidebar{overflow-y:auto;-webkit-overflow-scroll:touch}#documenter .docs-sidebar::-webkit-scrollbar{width:.3rem;background:none}#documenter .docs-sidebar::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#e0e0e0}#documenter .docs-sidebar::-webkit-scrollbar-thumb:hover{background:#ccc}}#documenter .docs-main #documenter-search-info{margin-bottom:1rem}#documenter .docs-main #documenter-search-results{list-style-type:circle;list-style-position:outside}#documenter .docs-main #documenter-search-results li{margin-left:2rem}#documenter .docs-main #documenter-search-results .docs-highlight{background-color:yellow}.ansi span.sgr1{font-weight:bolder}.ansi span.sgr2{font-weight:lighter}.ansi span.sgr3{font-style:italic}.ansi span.sgr4{text-decoration:underline}.ansi span.sgr7{color:#fff;background-color:#222}.ansi span.sgr8{color:transparent}.ansi span.sgr8 span{color:transparent}.ansi span.sgr9{text-decoration:line-through}.ansi span.sgr30{color:#242424}.ansi span.sgr31{color:#a7201f}.ansi span.sgr32{color:#066f00}.ansi span.sgr33{color:#856b00}.ansi span.sgr34{color:#2149b0}.ansi span.sgr35{color:#7d4498}.ansi span.sgr36{color:#007989}.ansi span.sgr37{color:gray}.ansi span.sgr40{background-color:#242424}.ansi span.sgr41{background-color:#a7201f}.ansi span.sgr42{background-color:#066f00}.ansi span.sgr43{background-color:#856b00}.ansi span.sgr44{background-color:#2149b0}.ansi span.sgr45{background-color:#7d4498}.ansi span.sgr46{background-color:#007989}.ansi span.sgr47{background-color:gray}.ansi span.sgr90{color:#616161}.ansi span.sgr91{color:#cb3c33}.ansi span.sgr92{color:#0e8300}.ansi span.sgr93{color:#a98800}.ansi span.sgr94{color:#3c5dcd}.ansi span.sgr95{color:#9256af}.ansi span.sgr96{color:#008fa3}.ansi span.sgr97{color:#f5f5f5}.ansi span.sgr100{background-color:#616161}.ansi span.sgr101{background-color:#cb3c33}.ansi span.sgr102{background-color:#0e8300}.ansi span.sgr103{background-color:#a98800}.ansi span.sgr104{background-color:#3c5dcd}.ansi span.sgr105{background-color:#9256af}.ansi span.sgr106{background-color:#008fa3}.ansi span.sgr107{background-color:#f5f5f5}code.language-julia-repl>span.hljs-meta{color:#066f00;font-weight:bolder}/*! + Theme: Default + Description: Original highlight.js style + Author: (c) Ivan Sagalaev + Maintainer: @highlightjs/core-team + Website: https://highlightjs.org/ + License: see project LICENSE + Touched: 2021 +*/pre code.hljs{display:block;overflow-x:auto}code.hljs{padding:3px 5px}.hljs{background:#F0F0F0;color:#444}.hljs-comment{color:#888888}.hljs-tag,.hljs-punctuation{color:#444a}.hljs-tag .hljs-name,.hljs-tag .hljs-attr{color:#444}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta .hljs-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-operator,.hljs-selector-pseudo{color:#BC6060}.hljs-literal{color:#78A960}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold} diff --git a/previews/PR539/assets/themeswap.js b/previews/PR539/assets/themeswap.js new file mode 100644 index 000000000..c58e993e3 --- /dev/null +++ b/previews/PR539/assets/themeswap.js @@ -0,0 +1,66 @@ +// Small function to quickly swap out themes. Gets put into the tag.. +function set_theme_from_local_storage() { + // Intialize the theme to null, which means default + var theme = null; + // If the browser supports the localstorage and is not disabled then try to get the + // documenter theme + if(window.localStorage != null) { + // Get the user-picked theme from localStorage. May be `null`, which means the default + // theme. + theme = window.localStorage.getItem("documenter-theme"); + } + // Check if the browser supports user color preference + var darkPreference = false; + // Check if the users preference is for dark color scheme + if(window.matchMedia('(prefers-color-scheme: dark)').matches === true) { + darkPreference = true; + } + // Initialize a few variables for the loop: + // + // - active: will contain the index of the theme that should be active. Note that there + // is no guarantee that localStorage contains sane values. If `active` stays `null` + // we either could not find the theme or it is the default (primary) theme anyway. + // Either way, we then need to stick to the primary theme. + // + // - disabled: style sheets that should be disabled (i.e. all the theme style sheets + // that are not the currently active theme) + var active = null; var disabled = []; var darkTheme = null; + for (var i = 0; i < document.styleSheets.length; i++) { + var ss = document.styleSheets[i]; + // The tag of each style sheet is expected to have a data-theme-name attribute + // which must contain the name of the theme. The names in localStorage much match this. + var themename = ss.ownerNode.getAttribute("data-theme-name"); + // attribute not set => non-theme stylesheet => ignore + if(themename === null) continue; + // To distinguish the default (primary) theme, it needs to have the data-theme-primary + // attribute set. + var isprimary = (ss.ownerNode.getAttribute("data-theme-primary") !== null); + // Check if the theme is primary dark theme + var isDarkTheme = (ss.ownerNode.getAttribute("data-theme-primary-dark") !== null); + // If ss is for dark theme then set the value of darkTheme to the name of the theme + if(isDarkTheme) darkTheme = themename; + // If we find a matching theme (and it's not the default), we'll set active to non-null + if(themename === theme) active = i; + // Store the style sheets of inactive themes so that we could disable them + if(themename !== theme) disabled.push(ss); + } + if(active !== null) { + // If we did find an active theme, we'll (1) add the theme--$(theme) class to + document.getElementsByTagName('html')[0].className = "theme--" + theme; + // and (2) disable all the other theme stylesheets + disabled.forEach(function(ss){ + ss.disabled = true; + }); + } + else if(darkTheme !== null && darkPreference === true) { + // If we did find an active theme, we'll (1) add the theme--$(theme) class to + document.getElementsByTagName('html')[0].className = "theme--" + darkTheme; + // and (2) disable all the other theme stylesheets + disabled.forEach(function(ss){ + if (ss.ownerNode.getAttribute("data-theme-name") !== darkTheme) { + ss.disabled = true; + } + }); + } +} +set_theme_from_local_storage(); diff --git a/previews/PR539/assets/warner.js b/previews/PR539/assets/warner.js new file mode 100644 index 000000000..5531c8851 --- /dev/null +++ b/previews/PR539/assets/warner.js @@ -0,0 +1,49 @@ +function maybeAddWarning () { + // DOCUMENTER_NEWEST is defined in versions.js, DOCUMENTER_CURRENT_VERSION and DOCUMENTER_STABLE + // in siteinfo.js. + // If either of these are undefined something went horribly wrong, so we abort. + if ( + window.DOCUMENTER_NEWEST === undefined || + window.DOCUMENTER_CURRENT_VERSION === undefined || + window.DOCUMENTER_STABLE === undefined + ) { + return + }; + + // Current version is not a version number, so we can't tell if it's the newest version. Abort. + if (!/v(\d+\.)*\d+/.test(window.DOCUMENTER_CURRENT_VERSION)) { + return + }; + + // Current version is newest version, so no need to add a warning. + if (window.DOCUMENTER_NEWEST === window.DOCUMENTER_CURRENT_VERSION) { + return + }; + + // Add a noindex meta tag (unless one exists) so that search engines don't index this version of the docs. + if (document.body.querySelector('meta[name="robots"]') === null) { + const meta = document.createElement('meta'); + meta.name = 'robots'; + meta.content = 'noindex'; + + document.getElementsByTagName('head')[0].appendChild(meta); + }; + + const div = document.createElement('div'); + div.classList.add('outdated-warning-overlay'); + const closer = document.createElement('button'); + closer.classList.add('outdated-warning-closer', 'delete'); + closer.addEventListener('click', function () { + document.body.removeChild(div); + }); + const href = window.documenterBaseURL + '/../' + window.DOCUMENTER_STABLE; + div.innerHTML = 'This documentation is not for the latest stable release, but for either the development version or an older release.
    Click here to go to the documentation for the latest stable release.'; + div.appendChild(closer); + document.body.appendChild(div); +}; + +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', maybeAddWarning); +} else { + maybeAddWarning(); +}; diff --git a/previews/PR539/basics/index.html b/previews/PR539/basics/index.html new file mode 100644 index 000000000..b0aaeb57e --- /dev/null +++ b/previews/PR539/basics/index.html @@ -0,0 +1,2 @@ + +How does it work? · FrankWolfe.jl

    How does it work?

    FrankWolfe.jl contains generic routines to solve optimization problems of the form

    \[\min_{x \in \mathcal{C}} f(x)\]

    where $\mathcal{C}$ is a compact convex set and $f$ is a differentiable function. These routines work by solving a sequence of linear subproblems:

    \[\min_{x \in \mathcal{C}} \langle d_k, x \rangle \quad \text{where} \quad d_k = \nabla f(x_k)\]

    Linear Minimization Oracles

    The Linear Minimization Oracle (LMO) is a key component, which is called at each iteration of the FW algorithm. Given a direction $d$, it returns an optimal vertex of the feasible set:

    \[v \in \arg \min_{x\in \mathcal{C}} \langle d,x \rangle.\]

    Custom LMOs

    To be used by the algorithms provided here, an LMO must be a subtype of FrankWolfe.LinearMinimizationOracle and implement the following method:

    compute_extreme_point(lmo::LMO, direction; kwargs...) -> v

    This method should minimize $v \mapsto \langle d, v \rangle$ over the set $\mathcal{C}$ defined by the LMO. Note that this means the set $\mathcal{C}$ doesn't have to be represented explicitly: all we need is to be able to minimize a linear function over it, even if the minimization procedure is a black box.

    Pre-defined LMOs

    If you don't want to define your LMO manually, several common implementations are available out-of-the-box:

    • Simplices: unit simplex, probability simplex
    • Balls in various norms
    • Polytopes: K-sparse, Birkhoff

    You can use an oracle defined via a Linear Programming solver (e.g. SCIP or HiGHS) with MathOptInferface: see FrankWolfe.MathOptLMO.

    Finally, we provide wrappers to combine oracles easily, for example in a product.

    See Combettes, Pokutta (2021) for references on most LMOs implemented in the package and their comparison with projection operators.

    Optimization algorithms

    The package features several variants of Frank-Wolfe that share the same basic API.

    Most of the algorithms listed below also have a lazified version: see Braun, Pokutta, Zink (2016).

    Standard Frank-Wolfe (FW)

    It is implemented in the frank_wolfe function.

    See Jaggi (2013) for an overview.

    This algorithm works both for convex and non-convex functions (use step size rule FrankWolfe.Nonconvex() in the second case).

    Away-step Frank-Wolfe (AFW)

    It is implemented in the away_frank_wolfe function.

    See Lacoste-Julien, Jaggi (2015) for an overview.

    Stochastic Frank-Wolfe (SFW)

    It is implemented in the FrankWolfe.stochastic_frank_wolfe function.

    Blended Conditional Gradients (BCG)

    It is implemented in the blended_conditional_gradient function, with a built-in stability feature that temporarily increases accuracy.

    See Braun, Pokutta, Tu, Wright (2018).

    Pairwise Frank-Wolfe (PFW)

    It is implemented in the pairwise_frank_wolfe function. See Lacoste-Julien, Jaggi (2015) for an overview.

    Blended Pairwise Conditional Gradients (BPCG)

    It is implemented in the FrankWolfe.blended_pairwise_conditional_gradient function, with a minor modification to improve sparsity.

    See Tsuji, Tanaka, Pokutta (2021)

    Comparison

    The following table compares the characteristics of the algorithms presented in the package:

    AlgorithmProgress/IterationTime/IterationSparsityNumerical StabilityActive SetLazifiable
    FWLowLowLowHighNoYes
    AFWMediumMedium-HighMediumMedium-HighYesYes
    B(P)CGHighMedium-HighHighMediumYesBy design
    SFWLowLowLowHighNoNo

    While the standard Frank-Wolfe algorithm can only move towards extreme points of the compact convex set $\mathcal{C}$, Away-step Frank-Wolfe can move away from them. The following figure from our paper illustrates this behaviour:

    FW vs AFW.

    Both algorithms minimize a quadratic function (whose contour lines are depicted) over a simple polytope (the black square). When the minimizer lies on a face, the standard Frank-Wolfe algorithm zig-zags towards the solution, while its Away-step variant converges more quickly.

    Block-Coordinate Frank-Wolfe (BCFW)

    It is implemented in the FrankWolfe.block_coordinate_frank_wolfe function.

    See Lacoste-Julien, Jaggi, Schmidt, Pletscher (2013) and Beck, Pauwels, Sabach (2015) for more details about different variants of Block-Coordinate Frank-Wolfe.

    Alternating Linear Minimization (ALM)

    It is implemented in the FrankWolfe.alternating_linear_minimization function.

    diff --git a/previews/PR539/contributing/index.html b/previews/PR539/contributing/index.html new file mode 100644 index 000000000..b0a0c55a8 --- /dev/null +++ b/previews/PR539/contributing/index.html @@ -0,0 +1,7 @@ + +Contributing · FrankWolfe.jl

    Contributing to FrankWolfe

    First, thanks for taking the time to contribute. Contributions in any form, such as documentation, bug fix, examples or algorithms, are appreciated and welcome.

    We list below some guidelines to help you contribute to the package.

    Community Standards

    Interactions on this repository must follow the Julia Community Standards including Pull Requests and issues.

    Where can I get an overview?

    Check out the paper presenting the package for a high-level overview of the feature and algorithms and the documentation for more details.

    I just have a question

    If your question is related to Julia, its syntax or tooling, the best places to get help will be tied to the Julia community, see the Julia community page for a number of communication channels (Slack, Zulip, and Discourse being the most active).

    For now, the best way to ask a question is to file an issue or reach out to Mathieu Besançon or Sebastian Pokutta. You can also ask your question on discourse.julialang.org in the optimization topic or on the Julia Slack on #mathematical-optimization, see the Julia community page to gain access.

    How can I file an issue?

    If you found a bug or want to propose a feature, we track our issues within the GitHub repository. Once opened, you can edit the issue or add new comments to continue the conversation.

    If you encounter a bug, send the stack trace (the lines appearing after the error occurred containing some source files) and ideally a Minimal Working Example (MWE), a small program that reproduces the bug.

    How can I contribute

    Contributing to the repository will likely be made in a Pull Request (PR). You will need to:

    1. Fork the repository
    2. Clone it on your machine to perform the changes
    3. Create a branch for your modifications, based on the branch you want to merge on (typically master)
    4. Push to this branch on your fork
    5. The GitHub web interface will then automatically suggest opening a PR onto the original repository.

    See the GitHub guide to creating PRs for more help on workflows using Git and GitHub.

    A PR should do a single thing to reduce the amount of code that must be reviewed. Do not run the formatter on the whole repository except if your PR is specifically about formatting.

    Improve the documentation

    The documentation can be improved by changing the files in docs/src, for example to add a section in the documentation, expand a paragraph or add a plot. The documentation attached to a given type of function can be modified in the source files directly, it appears above the function / type / thingy you try to document with three double quotation marks like this:

    """
    +This explains what the function `f` does, it supports markdown.
    +"""
    +function f(x)
    +    # ...
    +end

    Provide a new example or test

    If you fix a bug, one would typically expect to add a test that validates that the bug is gone. A test would be added in a file in the test/ folder, for which the entry point is runtests.jl.

    The examples/ folder features several examples covering different problem settings and algorithms. The examples are expected to run with the same environment and dependencies as the tests using TestEnv. If the example is lightweight enough, it can be added to the docs/src/examples/ folder which generates pages for the documentation based on Literate.jl.

    Provide a new feature

    Contributions bringing new features are also welcome. If the feature is likely to impact performance, some benchmarks should be run with BenchmarkTools on several of the examples to assert the effect at different problem sizes. If the feature should only be active in some cases, a keyword should be added to the main algorithms to support it.

    Some typical features to implement are:

    1. A new Linear Minimization Oracle (LMO)
    2. A new step size
    3. A new algorithm (less frequent) following the same API.

    Code style

    We try to follow the Julia documentation guidelines. We run JuliaFormatter.jl on the repo in the way set in the .JuliaFormatter.toml file, which enforces a number of conventions.

    This contribution guide was inspired by ColPrac and the one in Manopt.jl.

    diff --git a/previews/PR539/examples/.gitkeep b/previews/PR539/examples/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/previews/PR539/examples/docs_00_fw_visualized/index.html b/previews/PR539/examples/docs_00_fw_visualized/index.html new file mode 100644 index 000000000..8fec580da --- /dev/null +++ b/previews/PR539/examples/docs_00_fw_visualized/index.html @@ -0,0 +1,368 @@ + +Visualization of Frank-Wolfe running on a 2-dimensional polytope · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Visualization of Frank-Wolfe running on a 2-dimensional polytope

    This example provides an intuitive view of the Frank-Wolfe algorithm by running it on a polyhedral set with a quadratic function. The Linear Minimization Oracle (LMO) corresponds to a call to a generic simplex solver from MathOptInterface.jl (MOI).

    Import and setup

    We first import the necessary packages, including Polyhedra to visualize the feasible set.

    using LinearAlgebra
    +using FrankWolfe
    +
    +import MathOptInterface
    +const MOI = MathOptInterface
    +using GLPK
    +
    +using Polyhedra
    +using Plots

    We can then define the objective function, here the squared distance to a point in the place, and its in-place gradient.

    n = 2
    +y = [3.2, 0.5]
    +
    +function f(x)
    +    return 1 / 2 * norm(x - y)^2
    +end
    +function grad!(storage, x)
    +    @. storage = x - y
    +end
    grad! (generic function with 1 method)

    Custom callback

    FrankWolfe.jl lets users define custom callbacks to record information about each iteration. In that case, the callback will copy the current iterate x, the current vertex v, and the current step size gamma to an array thanks to a closure. We then declare the array and the callback over this array. Each iteration will then push to this array.

    function build_callback(trajectory_arr)
    +    return function callback(state, args...)
    +        return push!(trajectory_arr, (copy(state.x), copy(state.v), state.gamma))
    +    end
    +end
    +
    +iterates_information_vector = []
    +callback = build_callback(iterates_information_vector)
    callback (generic function with 1 method)

    Creating the Linear Minimization Oracle

    The LMO is defined as a call to a linear optimization solver, each iteration resets the objective and calls the solver. The linear constraints must be defined only once at the beginning and remain identical along iterations. We use here MathOptInterface directly but the constraints could also be defined with JuMP or Convex.jl.

    o = GLPK.Optimizer()
    +x = MOI.add_variables(o, n)
    +
    +# −x + y ≤ 2
    +c1 = MOI.add_constraint(o, -1.0x[1] + x[2], MOI.LessThan(2.0))
    +
    +# x + 2 y ≤ 4
    +c2 = MOI.add_constraint(o, x[1] + 2.0x[2], MOI.LessThan(4.0))
    +
    +# −2 x − y ≤ 1
    +c3 = MOI.add_constraint(o, -2.0x[1] - x[2], MOI.LessThan(1.0))
    +
    +# x − 2 y ≤ 2
    +c4 = MOI.add_constraint(o, x[1] - 2.0x[2], MOI.LessThan(2.0))
    +
    +# x ≤ 2
    +c5 = MOI.add_constraint(o, x[1] + 0.0x[2], MOI.LessThan(2.0))
    MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.LessThan{Float64}}(5)

    The LMO is then built by wrapping the current MOI optimizer

    lmo_moi = FrankWolfe.MathOptLMO(o)
    FrankWolfe.MathOptLMO{GLPK.Optimizer}(A GLPK model, true)

    Calling Frank-Wolfe

    We can now compute an initial starting point from any direction and call the Frank-Wolfe algorithm. Note that we copy x0 before passing it to the algorithm because it is modified in-place by frank_wolfe.

    x0 = FrankWolfe.compute_extreme_point(lmo_moi, zeros(n))
    +
    +xfinal, vfinal, primal_value, dual_gap, traj_data = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo_moi,
    +    copy(x0),
    +    line_search=FrankWolfe.Adaptive(),
    +    max_iteration=10,
    +    epsilon=1e-8,
    +    callback=callback,
    +    verbose=true,
    +    print_iter=1,
    +)
    (x = [2.0, 0.5000005296253868], v = [2.0, 0.0], primal = 0.7200000000001404, dual_gap = 2.648129737714555e-7, traj_data = Any[])

    We now collect the iterates and vertices across iterations.

    iterates = Vector{Vector{Float64}}()
    +push!(iterates, x0)
    +vertices = Vector{Vector{Float64}}()
    +for s in iterates_information_vector
    +    push!(iterates, s[1])
    +    push!(vertices, s[2])
    +end

    Plotting the algorithm run

    We define another method for f adapted to plot its contours.

    function f(x1, x2)
    +    x = [x1, x2]
    +    return f(x)
    +end
    +
    +xlist = collect(range(-1, 3, step=0.2))
    +ylist = collect(range(-1, 3, step=0.2))
    +
    +X = repeat(reshape(xlist, 1, :), length(ylist), 1)
    +Y = repeat(ylist, 1, length(xlist))
    21×21 Matrix{Float64}:
    + -1.0  -1.0  -1.0  -1.0  -1.0  -1.0  …  -1.0  -1.0  -1.0  -1.0  -1.0  -1.0
    + -0.8  -0.8  -0.8  -0.8  -0.8  -0.8     -0.8  -0.8  -0.8  -0.8  -0.8  -0.8
    + -0.6  -0.6  -0.6  -0.6  -0.6  -0.6     -0.6  -0.6  -0.6  -0.6  -0.6  -0.6
    + -0.4  -0.4  -0.4  -0.4  -0.4  -0.4     -0.4  -0.4  -0.4  -0.4  -0.4  -0.4
    + -0.2  -0.2  -0.2  -0.2  -0.2  -0.2     -0.2  -0.2  -0.2  -0.2  -0.2  -0.2
    +  0.0   0.0   0.0   0.0   0.0   0.0  …   0.0   0.0   0.0   0.0   0.0   0.0
    +  0.2   0.2   0.2   0.2   0.2   0.2      0.2   0.2   0.2   0.2   0.2   0.2
    +  0.4   0.4   0.4   0.4   0.4   0.4      0.4   0.4   0.4   0.4   0.4   0.4
    +  0.6   0.6   0.6   0.6   0.6   0.6      0.6   0.6   0.6   0.6   0.6   0.6
    +  0.8   0.8   0.8   0.8   0.8   0.8      0.8   0.8   0.8   0.8   0.8   0.8
    +  ⋮                             ⋮    ⋱   ⋮                             ⋮
    +  1.4   1.4   1.4   1.4   1.4   1.4      1.4   1.4   1.4   1.4   1.4   1.4
    +  1.6   1.6   1.6   1.6   1.6   1.6      1.6   1.6   1.6   1.6   1.6   1.6
    +  1.8   1.8   1.8   1.8   1.8   1.8      1.8   1.8   1.8   1.8   1.8   1.8
    +  2.0   2.0   2.0   2.0   2.0   2.0  …   2.0   2.0   2.0   2.0   2.0   2.0
    +  2.2   2.2   2.2   2.2   2.2   2.2      2.2   2.2   2.2   2.2   2.2   2.2
    +  2.4   2.4   2.4   2.4   2.4   2.4      2.4   2.4   2.4   2.4   2.4   2.4
    +  2.6   2.6   2.6   2.6   2.6   2.6      2.6   2.6   2.6   2.6   2.6   2.6
    +  2.8   2.8   2.8   2.8   2.8   2.8      2.8   2.8   2.8   2.8   2.8   2.8
    +  3.0   3.0   3.0   3.0   3.0   3.0  …   3.0   3.0   3.0   3.0   3.0   3.0

    The feasible space is represented using Polyhedra.

    h =
    +    HalfSpace([-1, 1], 2) ∩ HalfSpace([1, 2], 4) ∩ HalfSpace([-2, -1], 1) ∩ HalfSpace([1, -2], 2) ∩
    +    HalfSpace([1, 0], 2)
    +
    +p = polyhedron(h)
    +
    +p1 = contour(xlist, ylist, f, fill=true, line_smoothing=0.85)
    +plot(p1, opacity=0.5)
    +plot!(
    +    p,
    +    ratio=:equal,
    +    opacity=0.5,
    +    label="feasible region",
    +    framestyle=:zerolines,
    +    legend=true,
    +    color=:blue,
    +);

    Finally, we add all iterates and vertices to the plot.

    colors = ["gold", "purple", "darkorange2", "firebrick3"]
    +iterates = unique!(iterates)
    +for i in 1:3
    +    scatter!(
    +        [iterates[i][1]],
    +        [iterates[i][2]],
    +        label=string("x_", i - 1),
    +        markersize=6,
    +        color=colors[i],
    +    )
    +end
    +scatter!(
    +    [last(iterates)[1]],
    +    [last(iterates)[2]],
    +    label=string("x_", length(iterates) - 1),
    +    markersize=6,
    +    color=last(colors),
    +)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    plot chosen vertices

    scatter!([vertices[1][1]], [vertices[1][2]], m=:diamond, markersize=6, color=colors[1], label="v_1")
    +scatter!(
    +    [vertices[2][1]],
    +    [vertices[2][2]],
    +    m=:diamond,
    +    markersize=6,
    +    color=colors[2],
    +    label="v_2",
    +    legend=:outerleft,
    +    colorbar=true,
    +)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_01_mathopt_lmo/index.html b/previews/PR539/examples/docs_01_mathopt_lmo/index.html new file mode 100644 index 000000000..3fdd9299a --- /dev/null +++ b/previews/PR539/examples/docs_01_mathopt_lmo/index.html @@ -0,0 +1,320 @@ + +Comparison with MathOptInterface on a Probability Simplex · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Comparison with MathOptInterface on a Probability Simplex

    In this example, we project a random point onto a probability simplex with the Frank-Wolfe algorithm using either the specialized LMO defined in the package or a generic LP formulation using MathOptInterface.jl (MOI) and GLPK as underlying LP solver. It can be found as Example 4.4 in the paper.

    using FrankWolfe
    +
    +using LinearAlgebra
    +using LaTeXStrings
    +
    +using Plots
    +
    +using JuMP
    +const MOI = JuMP.MOI
    +
    +import GLPK
    +
    +n = Int(1e3)
    +k = 10000
    +
    +xpi = rand(n);
    +total = sum(xpi);
    +const xp = xpi ./ total;
    +
    +f(x) = norm(x - xp)^2
    +function grad!(storage, x)
    +    @. storage = 2 * (x - xp)
    +    return nothing
    +end
    +
    +lmo_radius = 2.5
    +lmo = FrankWolfe.FrankWolfe.ProbabilitySimplexOracle(lmo_radius)
    +
    +x00 = FrankWolfe.compute_extreme_point(lmo, zeros(n))
    +gradient = collect(x00)
    +
    +x_lmo, v, primal, dual_gap, trajectory_lmo = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo,
    +    collect(copy(x00)),
    +    max_iteration=k,
    +    line_search=FrankWolfe.Shortstep(2.0),
    +    print_iter=k / 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=false,
    +    trajectory=true,
    +);

    Create a MathOptInterface Optimizer and build the same linear constraints:

    o = GLPK.Optimizer()
    +x = MOI.add_variables(o, n)
    +
    +for xi in x
    +    MOI.add_constraint(o, xi, MOI.GreaterThan(0.0))
    +end
    +
    +MOI.add_constraint(
    +    o,
    +    MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(1.0, x), 0.0),
    +    MOI.EqualTo(lmo_radius),
    +)
    +
    +lmo_moi = FrankWolfe.MathOptLMO(o)
    +
    +x, v, primal, dual_gap, trajectory_moi = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo_moi,
    +    collect(copy(x00)),
    +    max_iteration=k,
    +    line_search=FrankWolfe.Shortstep(2.0),
    +    print_iter=k / 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=false,
    +    trajectory=true,
    +);

    Alternatively, we can use one of the modelling interfaces based on MOI to formulate the LP. The following example builds the same set of constraints using JuMP:

    m = JuMP.Model(GLPK.Optimizer)
    +@variable(m, y[1:n] ≥ 0)
    +
    +@constraint(m, sum(y) == lmo_radius)
    +
    +lmo_jump = FrankWolfe.MathOptLMO(m.moi_backend)
    +
    +x, v, primal, dual_gap, trajectory_jump = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo_jump,
    +    collect(copy(x00)),
    +    max_iteration=k,
    +    line_search=FrankWolfe.Shortstep(2.0),
    +    print_iter=k / 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=false,
    +    trajectory=true,
    +);
    +
    +x_lmo, v, primal, dual_gap, trajectory_lmo_blas = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo,
    +    x00,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Shortstep(2.0),
    +    print_iter=k / 10,
    +    memory_mode=FrankWolfe.OutplaceEmphasis(),
    +    verbose=false,
    +    trajectory=true,
    +);
    +
    +x, v, primal, dual_gap, trajectory_jump_blas = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo_jump,
    +    x00,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Shortstep(2.0),
    +    print_iter=k / 10,
    +    memory_mode=FrankWolfe.OutplaceEmphasis(),
    +    verbose=false,
    +    trajectory=true,
    +);

    We can now plot the results

    iteration_list = [[x[1] + 1 for x in trajectory_lmo], [x[1] + 1 for x in trajectory_moi]]
    +time_list = [[x[5] for x in trajectory_lmo], [x[5] for x in trajectory_moi]]
    +primal_gap_list = [[x[2] for x in trajectory_lmo], [x[2] for x in trajectory_moi]]
    +dual_gap_list = [[x[4] for x in trajectory_lmo], [x[4] for x in trajectory_moi]]
    +
    +label = [L"\textrm{Closed-form LMO}", L"\textrm{MOI LMO}"]
    +
    +plot_results(
    +    [primal_gap_list, primal_gap_list, dual_gap_list, dual_gap_list],
    +    [iteration_list, time_list, iteration_list, time_list],
    +    label,
    +    ["", "", L"\textrm{Iteration}", L"\textrm{Time}"],
    +    [L"\textrm{Primal Gap}", "", L"\textrm{Dual Gap}", ""],
    +    xscalelog=[:log, :identity, :log, :identity],
    +    yscalelog=[:log, :log, :log, :log],
    +    legend_position=[:bottomleft, nothing, nothing, nothing],
    +)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_02_polynomial_regression/index.html b/previews/PR539/examples/docs_02_polynomial_regression/index.html new file mode 100644 index 000000000..2e8b1b16d --- /dev/null +++ b/previews/PR539/examples/docs_02_polynomial_regression/index.html @@ -0,0 +1,505 @@ + +Polynomial Regression · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Polynomial Regression

    The following example features the LMO for polynomial regression on the $\ell_1$ norm ball. Given input/output pairs $\{x_i,y_i\}_{i=1}^N$ and sparse coefficients $c_j$, where

    \[y_i=\sum_{j=1}^m c_j f_j(x_i)\]

    and $f_j: \mathbb{R}^n\to\mathbb{R}$, the task is to recover those $c_j$ that are non-zero alongside their corresponding values. Under certain assumptions, this problem can be convexified into

    \[\min_{c\in\mathcal{C}}||y-Ac||^2\]

    for a convex set $\mathcal{C}$. It can also be found as example 4.1 in the paper. In order to evaluate the polynomial, we generate a total of 1000 data points $\{x_i\}_{i=1}^N$ from the standard multivariate Gaussian, with which we will compute the output variables $\{y_i\}_{i=1}^N$. Before evaluating the polynomial, these points will be contaminated with noise drawn from a standard multivariate Gaussian. We run the away_frank_wolfe and blended_conditional_gradient algorithms, and compare them to Projected Gradient Descent using a smoothness estimate. We will evaluate the output solution on test points drawn in a similar manner as the training points.

    using FrankWolfe
    +
    +using LinearAlgebra
    +import Random
    +
    +using MultivariatePolynomials
    +using DynamicPolynomials
    +
    +using Plots
    +
    +using LaTeXStrings
    +
    +const N = 10
    +
    +DynamicPolynomials.@polyvar X[1:15]
    +
    +const max_degree = 4
    +coefficient_magnitude = 10
    +noise_magnitude = 1
    +
    +const var_monomials = MultivariatePolynomials.monomials(X, 0:max_degree)
    +
    +Random.seed!(42)
    +const all_coeffs = map(var_monomials) do m
    +    d = MultivariatePolynomials.degree(m)
    +    return coefficient_magnitude * rand() .* (rand() .> 0.95 * d / max_degree)
    +end
    +
    +const true_poly = dot(all_coeffs, var_monomials)
    +
    +const training_data = map(1:500) do _
    +    x = 0.1 * randn(N)
    +    y = MultivariatePolynomials.subs(true_poly, Pair(X, x)) + noise_magnitude * randn()
    +    return (x, y.a[1])
    +end
    +
    +const extended_training_data = map(training_data) do (x, y)
    +    x_ext = MultivariatePolynomials.coefficient.(MultivariatePolynomials.subs.(var_monomials, X => x))
    +    return (x_ext, y)
    +end
    +
    +const test_data = map(1:1000) do _
    +    x = 0.4 * randn(N)
    +    y = MultivariatePolynomials.subs(true_poly, Pair(X, x)) + noise_magnitude * randn()
    +    return (x, y.a[1])
    +end
    +
    +const extended_test_data = map(test_data) do (x, y)
    +    x_ext = MultivariatePolynomials.coefficient.(MultivariatePolynomials.subs.(var_monomials, X => x))
    +    return (x_ext, y)
    +end
    +
    +function f(coefficients)
    +    return 0.5 / length(extended_training_data) * sum(extended_training_data) do (x, y)
    +        return (dot(coefficients, x) - y)^2
    +    end
    +end
    +
    +function f_test(coefficients)
    +    return 0.5 / length(extended_test_data) * sum(extended_test_data) do (x, y)
    +        return (dot(coefficients, x) - y)^2
    +    end
    +end
    +
    +function coefficient_errors(coeffs)
    +    return 0.5 * sum(eachindex(all_coeffs)) do idx
    +        return (all_coeffs[idx] - coeffs[idx])^2
    +    end
    +end
    +
    +function grad!(storage, coefficients)
    +    storage .= 0
    +    for (x, y) in extended_training_data
    +        p_i = dot(coefficients, x) - y
    +        @. storage += x * p_i
    +    end
    +    storage ./= length(training_data)
    +    return nothing
    +end
    +
    +function build_callback(trajectory_arr)
    +    return function callback(state, args...)
    +        return push!(
    +            trajectory_arr,
    +            (FrankWolfe.callback_state(state)..., f_test(state.x), coefficient_errors(state.x)),
    +        )
    +    end
    +end
    +
    +gradient = similar(all_coeffs)
    +
    +max_iter = 10000
    +random_initialization_vector = rand(length(all_coeffs))
    +
    +lmo = FrankWolfe.LpNormLMO{1}(0.95 * norm(all_coeffs, 1))
    +
    +# Estimating smoothness parameter
    +num_pairs = 1000
    +L_estimate = -Inf
    +gradient_aux = similar(gradient)
    +
    +
    +function projnorm1(x, τ)
    +    n = length(x)
    +    if norm(x, 1) ≤ τ
    +        return x
    +    end
    +    u = abs.(x)
    +    # simplex projection
    +    bget = false
    +    s_indices = sortperm(u, rev=true)
    +    tsum = zero(τ)
    +
    +    @inbounds for i in 1:n-1
    +        tsum += u[s_indices[i]]
    +        tmax = (tsum - τ) / i
    +        if tmax ≥ u[s_indices[i+1]]
    +            bget = true
    +            break
    +        end
    +    end
    +    if !bget
    +        tmax = (tsum + u[s_indices[n]] - τ) / n
    +    end
    +
    +    @inbounds for i in 1:n
    +        u[i] = max(u[i] - tmax, 0)
    +        u[i] *= sign(x[i])
    +    end
    +    return u
    +end
    +
    +
    +
    +
    +
    +for i in 1:num_pairs
    +    global L_estimate
    +    x = compute_extreme_point(lmo, randn(size(all_coeffs)))
    +    y = compute_extreme_point(lmo, randn(size(all_coeffs)))
    +    grad!(gradient, x)
    +    grad!(gradient_aux, y)
    +    new_L = norm(gradient - gradient_aux) / norm(x - y)
    +    if new_L > L_estimate
    +        L_estimate = new_L
    +    end
    +end

    We can now perform projected gradient descent:

    xgd = FrankWolfe.compute_extreme_point(lmo, random_initialization_vector)
    +training_gd = Float64[]
    +test_gd = Float64[]
    +coeff_error = Float64[]
    +time_start = time_ns()
    +gd_times = Float64[]
    +for iter in 1:max_iter
    +    global xgd
    +    grad!(gradient, xgd)
    +    xgd = projnorm1(xgd - gradient / L_estimate, lmo.right_hand_side)
    +    push!(training_gd, f(xgd))
    +    push!(test_gd, f_test(xgd))
    +    push!(coeff_error, coefficient_errors(xgd))
    +    push!(gd_times, (time_ns() - time_start) * 1e-9)
    +end
    +
    +x00 = FrankWolfe.compute_extreme_point(lmo, random_initialization_vector)
    +x0 = deepcopy(x00)
    +
    +trajectory_lafw = []
    +callback = build_callback(trajectory_lafw)
    +x_lafw, v, primal, dual_gap, _ = FrankWolfe.away_frank_wolfe(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    max_iteration=max_iter,
    +    line_search=FrankWolfe.Adaptive(L_est=L_estimate),
    +    print_iter=max_iter ÷ 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=false,
    +    lazy=true,
    +    gradient=gradient,
    +    callback=callback,
    +)
    +
    +trajectory_bcg = []
    +callback = build_callback(trajectory_bcg)
    +
    +x0 = deepcopy(x00)
    +x_bcg, v, primal, dual_gap, _, _ = FrankWolfe.blended_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    max_iteration=max_iter,
    +    line_search=FrankWolfe.Adaptive(L_est=L_estimate),
    +    print_iter=max_iter ÷ 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=false,
    +    weight_purge_threshold=1e-10,
    +    callback=callback,
    +)
    +
    +x0 = deepcopy(x00)
    +
    +trajectory_lafw_ref = []
    +callback = build_callback(trajectory_lafw_ref)
    +_, _, primal_ref, _, _ = FrankWolfe.away_frank_wolfe(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    max_iteration=2 * max_iter,
    +    line_search=FrankWolfe.Adaptive(L_est=L_estimate),
    +    print_iter=max_iter ÷ 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=false,
    +    lazy=true,
    +    gradient=gradient,
    +    callback=callback,
    +)
    +
    +iteration_list = [
    +    [x[1] + 1 for x in trajectory_lafw],
    +    [x[1] + 1 for x in trajectory_bcg],
    +    collect(eachindex(training_gd)),
    +]
    +time_list = [[x[5] for x in trajectory_lafw], [x[5] for x in trajectory_bcg], gd_times]
    +primal_list = [
    +    [x[2] - primal_ref for x in trajectory_lafw],
    +    [x[2] - primal_ref for x in trajectory_bcg],
    +    [x - primal_ref for x in training_gd],
    +]
    +test_list = [[x[6] for x in trajectory_lafw], [x[6] for x in trajectory_bcg], test_gd]
    +label = [L"\textrm{L-AFW}", L"\textrm{BCG}", L"\textrm{GD}"]
    +coefficient_error_values =
    +    [[x[7] for x in trajectory_lafw], [x[7] for x in trajectory_bcg], coeff_error]
    +
    +
    +plot_results(
    +    [primal_list, primal_list, test_list, test_list],
    +    [iteration_list, time_list, iteration_list, time_list],
    +    label,
    +    [L"\textrm{Iteration}", L"\textrm{Time}", L"\textrm{Iteration}", L"\textrm{Time}"],
    +    [L"\textrm{Primal Gap}", L"\textrm{Primal Gap}", L"\textrm{Test loss}", L"\textrm{Test loss}"],
    +    xscalelog=[:log, :identity, :log, :identity],
    +    legend_position=[:bottomleft, nothing, nothing, nothing],
    +)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_03_matrix_completion/index.html b/previews/PR539/examples/docs_03_matrix_completion/index.html new file mode 100644 index 000000000..7bc880795 --- /dev/null +++ b/previews/PR539/examples/docs_03_matrix_completion/index.html @@ -0,0 +1,512 @@ + +Matrix Completion · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Matrix Completion

    We present another example that is about matrix completion. The idea is, given a partially observed matrix $Y\in\mathbb{R}^{m\times n}$, to find $X\in\mathbb{R}^{m\times n}$ to minimize the sum of squared errors from the observed entries while 'completing' the matrix $Y$, i.e. filling the unobserved entries to match $Y$ as good as possible. A detailed explanation can be found in section 4.2 of the paper. We will try to solve

    \[\min_{||X||_*\le \tau} \sum_{(i,j)\in\mathcal{I}} (X_{i,j}-Y_{i,j})^2,\]

    where $\tau>0$, $||X||_*$ is the nuclear norm, and $\mathcal{I}$ denotes the indices of the observed entries. We will use FrankWolfe.NuclearNormLMO and compare our Frank-Wolfe implementation with a Projected Gradient Descent (PGD) algorithm which, after each gradient descent step, projects the iterates back onto the nuclear norm ball. We use a movielens dataset for comparison.

    using FrankWolfe
    +using ZipFile, DataFrames, CSV
    +
    +using Random
    +using Plots
    +
    +using Profile
    +
    +import Arpack
    +using SparseArrays, LinearAlgebra
    +
    +using LaTeXStrings
    +
    +temp_zipfile = download("http://files.grouplens.org/datasets/movielens/ml-latest-small.zip")
    +
    +zarchive = ZipFile.Reader(temp_zipfile)
    +
    +movies_file = zarchive.files[findfirst(f -> occursin("movies", f.name), zarchive.files)]
    +movies_frame = CSV.read(movies_file, DataFrame)
    +
    +ratings_file = zarchive.files[findfirst(f -> occursin("ratings", f.name), zarchive.files)]
    +ratings_frame = CSV.read(ratings_file, DataFrame)
    +
    +users = unique(ratings_frame[:, :userId])
    +movies = unique(ratings_frame[:, :movieId])
    +
    +@assert users == eachindex(users)
    +movies_revert = zeros(Int, maximum(movies))
    +for (idx, m) in enumerate(movies)
    +    movies_revert[m] = idx
    +end
    +movies_indices = [movies_revert[idx] for idx in ratings_frame[:, :movieId]]
    +
    +const rating_matrix = sparse(
    +    ratings_frame[:, :userId],
    +    movies_indices,
    +    ratings_frame[:, :rating],
    +    length(users),
    +    length(movies),
    +)
    +
    +missing_rate = 0.05
    +
    +Random.seed!(42)
    +
    +const missing_ratings = Tuple{Int,Int}[]
    +const present_ratings = Tuple{Int,Int}[]
    +let
    +    (I, J, V) = SparseArrays.findnz(rating_matrix)
    +    for idx in eachindex(I)
    +        if V[idx] > 0
    +            if rand() <= missing_rate
    +                push!(missing_ratings, (I[idx], J[idx]))
    +            else
    +                push!(present_ratings, (I[idx], J[idx]))
    +            end
    +        end
    +    end
    +end
    +
    +function f(X)
    +    r = 0.0
    +    for (i, j) in present_ratings
    +        r += 0.5 * (X[i, j] - rating_matrix[i, j])^2
    +    end
    +    return r
    +end
    +
    +function grad!(storage, X)
    +    storage .= 0
    +    for (i, j) in present_ratings
    +        storage[i, j] = X[i, j] - rating_matrix[i, j]
    +    end
    +    return nothing
    +end
    +
    +function test_loss(X)
    +    r = 0.0
    +    for (i, j) in missing_ratings
    +        r += 0.5 * (X[i, j] - rating_matrix[i, j])^2
    +    end
    +    return r
    +end
    +
    +function project_nuclear_norm_ball(X; radius=1.0)
    +    U, sing_val, Vt = svd(X)
    +    if (sum(sing_val) <= radius)
    +        return X, -norm_estimation * U[:, 1] * Vt[:, 1]'
    +    end
    +    sing_val = FrankWolfe.projection_simplex_sort(sing_val, s=radius)
    +    return U * Diagonal(sing_val) * Vt', -norm_estimation * U[:, 1] * Vt[:, 1]'
    +end
    +
    +norm_estimation = 10 * Arpack.svds(rating_matrix, nsv=1, ritzvec=false)[1].S[1]
    +
    +const lmo = FrankWolfe.NuclearNormLMO(norm_estimation)
    +const x0 = FrankWolfe.compute_extreme_point(lmo, ones(size(rating_matrix)))
    +const k = 10
    +
    +gradient = spzeros(size(x0)...)
    +gradient_aux = spzeros(size(x0)...)
    +
    +function build_callback(trajectory_arr)
    +    return function callback(state, args...)
    +        return push!(trajectory_arr, (FrankWolfe.callback_state(state)..., test_loss(state.x)))
    +    end
    +end
    build_callback (generic function with 1 method)

    The smoothness constant is estimated:

    num_pairs = 100
    +L_estimate = -Inf
    +for i in 1:num_pairs
    +    global L_estimate
    +    u1 = rand(size(x0, 1))
    +    u1 ./= sum(u1)
    +    u1 .*= norm_estimation
    +    v1 = rand(size(x0, 2))
    +    v1 ./= sum(v1)
    +    x = FrankWolfe.RankOneMatrix(u1, v1)
    +    u2 = rand(size(x0, 1))
    +    u2 ./= sum(u2)
    +    u2 .*= norm_estimation
    +    v2 = rand(size(x0, 2))
    +    v2 ./= sum(v2)
    +    y = FrankWolfe.RankOneMatrix(u2, v2)
    +    grad!(gradient, x)
    +    grad!(gradient_aux, y)
    +    new_L = norm(gradient - gradient_aux) / norm(x - y)
    +    if new_L > L_estimate
    +        L_estimate = new_L
    +    end
    +end

    We can now perform projected gradient descent:

    xgd = Matrix(x0)
    +function_values = Float64[]
    +timing_values = Float64[]
    +function_test_values = Float64[]
    +
    +ls = FrankWolfe.Backtracking()
    +ls_storage = similar(xgd)
    +time_start = time_ns()
    +for _ in 1:k
    +    f_val = f(xgd)
    +    push!(function_values, f_val)
    +    push!(function_test_values, test_loss(xgd))
    +    push!(timing_values, (time_ns() - time_start) / 1e9)
    +    @info f_val
    +    grad!(gradient, xgd)
    +    xgd_new, vertex = project_nuclear_norm_ball(xgd - gradient / L_estimate, radius=norm_estimation)
    +    gamma = FrankWolfe.perform_line_search(
    +        ls,
    +        1,
    +        f,
    +        grad!,
    +        gradient,
    +        xgd,
    +        xgd - xgd_new,
    +        1.0,
    +        ls_storage,
    +        FrankWolfe.InplaceEmphasis(),
    +    )
    +    @. xgd -= gamma * (xgd - xgd_new)
    +end
    +
    +trajectory_arr_fw = Vector{Tuple{Int64,Float64,Float64,Float64,Float64,Float64}}()
    +callback = build_callback(trajectory_arr_fw)
    +xfin, _, _, _, traj_data = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo,
    +    x0;
    +    epsilon=1e-9,
    +    max_iteration=10 * k,
    +    print_iter=k / 10,
    +    verbose=false,
    +    line_search=FrankWolfe.Adaptive(),
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    gradient=gradient,
    +    callback=callback,
    +)
    +
    +trajectory_arr_lazy = Vector{Tuple{Int64,Float64,Float64,Float64,Float64,Float64}}()
    +callback = build_callback(trajectory_arr_lazy)
    +xlazy, _, _, _, _ = FrankWolfe.lazified_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0;
    +    epsilon=1e-9,
    +    max_iteration=10 * k,
    +    print_iter=k / 10,
    +    verbose=false,
    +    line_search=FrankWolfe.Adaptive(),
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    gradient=gradient,
    +    callback=callback,
    +)
    +
    +
    +trajectory_arr_lazy_ref = Vector{Tuple{Int64,Float64,Float64,Float64,Float64,Float64}}()
    +callback = build_callback(trajectory_arr_lazy_ref)
    +xlazy, _, _, _, _ = FrankWolfe.lazified_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0;
    +    epsilon=1e-9,
    +    max_iteration=50 * k,
    +    print_iter=k / 10,
    +    verbose=false,
    +    line_search=FrankWolfe.Adaptive(),
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    gradient=gradient,
    +    callback=callback,
    +)
    +
    +fw_test_values = getindex.(trajectory_arr_fw, 6)
    +lazy_test_values = getindex.(trajectory_arr_lazy, 6)
    +
    +results = Dict(
    +    "svals_gd" => svdvals(xgd),
    +    "svals_fw" => svdvals(xfin),
    +    "svals_lcg" => svdvals(xlazy),
    +    "fw_test_values" => fw_test_values,
    +    "lazy_test_values" => lazy_test_values,
    +    "trajectory_arr_fw" => trajectory_arr_fw,
    +    "trajectory_arr_lazy" => trajectory_arr_lazy,
    +    "function_values_gd" => function_values,
    +    "function_values_test_gd" => function_test_values,
    +    "timing_values_gd" => timing_values,
    +    "trajectory_arr_lazy_ref" => trajectory_arr_lazy_ref,
    +)
    +
    +ref_optimum = results["trajectory_arr_lazy_ref"][end][2]
    +
    +iteration_list = [
    +    [x[1] + 1 for x in results["trajectory_arr_fw"]],
    +    [x[1] + 1 for x in results["trajectory_arr_lazy"]],
    +    collect(1:1:length(results["function_values_gd"])),
    +]
    +time_list = [
    +    [x[5] for x in results["trajectory_arr_fw"]],
    +    [x[5] for x in results["trajectory_arr_lazy"]],
    +    results["timing_values_gd"],
    +]
    +primal_gap_list = [
    +    [x[2] - ref_optimum for x in results["trajectory_arr_fw"]],
    +    [x[2] - ref_optimum for x in results["trajectory_arr_lazy"]],
    +    [x - ref_optimum for x in results["function_values_gd"]],
    +]
    +test_list =
    +    [results["fw_test_values"], results["lazy_test_values"], results["function_values_test_gd"]]
    +
    +label = [L"\textrm{FW}", L"\textrm{L-CG}", L"\textrm{GD}"]
    +
    +plot_results(
    +    [primal_gap_list, primal_gap_list, test_list, test_list],
    +    [iteration_list, time_list, iteration_list, time_list],
    +    label,
    +    [L"\textrm{Iteration}", L"\textrm{Time}", L"\textrm{Iteration}", L"\textrm{Time}"],
    +    [
    +        L"\textrm{Primal Gap}",
    +        L"\textrm{Primal Gap}",
    +        L"\textrm{Test Error}",
    +        L"\textrm{Test Error}",
    +    ],
    +    xscalelog=[:log, :identity, :log, :identity],
    +    legend_position=[:bottomleft, nothing, nothing, nothing],
    +)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_04_rational_opt/index.html b/previews/PR539/examples/docs_04_rational_opt/index.html new file mode 100644 index 000000000..a58316609 --- /dev/null +++ b/previews/PR539/examples/docs_04_rational_opt/index.html @@ -0,0 +1,82 @@ + +Exact Optimization with Rational Arithmetic · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Exact Optimization with Rational Arithmetic

    This example can be found in section 4.3 in the paper. The package allows for exact optimization with rational arithmetic. For this, it suffices to set up the LMO to be rational and choose an appropriate step-size rule as detailed below. For the LMOs included in the package, this simply means initializing the radius with a rational-compatible element type, e.g., 1, rather than a floating-point number, e.g., 1.0. Given that numerators and denominators can become quite large in rational arithmetic, it is strongly advised to base the used rationals on extended-precision integer types such as BigInt, i.e., we use Rational{BigInt}.

    The second requirement ensuring that the computation runs in rational arithmetic is a rational-compatible step-size rule. The most basic step-size rule compatible with rational optimization is the agnostic step-size rule with $\gamma_t = 2/(2 + t)$. With this step-size rule, the gradient does not even need to be rational as long as the atom computed by the LMO is of a rational type. Assuming these requirements are met, all iterates and the computed solution will then be rational.

    using FrankWolfe
    +using LinearAlgebra
    +
    +n = 100
    +k = n
    +
    +x = fill(big(1) // 100, n)
    +
    +f(x) = dot(x, x)
    +function grad!(storage, x)
    +    @. storage = 2 * x
    +end
    grad! (generic function with 1 method)

    pick feasible region radius needs to be integer or rational

    lmo = FrankWolfe.ProbabilitySimplexOracle{Rational{BigInt}}(1)
    FrankWolfe.ProbabilitySimplexOracle{Rational{BigInt}}(1//1)

    compute some initial vertex

    x0 = FrankWolfe.compute_extreme_point(lmo, zeros(n));
    +
    +x, v, primal, dual_gap, trajectory = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Agnostic(),
    +    print_iter=k / 10,
    +    verbose=true,
    +    memory_mode=FrankWolfe.OutplaceEmphasis(),
    +);
    +
    +println("\nOutput type of solution: ", eltype(x))
    
    +Vanilla Frank-Wolfe Algorithm.
    +MEMORY_MODE: FrankWolfe.OutplaceEmphasis() STEPSIZE: Agnostic(2) EPSILON: 1.0e-7 MAXITERATION: 100 TYPE: Rational{BigInt}
    +MOMENTUM: nothing GRADIENTTYPE: Nothing
    +LMO: FrankWolfe.ProbabilitySimplexOracle{Rational{BigInt}}
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   1.000000e+00  -1.000000e+00   2.000000e+00   0.000000e+00            Inf
    +    FW            10   1.407407e-01  -1.407407e-01   2.814815e-01   4.641907e-01   2.154287e+01
    +    FW            20   6.842105e-02  -6.842105e-02   1.368421e-01   4.658324e-01   4.293390e+01
    +    FW            30   4.521073e-02  -4.521073e-02   9.042146e-02   4.674324e-01   6.418040e+01
    +    FW            40   3.376068e-02  -3.376068e-02   6.752137e-02   4.692864e-01   8.523580e+01
    +    FW            50   2.693878e-02  -2.693878e-02   5.387755e-02   4.712210e-01   1.061073e+02
    +    FW            60   2.241055e-02  -2.241055e-02   4.482109e-02   4.731888e-01   1.267993e+02
    +    FW            70   1.918565e-02  -1.918565e-02   3.837129e-02   4.755900e-01   1.471856e+02
    +    FW            80   1.677215e-02  -1.677215e-02   3.354430e-02   4.777740e-01   1.674432e+02
    +    FW            90   1.489804e-02  -1.489804e-02   2.979609e-02   4.806459e-01   1.872480e+02
    +    FW           100   1.340067e-02  -1.340067e-02   2.680135e-02   4.832804e-01   2.069192e+02
    +  Last           101   1.314422e-02  -1.236767e-02   2.551189e-02   4.842091e-01   2.085876e+02
    +-------------------------------------------------------------------------------------------------
    +
    +Output type of solution: BigFloat

    Another possible step-size rule is rationalshortstep which computes the step size by minimizing the smoothness inequality as $\gamma_t=\frac{\langle \nabla f(x_t),x_t-v_t\rangle}{2L||x_t-v_t||^2}$. However, as this step size depends on an upper bound on the Lipschitz constant $L$ as well as the inner product with the gradient $\nabla f(x_t)$, both have to be of a rational type.

    @time x, v, primal, dual_gap, trajectory = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Shortstep(2 // 1),
    +    print_iter=k / 10,
    +    verbose=true,
    +    memory_mode=FrankWolfe.OutplaceEmphasis(),
    +);
    
    +Vanilla Frank-Wolfe Algorithm.
    +MEMORY_MODE: FrankWolfe.OutplaceEmphasis() STEPSIZE: Shortstep EPSILON: 1.0e-7 MAXITERATION: 100 TYPE: Rational{BigInt}
    +MOMENTUM: nothing GRADIENTTYPE: Nothing
    +LMO: FrankWolfe.ProbabilitySimplexOracle{Rational{BigInt}}
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   1.000000e+00  -1.000000e+00   2.000000e+00   0.000000e+00            Inf
    +    FW            10   1.000000e-01  -1.000000e-01   2.000000e-01   3.915628e-01   2.553868e+01
    +    FW            20   5.000000e-02  -5.000000e-02   1.000000e-01   3.928624e-01   5.090841e+01
    +    FW            30   3.333333e-02  -3.333333e-02   6.666667e-02   3.942577e-01   7.609236e+01
    +    FW            40   2.500000e-02  -2.500000e-02   5.000000e-02   3.959560e-01   1.010213e+02
    +    FW            50   2.000000e-02  -2.000000e-02   4.000000e-02   3.979409e-01   1.256468e+02
    +    FW            60   1.666667e-02  -1.666667e-02   3.333333e-02   4.002750e-01   1.498970e+02
    +    FW            70   1.428571e-02  -1.428571e-02   2.857143e-02   4.028441e-01   1.737645e+02
    +    FW            80   1.250000e-02  -1.250000e-02   2.500000e-02   4.056477e-01   1.972155e+02
    +    FW            90   1.111111e-02  -1.111111e-02   2.222222e-02   4.088938e-01   2.201061e+02
    +    FW           100   1.000000e-02   1.000000e-02   1.889162e-78   4.123849e-01   2.424919e+02
    +  Last           100   1.000000e-02   1.000000e-02   2.159042e-78   4.131230e-01   2.420587e+02
    +-------------------------------------------------------------------------------------------------
    +  0.660754 seconds (1.63 M allocations: 92.346 MiB, 1.54% compilation time)

    Note: at the last step, we exactly close the gap, finding the solution 1//n * ones(n)


    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_05_blended_cg/index.html b/previews/PR539/examples/docs_05_blended_cg/index.html new file mode 100644 index 000000000..412df1cab --- /dev/null +++ b/previews/PR539/examples/docs_05_blended_cg/index.html @@ -0,0 +1,269 @@ + +Blended Conditional Gradients · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Blended Conditional Gradients

    The FW and AFW algorithms, and their lazy variants share one feature: they attempt to make primal progress over a reduced set of vertices. The AFW algorithm does this through away steps (which do not increase the cardinality of the active set), and the lazy variants do this through the use of previously exploited vertices. A third strategy that one can follow is to explicitly blend Frank-Wolfe steps with gradient descent steps over the convex hull of the active set (note that this can be done without requiring a projection oracle over $C$, thus making the algorithm projection-free). This results in the Blended Conditional Gradient (BCG) algorithm, which attempts to make as much progress as possible through the convex hull of the current active set $S_t$ until it automatically detects that in order to make further progress it requires additional calls to the LMO.

    See also Blended Conditional Gradients: the unconditioning of conditional gradients, Braun et al, 2019, https://arxiv.org/abs/1805.07311

    using FrankWolfe
    +using LinearAlgebra
    +using Random
    +using SparseArrays
    +
    +n = 1000
    +k = 10000
    +
    +Random.seed!(41)
    +
    +matrix = rand(n, n)
    +hessian = transpose(matrix) * matrix
    +linear = rand(n)
    +f(x) = dot(linear, x) + 0.5 * transpose(x) * hessian * x
    +function grad!(storage, x)
    +    return storage .= linear + hessian * x
    +end
    +L = eigmax(hessian)
    250643.69867666418

    We run over the probability simplex and call the LMO to get an initial feasible point:

    lmo = FrankWolfe.ProbabilitySimplexOracle(1.0);
    +x00 = FrankWolfe.compute_extreme_point(lmo, zeros(n))
    +
    +target_tolerance = 1e-5
    +
    +x0 = deepcopy(x00)
    +x, v, primal, dual_gap, trajectoryBCG_accel_simplex, _ = FrankWolfe.blended_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    epsilon=target_tolerance,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Adaptive(L_est=L),
    +    print_iter=k / 10,
    +    hessian=hessian,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    accelerated=true,
    +    verbose=true,
    +    trajectory=true,
    +    lazy_tolerance=1.0,
    +    weight_purge_threshold=1e-10,
    +)
    +
    +x0 = deepcopy(x00)
    +x, v, primal, dual_gap, trajectoryBCG_simplex, _ = FrankWolfe.blended_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    epsilon=target_tolerance,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Adaptive(L_est=L),
    +    print_iter=k / 10,
    +    hessian=hessian,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    accelerated=false,
    +    verbose=true,
    +    trajectory=true,
    +    lazy_tolerance=1.0,
    +    weight_purge_threshold=1e-10,
    +)
    +
    +x0 = deepcopy(x00)
    +x, v, primal, dual_gap, trajectoryBCG_convex, _ = FrankWolfe.blended_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    epsilon=target_tolerance,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Adaptive(L_est=L),
    +    print_iter=k / 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=true,
    +    trajectory=true,
    +    lazy_tolerance=1.0,
    +    weight_purge_threshold=1e-10,
    +)
    +
    +data = [trajectoryBCG_accel_simplex, trajectoryBCG_simplex, trajectoryBCG_convex]
    +label = ["BCG (accel simplex)", "BCG (simplex)", "BCG (convex)"]
    +plot_trajectories(data, label, xscalelog=true)
    +
    +
    +
    +matrix = rand(n, n)
    +hessian = transpose(matrix) * matrix
    +linear = rand(n)
    +f(x) = dot(linear, x) + 0.5 * transpose(x) * hessian * x + 10
    +function grad!(storage, x)
    +    return storage .= linear + hessian * x
    +end
    +L = eigmax(hessian)
    +
    +lmo = FrankWolfe.KSparseLMO(100, 100.0)
    +x00 = FrankWolfe.compute_extreme_point(lmo, zeros(n))
    +
    +x0 = deepcopy(x00)
    +x, v, primal, dual_gap, trajectoryBCG_accel_simplex, _ = FrankWolfe.blended_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    epsilon=target_tolerance,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Adaptive(L_est=L),
    +    print_iter=k / 10,
    +    hessian=hessian,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    accelerated=true,
    +    verbose=true,
    +    trajectory=true,
    +    lazy_tolerance=1.0,
    +    weight_purge_threshold=1e-10,
    +)
    +
    +x0 = deepcopy(x00)
    +x, v, primal, dual_gap, trajectoryBCG_simplex, _ = FrankWolfe.blended_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    epsilon=target_tolerance,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Adaptive(L_est=L),
    +    print_iter=k / 10,
    +    hessian=hessian,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    accelerated=false,
    +    verbose=true,
    +    trajectory=true,
    +    lazy_tolerance=1.0,
    +    weight_purge_threshold=1e-10,
    +)
    +
    +x0 = deepcopy(x00)
    +x, v, primal, dual_gap, trajectoryBCG_convex, _ = FrankWolfe.blended_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    epsilon=target_tolerance,
    +    max_iteration=k,
    +    line_search=FrankWolfe.Adaptive(L_est=L),
    +    print_iter=k / 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=true,
    +    trajectory=true,
    +    lazy_tolerance=1.0,
    +    weight_purge_threshold=1e-10,
    +)
    +
    +data = [trajectoryBCG_accel_simplex, trajectoryBCG_simplex, trajectoryBCG_convex]
    +label = ["BCG (accel simplex)", "BCG (simplex)", "BCG (convex)"]
    +plot_trajectories(data, label, xscalelog=true)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_06_spectrahedron/index.html b/previews/PR539/examples/docs_06_spectrahedron/index.html new file mode 100644 index 000000000..e757067f2 --- /dev/null +++ b/previews/PR539/examples/docs_06_spectrahedron/index.html @@ -0,0 +1,192 @@ + +Spectrahedron · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Spectrahedron

    This example shows an optimization problem over the spectraplex:

    \[S = \{X \in \mathbb{S}_+^n, Tr(X) = 1\}\]

    with $\mathbb{S}_+^n$ the set of positive semidefinite matrices. Linear optimization with symmetric objective $D$ over the spetraplex consists in computing the leading eigenvector of $D$.

    The package also exposes UnitSpectrahedronLMO which corresponds to the feasible set:

    \[S_u = \{X \in \mathbb{S}_+^n, Tr(X) \leq 1\}\]

    using FrankWolfe
    +using LinearAlgebra
    +using Random
    +using SparseArrays

    The objective function will be the symmetric squared distance to a set of known or observed entries $Y_{ij}$ of the matrix.

    \[f(X) = \sum_{(i,j) \in L} 1/2 (X_{ij} - Y_{ij})^2\]

    Setting up the input data, objective, and gradient

    Dimension, number of iterations and number of known entries:

    n = 1500
    +k = 5000
    +n_entries = 1000
    +
    +Random.seed!(41)
    +
    +const entry_indices = unique!([minmax(rand(1:n, 2)...) for _ in 1:n_entries])
    +const entry_values = randn(length(entry_indices))
    +
    +function f(X)
    +    r = zero(eltype(X))
    +    for (idx, (i, j)) in enumerate(entry_indices)
    +        r += 1 / 2 * (X[i, j] - entry_values[idx])^2
    +        r += 1 / 2 * (X[j, i] - entry_values[idx])^2
    +    end
    +    return r / length(entry_values)
    +end
    +
    +function grad!(storage, X)
    +    storage .= 0
    +    for (idx, (i, j)) in enumerate(entry_indices)
    +        storage[i, j] += (X[i, j] - entry_values[idx])
    +        storage[j, i] += (X[j, i] - entry_values[idx])
    +    end
    +    return storage ./= length(entry_values)
    +end
    grad! (generic function with 1 method)

    Note that the ensure_symmetry = false argument to SpectraplexLMO. It skips an additional step making the used direction symmetric. It is not necessary when the gradient is a LinearAlgebra.Symmetric (or more rarely a LinearAlgebra.Diagonal or LinearAlgebra.UniformScaling).

    const lmo = FrankWolfe.SpectraplexLMO(1.0, n, false)
    +const x0 = FrankWolfe.compute_extreme_point(lmo, spzeros(n, n))
    +
    +target_tolerance = 1e-8;

    Running standard and lazified Frank-Wolfe

    Xfinal, Vfinal, primal, dual_gap, trajectory = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    max_iteration=k,
    +    line_search=FrankWolfe.MonotonicStepSize(),
    +    print_iter=k / 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=true,
    +    trajectory=true,
    +    epsilon=target_tolerance,
    +)
    +
    +Xfinal, Vfinal, primal, dual_gap, trajectory_lazy = FrankWolfe.lazified_conditional_gradient(
    +    f,
    +    grad!,
    +    lmo,
    +    x0,
    +    max_iteration=k,
    +    line_search=FrankWolfe.MonotonicStepSize(),
    +    print_iter=k / 10,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=true,
    +    trajectory=true,
    +    epsilon=target_tolerance,
    +);
    
    +Vanilla Frank-Wolfe Algorithm.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: MonotonicStepSize EPSILON: 1.0e-8 MAXITERATION: 5000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: Nothing
    +LMO: FrankWolfe.SpectraplexLMO{Float64, Matrix{Float64}}
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   1.018597e+00   1.014119e+00   4.477824e-03   0.000000e+00            Inf
    +  Last            25   1.014314e+00   1.014314e+00   9.179324e-09   1.040934e+00   2.401689e+01
    +-------------------------------------------------------------------------------------------------
    +
    +Lazified Conditional Gradient (Frank-Wolfe + Lazification).
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: MonotonicStepSize EPSILON: 1.0e-8 MAXITERATION: 5000 lazy_tolerance: 2.0 TYPE: Float64
    +GRADIENTTYPE: Matrix{Float64} CACHESIZE Inf GREEDYCACHE: false
    +LMO: FrankWolfe.VectorCacheLMO{FrankWolfe.SpectraplexLMO{Float64, Matrix{Float64}}, FrankWolfe.RankOneMatrix{Float64, Vector{Float64}, Vector{Float64}}}
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +----------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec     Cache Size
    +----------------------------------------------------------------------------------------------------------------
    +     I             1   1.018597e+00   1.014119e+00   4.477824e-03   0.000000e+00            Inf              1
    +    LD             2   1.014317e+00   1.014314e+00   3.630596e-06   6.283728e-01   3.182824e+00              2
    +    LD             3   1.014315e+00   1.014314e+00   1.025225e-06   6.675015e-01   4.494372e+00              3
    +    LD             4   1.014315e+00   1.014314e+00   5.032060e-07   7.063678e-01   5.662772e+00              4
    +    LD             6   1.014314e+00   1.014314e+00   1.996252e-07   7.564774e-01   7.931499e+00              5
    +    LD             9   1.014314e+00   1.014314e+00   8.299030e-08   8.570277e-01   1.050141e+01              6
    +    LD            13   1.014314e+00   1.014314e+00   3.827847e-08   9.362972e-01   1.388448e+01              7
    +    LD            19   1.014314e+00   1.014314e+00   1.745621e-08   1.042934e+00   1.821784e+01              8
    +    LD            27   1.014314e+00   1.014314e+00   8.503621e-09   1.177505e+00   2.292983e+01              9
    +  Last            27   1.014314e+00   1.014314e+00   7.896182e-09   1.255229e+00   2.151003e+01             10
    +----------------------------------------------------------------------------------------------------------------

    Plotting the resulting trajectories

    data = [trajectory, trajectory_lazy]
    +label = ["FW", "LCG"]
    +plot_trajectories(data, label, xscalelog=true)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_07_shifted_norm_polytopes/index.html b/previews/PR539/examples/docs_07_shifted_norm_polytopes/index.html new file mode 100644 index 000000000..92f793fca --- /dev/null +++ b/previews/PR539/examples/docs_07_shifted_norm_polytopes/index.html @@ -0,0 +1,210 @@ + +FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls · FrankWolfe.jl
    using FrankWolfe
    +using LinearAlgebra
    +using LaTeXStrings
    +using Plots

    FrankWolfe for scaled, shifted $\ell^1$ and $\ell^{\infty}$ norm balls

    In this example, we run the vanilla FrankWolfe algorithm on a scaled and shifted $\ell^1$ and $\ell^{\infty}$ norm ball, using the ScaledBoundL1NormBall and ScaledBoundLInfNormBall LMOs. We shift both onto the point $(1,0)$ and then scale them by a factor of $2$ along the x-axis. We project the point $(2,1)$ onto the polytopes.

    n = 2
    +
    +k = 1000
    +
    +xp = [2.0, 1.0]
    +
    +f(x) = norm(x - xp)^2
    +
    +function grad!(storage, x)
    +    @. storage = 2 * (x - xp)
    +    return nothing
    +end
    +
    +lower = [-1.0, -1.0]
    +upper = [3.0, 1.0]
    +
    +l1 = FrankWolfe.ScaledBoundL1NormBall(lower, upper)
    +
    +linf = FrankWolfe.ScaledBoundLInfNormBall(lower, upper)
    +
    +x1 = FrankWolfe.compute_extreme_point(l1, zeros(n))
    +gradient = collect(x1)
    +
    +x_l1, v_1, primal_1, dual_gap_1, trajectory_1 = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    l1,
    +    collect(copy(x1)),
    +    max_iteration=k,
    +    line_search=FrankWolfe.Shortstep(2.0),
    +    print_iter=50,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=true,
    +    trajectory=true,
    +);
    +
    +println("\nFinal solution: ", x_l1)
    +
    +x2 = FrankWolfe.compute_extreme_point(linf, zeros(n))
    +gradient = collect(x2)
    +
    +x_linf, v_2, primal_2, dual_gap_2, trajectory_2 = FrankWolfe.frank_wolfe(
    +    f,
    +    grad!,
    +    linf,
    +    collect(copy(x2)),
    +    max_iteration=k,
    +    line_search=FrankWolfe.Shortstep(2.0),
    +    print_iter=50,
    +    memory_mode=FrankWolfe.InplaceEmphasis(),
    +    verbose=true,
    +    trajectory=true,
    +);
    +
    +println("\nFinal solution: ", x_linf)
    
    +Vanilla Frank-Wolfe Algorithm.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: Shortstep EPSILON: 1.0e-7 MAXITERATION: 1000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: Nothing
    +LMO: FrankWolfe.ScaledBoundL1NormBall{Float64, 1, Vector{Float64}, Vector{Float64}}
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   2.000000e+00  -6.000000e+00   8.000000e+00   0.000000e+00            Inf
    +    FW            50   2.198243e-01   1.859119e-01   3.391239e-02   9.587770e-02   5.214977e+02
    +    FW           100   2.104540e-01   1.927834e-01   1.767061e-02   9.615745e-02   1.039961e+03
    +    FW           150   2.071345e-01   1.951277e-01   1.200679e-02   9.642886e-02   1.555551e+03
    +    FW           200   2.054240e-01   1.963167e-01   9.107240e-03   9.669237e-02   2.068415e+03
    +    FW           250   2.043783e-01   1.970372e-01   7.341168e-03   9.695954e-02   2.578395e+03
    +    FW           300   2.036722e-01   1.975209e-01   6.151268e-03   9.722296e-02   3.085691e+03
    +    FW           350   2.031630e-01   1.978684e-01   5.294582e-03   9.748559e-02   3.590274e+03
    +    FW           400   2.027782e-01   1.981301e-01   4.648079e-03   9.774525e-02   4.092270e+03
    +    FW           450   2.024772e-01   1.983344e-01   4.142727e-03   9.800676e-02   4.591520e+03
    +    FW           500   2.022352e-01   1.984984e-01   3.736776e-03   9.826837e-02   5.088107e+03
    +    FW           550   2.020364e-01   1.986329e-01   3.403479e-03   9.853783e-02   5.581613e+03
    +    FW           600   2.018701e-01   1.987452e-01   3.124906e-03   9.880038e-02   6.072851e+03
    +    FW           650   2.017290e-01   1.988404e-01   2.888583e-03   9.906104e-02   6.561611e+03
    +    FW           700   2.016078e-01   1.989222e-01   2.685564e-03   9.932316e-02   7.047702e+03
    +    FW           750   2.015024e-01   1.989932e-01   2.509264e-03   9.958316e-02   7.531394e+03
    +    FW           800   2.014101e-01   1.990554e-01   2.354727e-03   9.985966e-02   8.011243e+03
    +    FW           850   2.013284e-01   1.991103e-01   2.218154e-03   1.001309e-01   8.488891e+03
    +    FW           900   2.012558e-01   1.991592e-01   2.096580e-03   1.003930e-01   8.964769e+03
    +    FW           950   2.011906e-01   1.992030e-01   1.987662e-03   1.006513e-01   9.438528e+03
    +    FW          1000   2.011319e-01   1.992424e-01   1.889519e-03   1.009161e-01   9.909219e+03
    +  Last          1001   2.011297e-01   1.992439e-01   1.885794e-03   1.010662e-01   9.904402e+03
    +-------------------------------------------------------------------------------------------------
    +
    +Final solution: [1.799813188674937, 0.5986834801090863]
    +
    +Vanilla Frank-Wolfe Algorithm.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: Shortstep EPSILON: 1.0e-7 MAXITERATION: 1000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: Nothing
    +LMO: FrankWolfe.ScaledBoundLInfNormBall{Float64, 1, Vector{Float64}, Vector{Float64}}
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   1.300000e+01  -1.900000e+01   3.200000e+01   0.000000e+00            Inf
    +    FW            50   1.084340e-02  -7.590380e-02   8.674720e-02   5.209562e-02   9.597735e+02
    +    FW           100   5.509857e-03  -3.856900e-02   4.407886e-02   5.237126e-02   1.909444e+03
    +    FW           150   3.695414e-03  -2.586790e-02   2.956331e-02   5.264552e-02   2.849245e+03
    +    FW           200   2.780453e-03  -1.946317e-02   2.224362e-02   5.291059e-02   3.779961e+03
    +    FW           250   2.228830e-03  -1.560181e-02   1.783064e-02   5.317485e-02   4.701471e+03
    +    FW           300   1.859926e-03  -1.301948e-02   1.487941e-02   5.343960e-02   5.613815e+03
    +    FW           350   1.595838e-03  -1.117087e-02   1.276670e-02   5.370735e-02   6.516799e+03
    +    FW           400   1.397443e-03  -9.782098e-03   1.117954e-02   5.396874e-02   7.411698e+03
    +    FW           450   1.242935e-03  -8.700548e-03   9.943483e-03   5.423761e-02   8.296825e+03
    +    FW           500   1.119201e-03  -7.834409e-03   8.953610e-03   5.450018e-02   9.174282e+03
    +    FW           550   1.017878e-03  -7.125146e-03   8.143024e-03   5.478830e-02   1.003864e+04
    +    FW           600   9.333816e-04  -6.533671e-03   7.467053e-03   5.505167e-02   1.089885e+04
    +    FW           650   8.618413e-04  -6.032889e-03   6.894730e-03   5.531882e-02   1.175007e+04
    +    FW           700   8.004890e-04  -5.603423e-03   6.403912e-03   5.558231e-02   1.259394e+04
    +    FW           750   7.472928e-04  -5.231050e-03   5.978342e-03   5.584265e-02   1.343059e+04
    +    FW           800   7.007275e-04  -4.905093e-03   5.605820e-03   5.610590e-02   1.425875e+04
    +    FW           850   6.596259e-04  -4.617381e-03   5.277007e-03   5.636842e-02   1.507936e+04
    +    FW           900   6.230796e-04  -4.361557e-03   4.984637e-03   5.662660e-02   1.589359e+04
    +    FW           950   5.903710e-04  -4.132597e-03   4.722968e-03   5.689164e-02   1.669841e+04
    +    FW          1000   5.609256e-04  -3.926479e-03   4.487405e-03   5.715297e-02   1.749690e+04
    +  Last          1001   5.598088e-04  -3.918661e-03   4.478470e-03   5.729962e-02   1.746958e+04
    +-------------------------------------------------------------------------------------------------
    +
    +Final solution: [2.0005598087769556, 0.9763463450796975]

    We plot the polytopes alongside the solutions from above:

    xcoord1 = [1, 3, 1, -1, 1]
    +ycoord1 = [-1, 0, 1, 0, -1]
    +
    +xcoord2 = [3, 3, -1, -1, 3]
    +ycoord2 = [-1, 1, 1, -1, -1]
    +
    +plot(
    +    xcoord1,
    +    ycoord1,
    +    title="Visualization of scaled shifted norm balls",
    +    lw=2,
    +    label=L"\ell^1 \textrm{ norm}",
    +)
    +plot!(xcoord2, ycoord2, lw=2, label=L"\ell^{\infty} \textrm{ norm}")
    +plot!(
    +    [x_l1[1]],
    +    [x_l1[2]],
    +    seriestype=:scatter,
    +    lw=5,
    +    color="blue",
    +    label=L"\ell^1 \textrm{ solution}",
    +)
    +plot!(
    +    [x_linf[1]],
    +    [x_linf[2]],
    +    seriestype=:scatter,
    +    lw=5,
    +    color="orange",
    +    label=L"\ell^{\infty} \textrm{ solution}",
    +    legend=:bottomleft,
    +)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_08_callback_and_tracking/index.html b/previews/PR539/examples/docs_08_callback_and_tracking/index.html new file mode 100644 index 000000000..415a23388 --- /dev/null +++ b/previews/PR539/examples/docs_08_callback_and_tracking/index.html @@ -0,0 +1,82 @@ + +Tracking, counters and custom callbacks for Frank Wolfe · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Tracking, counters and custom callbacks for Frank Wolfe

    In this example we will run the standard Frank-Wolfe algorithm while tracking the number of calls to the different oracles, namely function, gradient evaluations, and LMO calls. In order to track each of these metrics, a "Tracking" version of the Gradient, LMO and Function methods have to be supplied to the frank_wolfe algorithm, which are wrapping a standard one.

    using FrankWolfe
    +using Test
    +using LinearAlgebra
    +using FrankWolfe: ActiveSet

    The trackers for primal objective, gradient and LMO.

    In order to count the number of function calls, a TrackingObjective is built from a standard objective function f, which will act in the same way as the original function does, but with an additional .counter field which tracks the number of calls.

    f(x) = norm(x)^2
    +tf = FrankWolfe.TrackingObjective(f)
    +@show tf.counter
    +tf(rand(3))
    +@show tf.counter
    +# Resetting the counter
    +tf.counter = 0;
    tf.counter = 0
    +tf.counter = 1

    Similarly, the tgrad! function tracks the number of gradient calls:

    function grad!(storage, x)
    +    return storage .= 2x
    +end
    +tgrad! = FrankWolfe.TrackingGradient(grad!)
    +@show tgrad!.counter;
    tgrad!.counter = 0

    The tracking LMO operates in a similar fashion and tracks the number of compute_extreme_point calls.

    lmo_prob = FrankWolfe.ProbabilitySimplexOracle(1)
    +tlmo_prob = FrankWolfe.TrackingLMO(lmo_prob)
    +@show tlmo_prob.counter;
    tlmo_prob.counter = 0

    The tracking LMO can be applied for all types of LMOs and even in a nested way, which can be useful to track the number of calls to a lazified oracle. We can now pass the tracking versions tf, tgrad and tlmo_prob to frank_wolfe and display their call counts after the optimization process.

    x0 = FrankWolfe.compute_extreme_point(tlmo_prob, ones(5))
    +fw_results = FrankWolfe.frank_wolfe(
    +    tf,
    +    tgrad!,
    +    tlmo_prob,
    +    x0,
    +    max_iteration=1000,
    +    line_search=FrankWolfe.Agnostic(),
    +    callback=nothing,
    +)
    +
    +@show tf.counter
    +@show tgrad!.counter
    +@show tlmo_prob.counter;
    tf.counter = 1
    +tgrad!.counter = 1002
    +tlmo_prob.counter = 1003

    Adding a custom callback

    A callback is a user-defined function called at every iteration of the algorithm with the current state passed as a named tuple.

    We can implement our own callback, for example with:

    • Extended trajectory logging, similar to the trajectory = true option
    • Stop criterion after a certain number of calls to the primal objective function

    To reuse the same tracking functions, Let us first reset their counters:

    tf.counter = 0
    +tgrad!.counter = 0
    +tlmo_prob.counter = 0;

    The storage variable stores in the trajectory array the number of calls to each oracle at each iteration.

    storage = []
    Any[]

    Now define our own trajectory logging function that extends the five default logged elements (iterations, primal, dual, dual_gap, time) with ".counter" field arguments present in the tracking functions.

    function push_tracking_state(state, storage)
    +    base_tuple = FrankWolfe.callback_state(state)
    +    if state.lmo isa FrankWolfe.CachedLinearMinimizationOracle
    +        complete_tuple = tuple(
    +            base_tuple...,
    +            state.gamma,
    +            state.f.counter,
    +            state.grad!.counter,
    +            state.lmo.inner.counter,
    +        )
    +    else
    +        complete_tuple = tuple(
    +            base_tuple...,
    +            state.gamma,
    +            state.f.counter,
    +            state.grad!.counter,
    +            state.lmo.counter,
    +        )
    +    end
    +    return push!(storage, complete_tuple)
    +end
    push_tracking_state (generic function with 1 method)

    In case we want to stop the frank_wolfe algorithm prematurely after a certain condition is met, we can return a boolean stop criterion false. Here, we will implement a callback that terminates the algorithm if the primal objective function is evaluated more than 500 times.

    function make_callback(storage)
    +    return function callback(state, args...)
    +        push_tracking_state(state, storage)
    +        return state.f.counter < 500
    +    end
    +end
    +
    +callback = make_callback(storage)
    callback (generic function with 1 method)

    We can show the difference between this standard run and the lazified conditional gradient algorithm which does not call the LMO at each iteration.

    FrankWolfe.lazified_conditional_gradient(
    +    tf,
    +    tgrad!,
    +    tlmo_prob,
    +    x0,
    +    max_iteration=1000,
    +    traj_data=storage,
    +    line_search=FrankWolfe.Agnostic(),
    +    callback=callback,
    +)
    +
    +total_iterations = storage[end][1]
    +@show total_iterations
    +@show tf.counter
    +@show tgrad!.counter
    +@show tlmo_prob.counter;
    ┌ Warning: Lazification is not known to converge with open-loop step size strategies.
    +└ @ FrankWolfe ~/work/FrankWolfe.jl/FrankWolfe.jl/src/fw_algorithms.jl:315
    +total_iterations = 500
    +tf.counter = 501
    +tgrad!.counter = 501
    +tlmo_prob.counter = 13

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_09_extra_vertex_storage/index.html b/previews/PR539/examples/docs_09_extra_vertex_storage/index.html new file mode 100644 index 000000000..43321c278 --- /dev/null +++ b/previews/PR539/examples/docs_09_extra_vertex_storage/index.html @@ -0,0 +1,69 @@ + +Extra-lazification · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Extra-lazification

    Sometimes the Frank-Wolfe algorithm will be run multiple times with slightly different settings under which vertices collected in a previous run are still valid.

    The extra-lazification feature can be used for this purpose. It consists of a storage that can collect dropped vertices during a run, and the ability to use these vertices in another run, when they are not part of the current active set. The vertices that are part of the active set do not need to be duplicated in the extra-lazification storage. The extra-vertices can be used instead of calling the LMO when it is a relatively expensive operation.

    using FrankWolfe
    +using Test
    +using LinearAlgebra

    We will use a parameterized objective function $1/2 \|x - c\|^2$ over the unit simplex.

    const n = 100
    +const center0 = 5.0 .+ 3 * rand(n)
    +f(x) = 0.5 * norm(x .- center0)^2
    +function grad!(storage, x)
    +    return storage .= x .- center0
    +end
    grad! (generic function with 1 method)

    The TrackingLMO will let us count how many real calls to the LMO are performed by a single run of the algorithm.

    lmo = FrankWolfe.UnitSimplexOracle(4.3)
    +tlmo = FrankWolfe.TrackingLMO(lmo)
    +x0 = FrankWolfe.compute_extreme_point(lmo, randn(n));

    Adding a vertex storage

    FrankWolfe offers a simple FrankWolfe.DeletedVertexStorage storage type which has as parameter return_kth, the number of good directions to find before returning the best. return_kth larger than the number of vertices means that the best-aligned vertex will be found. return_kth = 1 means the first acceptable vertex (with the specified threhsold) is returned.

    See FrankWolfe.DeletedVertexStorage

    vertex_storage = FrankWolfe.DeletedVertexStorage(typeof(x0)[], 5)
    +tlmo.counter = 0
    +
    +results = FrankWolfe.blended_pairwise_conditional_gradient(
    +    f,
    +    grad!,
    +    tlmo,
    +    x0,
    +    max_iteration=4000,
    +    verbose=true,
    +    lazy=true,
    +    epsilon=1e-5,
    +    add_dropped_vertices=true,
    +    extra_vertex_storage=vertex_storage,
    +)
    (x = [0.40888360533486434, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.24668091286378452, 0.0, 0.0, 0.0, 0.3856705242607134, 0.0, 0.0, 0.0], v = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], primal = 2114.012843766959, dual_gap = 5.738928329890314e-6, traj_data = Any[], active_set = Tuple{Float64, FrankWolfe.ScaledHotVector{Float64}}[(0.003474953505605373, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.11153306199151813, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.10971865056036759, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.10675045717875149, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.10077225252962349, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.09508921054299171, [4.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.08969081959551475, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.3, 0.0, 0.0, 0.0]), (0.08567862184803596, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.07574179602096497, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.060901136381411786, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.057367654154368494, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 4.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.054959370032634396, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), (0.04832201565821181, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])])

    The counter indicates the number of initial calls to the LMO. We will now construct different objective functions based on new centers, call the BPCG algorithm while accumulating vertices in the storage, in addition to warm-starting with the active set of the previous iteration. This allows for a "double-warmstarted" algorithm, reducing the number of LMO calls from one problem to the next.

    active_set = results[end]
    +tlmo.counter
    +
    +for iter in 1:10
    +    center = 5.0 .+ 3 * rand(n)
    +    f_i(x) = 0.5 * norm(x .- center)^2
    +    function grad_i!(storage, x)
    +        return storage .= x .- center
    +    end
    +    tlmo.counter = 0
    +    FrankWolfe.blended_pairwise_conditional_gradient(
    +        f_i,
    +        grad_i!,
    +        tlmo,
    +        active_set,
    +        max_iteration=4000,
    +        lazy=true,
    +        epsilon=1e-5,
    +        add_dropped_vertices=true,
    +        use_extra_vertex_storage=true,
    +        extra_vertex_storage=vertex_storage,
    +        verbose=false,
    +    )
    +    @info "Number of LMO calls in iter $iter: $(tlmo.counter)"
    +    @info "Vertex storage size: $(length(vertex_storage.storage))"
    +end
    [ Info: Number of LMO calls in iter 1: 25
    +[ Info: Vertex storage size: 8
    +[ Info: Number of LMO calls in iter 2: 28
    +[ Info: Vertex storage size: 22
    +[ Info: Number of LMO calls in iter 3: 25
    +[ Info: Vertex storage size: 38
    +[ Info: Number of LMO calls in iter 4: 18
    +[ Info: Vertex storage size: 52
    +[ Info: Number of LMO calls in iter 5: 17
    +[ Info: Vertex storage size: 56
    +[ Info: Number of LMO calls in iter 6: 21
    +[ Info: Vertex storage size: 62
    +[ Info: Number of LMO calls in iter 7: 14
    +[ Info: Vertex storage size: 69
    +[ Info: Number of LMO calls in iter 8: 22
    +[ Info: Vertex storage size: 71
    +[ Info: Number of LMO calls in iter 9: 17
    +[ Info: Vertex storage size: 77
    +[ Info: Number of LMO calls in iter 10: 16
    +[ Info: Vertex storage size: 82

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_10_alternating_methods/index.html b/previews/PR539/examples/docs_10_alternating_methods/index.html new file mode 100644 index 000000000..f0a9fbd66 --- /dev/null +++ b/previews/PR539/examples/docs_10_alternating_methods/index.html @@ -0,0 +1,245 @@ + +Alternating methods · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Alternating methods

    In this example we will compare FrankWolfe.alternating_linear_minimization and FrankWolfe.alternating_projections for a very simple feasibility problem.

    We consider the probability simplex

    \[P = \{ x \in \mathbb{R}^n \colon \sum_{i=1}^n x_i = 1, x_i \geq 0 ~~ i=1,\dots,n\} ~.\]

    and a scaled, shifted $\ell^{\infty}$ norm ball

    \[Q = [-1,0]^n ~.\]

    The goal is to find a point that lies both in $P$ and $Q$. We do this by reformulating the problem first. Instead of a finding a point in the intersection $P \cap Q$, we search for a pair of points, $(x_P, x_Q)$ in the cartesian product $P \times Q$, which attains minimal distance between $P$ and $Q$,

    \[\|x_P - x_Q\|_2 = \min_{(x,y) \in P \times Q} \|x - y \|_2 ~.\]

    using FrankWolfe
    +include("../examples/plot_utils.jl")
    plot_sparsity (generic function with 1 method)

    Setting up objective, gradient and linear minimization oracles

    Alternating Linear Minimization (ALM) allows for an additional objective such that one can optimize over an intersection of sets instead of finding only feasible points. Since this example only considers the feasibility, we set the objective function as well as the gradient to zero.

    n = 20
    +
    +f(x) = 0
    +
    +function grad!(storage, x)
    +    @. storage = zero(x)
    +end
    +
    +
    +lmo1 = FrankWolfe.ProbabilitySimplexOracle(1.0)
    +lmo2 = FrankWolfe.ScaledBoundLInfNormBall(-ones(n), zeros(n))
    +lmos = (lmo1, lmo2)
    +
    +x0 = rand(n)
    +
    +target_tolerance = 1e-6
    +
    +trajectories = [];

    Running Alternating Linear Minimization

    The method FrankWolfe.alternating_linear_minimization is not a FrankWolfe method itself. It is a wrapper translating a problem over the intersection of multiple sets to a problem over the product space. ALM can be called with any FW method. The default choice though is FrankWolfe.block_coordinate_frank_wolfe as it allows to update the blocks separately. There are three different update orders implemented, FullUpdate, CyclicUpdate and Stochasticupdate. Accordingly both blocks are updated either simulatenously, sequentially or in random order.

    for order in [FrankWolfe.FullUpdate(), FrankWolfe.CyclicUpdate(), FrankWolfe.StochasticUpdate()]
    +
    +    _, _, _, _, _, alm_trajectory = FrankWolfe.alternating_linear_minimization(
    +        FrankWolfe.block_coordinate_frank_wolfe,
    +        f,
    +        grad!,
    +        lmos,
    +        x0,
    +        update_order=order,
    +        verbose=true,
    +        trajectory=true,
    +        epsilon=target_tolerance,
    +    )
    +    push!(trajectories, alm_trajectory)
    +end
    
    +Alternating Linear Minimization (ALM).
    +FW METHOD: block_coordinate_frank_wolfe
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: FrankWolfe.Adaptive{Float64, Int64} EPSILON: 1.0e-6 MAXITERATION: 10000
    +TYPE: Float64 GRADIENTTYPE: Float64
    +LAMBDA: 1.0
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +----------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec          Dist2
    +----------------------------------------------------------------------------------------------------------------
    +     I             1   1.889232e+00  -2.011077e+01   2.200000e+01   0.000000e+00            Inf   1.889232e+00
    +    FW          1000   2.500023e-02   2.494268e-02   5.755263e-05   9.259018e-01   1.080028e+03   2.500023e-02
    +    FW          2000   2.500000e-02   2.499779e-02   2.211653e-06   9.407413e-01   2.125983e+03   2.500000e-02
    +  Last          2236   2.500000e-02   2.499900e-02   1.003006e-06   1.103826e+00   2.025682e+03   2.500000e-02
    +----------------------------------------------------------------------------------------------------------------
    +
    +Alternating Linear Minimization (ALM).
    +FW METHOD: block_coordinate_frank_wolfe
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: FrankWolfe.Adaptive{Float64, Int64} EPSILON: 1.0e-6 MAXITERATION: 10000
    +TYPE: Float64 GRADIENTTYPE: Float64
    +LAMBDA: 1.0
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +----------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec          Dist2
    +----------------------------------------------------------------------------------------------------------------
    +     I             1   1.889232e+00  -2.011077e+01   2.200000e+01   0.000000e+00            Inf   1.889232e+00
    +    FW          1000   2.500023e-02   2.494416e-02   5.606946e-05   2.348733e-01   4.257615e+03   2.500023e-02
    +    FW          2000   2.500000e-02   2.499785e-02   2.154004e-06   2.565709e-01   7.795117e+03   2.500000e-02
    +  Last          2237   2.500000e-02   2.499900e-02   9.981445e-07   2.620337e-01   8.537069e+03   2.500000e-02
    +----------------------------------------------------------------------------------------------------------------
    +
    +Alternating Linear Minimization (ALM).
    +FW METHOD: block_coordinate_frank_wolfe
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: FrankWolfe.Adaptive{Float64, Int64} EPSILON: 1.0e-6 MAXITERATION: 10000
    +TYPE: Float64 GRADIENTTYPE: Float64
    +LAMBDA: 1.0
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +----------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec          Dist2
    +----------------------------------------------------------------------------------------------------------------
    +     I             1   2.866179e-01  -2.171338e+01   2.200000e+01   0.000000e+00            Inf   2.866179e-01
    +    FW          1000   2.500018e-02   2.495033e-02   4.985431e-05   8.860840e-02   1.128561e+04   2.500018e-02
    +    FW          2000   2.500000e-02   2.499809e-02   1.906507e-06   1.108980e-01   1.803460e+04   2.500000e-02
    +  Last          2194   2.500000e-02   2.499900e-02   9.989094e-07   1.154374e-01   1.900597e+04   2.500000e-02
    +----------------------------------------------------------------------------------------------------------------

    As an alternative to Block-Coordiante Frank-Wolfe (BCFW), one can also run alternating linear minimization with standard Frank-Wolfe algorithm. These methods perform then the full (simulatenous) update at each iteration. In this example we also use FrankWolfe.away_frank_wolfe.

    _, _, _, _, _, afw_trajectory = FrankWolfe.alternating_linear_minimization(
    +    FrankWolfe.away_frank_wolfe,
    +    f,
    +    grad!,
    +    lmos,
    +    x0,
    +    verbose=true,
    +    trajectory=true,
    +    epsilon=target_tolerance,
    +)
    +push!(trajectories, afw_trajectory);
    
    +Alternating Linear Minimization (ALM).
    +FW METHOD: away_frank_wolfe
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: FrankWolfe.Adaptive{Float64, Int64} EPSILON: 1.0e-6 MAXITERATION: 10000
    +TYPE: Float64 GRADIENTTYPE: Float64
    +LAMBDA: 1.0
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec          Dist2     #ActiveSet
    +-------------------------------------------------------------------------------------------------------------------------------
    +     I             1   1.150000e+01           -Inf            Inf   0.000000e+00            Inf   1.005291e+00              2
    +  Last           161   2.500000e-02   2.499904e-02   9.621137e-07   4.041410e-01   3.983758e+02   2.500000e-02             78
    +-------------------------------------------------------------------------------------------------------------------------------
    +    PP           161   2.500000e-02   2.499904e-02   9.621137e-07   4.861002e-01   3.312075e+02   2.500000e-02             78
    +-------------------------------------------------------------------------------------------------------------------------------

    Running Alternating Projections

    Unlike ALM, Alternating Projections (AP) is only suitable for feasibility problems. One omits the objective and gradient as parameters.

    _, _, _, _, ap_trajectory = FrankWolfe.alternating_projections(
    +    lmos,
    +    x0,
    +    trajectory=true,
    +    verbose=true,
    +    print_iter=100,
    +    epsilon=target_tolerance,
    +)
    +push!(trajectories, ap_trajectory);
    
    +Alternating Projections.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() EPSILON: 1.0e-6 MAXITERATION: 10000 TYPE: Float64
    +GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}}
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +----------------------------------------------------------------------------------
    +  Type     Iteration       Dual Gap          dist2           Time         It/sec
    +----------------------------------------------------------------------------------
    +     I             1   6.021733e-01   1.505433e-01   0.000000e+00            Inf
    +    FW           100   9.968329e-05   2.500020e-02   1.408445e+00   7.100030e+01
    +    FW           200   2.316528e-05   2.500001e-02   1.412918e+00   1.415510e+02
    +    FW           300   1.122389e-05   2.500000e-02   1.416701e+00   2.117596e+02
    +    FW           400   6.105757e-06   2.500000e-02   1.419946e+00   2.817008e+02
    +    FW           500   3.822934e-06   2.500000e-02   1.423155e+00   3.513320e+02
    +    FW           600   2.624313e-06   2.500000e-02   1.426206e+00   4.206966e+02
    +    FW           700   1.881535e-06   2.500000e-02   1.429288e+00   4.897542e+02
    +    FW           800   1.505897e-06   2.500000e-02   1.432177e+00   5.585904e+02
    +    FW           900   1.216129e-06   2.500000e-02   1.435062e+00   6.271506e+02
    +  Last           992   9.990101e-07   2.500000e-02   1.807030e+00   5.489672e+02
    +----------------------------------------------------------------------------------

    Plotting the resulting trajectories

    labels = ["BCFW - Full", "BCFW - Cyclic", "BCFW - Stochastic", "AFW", "AP"]
    +
    +plot_trajectories(trajectories, labels, xscalelog=true)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_11_block_coordinate_fw/index.html b/previews/PR539/examples/docs_11_block_coordinate_fw/index.html new file mode 100644 index 000000000..19aa703c1 --- /dev/null +++ b/previews/PR539/examples/docs_11_block_coordinate_fw/index.html @@ -0,0 +1,421 @@ + +Block-Coordinate Frank-Wolfe and Block-Vectors · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Block-Coordinate Frank-Wolfe and Block-Vectors

    In this example, we demonstrate the usage of the FrankWolfe.block_coordinate_frank_wolfe and FrankWolfe.BlockVector. We consider the problem of minimizing the squared Euclidean distance between two sets. We compare different update orders and different update steps.

    Import and setup

    We first import the necessary packages and include the code for plotting the results.

    using FrankWolfe
    +using LinearAlgebra
    +
    +include("plot_utils.jl")
    plot_sparsity (generic function with 1 method)

    Next, we define the objective function and its gradient. The iterates x are instances of the FrankWolfe.BlockVector type. The different blocks of the vector can be accessed via the blocks field.

    f(x) = dot(x.blocks[1] - x.blocks[2], x.blocks[1] - x.blocks[2])
    +
    +function grad!(storage, x)
    +    @. storage.blocks = [x.blocks[1] - x.blocks[2], x.blocks[2] - x.blocks[1]]
    +end
    grad! (generic function with 1 method)

    In our example we consider the probability simplex and an L-infinity norm ball as the feasible sets.

    n = 100
    +lmo1 = FrankWolfe.ScaledBoundLInfNormBall(-ones(n), zeros(n))
    +lmo2 = FrankWolfe.ProbabilitySimplexOracle(1.0)
    +prod_lmo = FrankWolfe.ProductLMO((lmo1, lmo2))
    FrankWolfe.ProductLMO{2, Tuple{FrankWolfe.ScaledBoundLInfNormBall{Float64, 1, Vector{Float64}, Vector{Float64}}, FrankWolfe.ProbabilitySimplexOracle{Float64}}}((FrankWolfe.ScaledBoundLInfNormBall{Float64, 1, Vector{Float64}, Vector{Float64}}([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0  …  -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), FrankWolfe.ProbabilitySimplexOracle{Float64}(1.0)))

    We initialize the starting point x0 as a FrankWolfe.BlockVector with two blocks. The two other arguments are the block sizes and the overall number of entries.

    x0 = FrankWolfe.BlockVector([-ones(n), [i == 1 ? 1 : 0 for i in 1:n]], [(n,), (n,)], 2 * n);

    Running block-coordinate Frank-Wolfe with different update-orders

    In a first step, we compare different update orders. There are three different update orders implemented, FrankWolfe.FullUpdate, CyclicUpdate and Stochasticupdate. For creating a custome FrankWolfe.BlockCoordinateUpdateOrder, one needs to implement the function select_update_indices.

    struct CustomOrder <: FrankWolfe.BlockCoordinateUpdateOrder end
    +
    +function FrankWolfe.select_update_indices(::CustomOrder, state::FrankWolfe.CallbackState, dual_gaps)
    +    return [rand() < 1 / n ? 1 : 2 for _ in 1:length(state.lmo.lmos)]
    +end

    We run the block-coordinate Frank-Wolfe method with the different update orders and store the trajectories.

    trajectories = []
    +
    +for order in [
    +    FrankWolfe.FullUpdate(),
    +    FrankWolfe.CyclicUpdate(),
    +    FrankWolfe.StochasticUpdate(),
    +    CustomOrder(),
    +]
    +
    +    _, _, _, _, traj_data = FrankWolfe.block_coordinate_frank_wolfe(
    +        f,
    +        grad!,
    +        prod_lmo,
    +        x0;
    +        verbose=true,
    +        trajectory=true,
    +        update_order=order,
    +    )
    +    push!(trajectories, traj_data)
    +end
    
    +Block coordinate Frank-Wolfe (BCFW).
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.FullUpdate() UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   5.732358e-01  -1.014268e+02   1.020000e+02   0.000000e+00            Inf
    +    FW          1000   1.006522e-02   9.790473e-03   2.747434e-04   3.368302e-01   2.968855e+03
    +    FW          2000   1.002905e-02   9.883695e-03   1.453591e-04   4.092902e-01   4.886509e+03
    +    FW          3000   1.001690e-02   9.923899e-03   9.300514e-05   4.347436e-01   6.900619e+03
    +    FW          4000   1.001088e-02   9.940501e-03   7.037823e-05   4.581379e-01   8.730995e+03
    +    FW          5000   1.000730e-02   9.952154e-03   5.515099e-05   4.809050e-01   1.039706e+04
    +    FW          6000   1.000507e-02   9.960902e-03   4.416633e-05   5.037211e-01   1.191135e+04
    +    FW          7000   1.000360e-02   9.967424e-03   3.617261e-05   5.264361e-01   1.329696e+04
    +    FW          8000   1.000260e-02   9.972504e-03   3.009367e-05   5.491378e-01   1.456829e+04
    +    FW          9000   1.000190e-02   9.976620e-03   2.528359e-05   5.717150e-01   1.574211e+04
    +    FW         10000   1.000141e-02   9.979993e-03   2.141696e-05   5.942825e-01   1.682701e+04
    +  Last         10001   1.000141e-02   9.979981e-03   2.142870e-05   6.948449e-01   1.439314e+04
    +-------------------------------------------------------------------------------------------------
    +
    +Block coordinate Frank-Wolfe (BCFW).
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   5.732358e-01  -1.014268e+02   1.020000e+02   0.000000e+00            Inf
    +    FW          1000   1.006522e-02   9.790473e-03   2.747434e-04   1.218920e-01   8.203981e+03
    +    FW          2000   1.002905e-02   9.883695e-03   1.453591e-04   1.513527e-01   1.321417e+04
    +    FW          3000   1.001690e-02   9.923899e-03   9.300514e-05   1.806870e-01   1.660330e+04
    +    FW          4000   1.001088e-02   9.940501e-03   7.037823e-05   2.101374e-01   1.903516e+04
    +    FW          5000   1.000730e-02   9.952154e-03   5.515099e-05   2.986543e-01   1.674177e+04
    +    FW          6000   1.000507e-02   9.960902e-03   4.416633e-05   3.290735e-01   1.823301e+04
    +    FW          7000   1.000360e-02   9.967424e-03   3.617261e-05   3.598994e-01   1.944988e+04
    +    FW          8000   1.000260e-02   9.972504e-03   3.009367e-05   3.893015e-01   2.054963e+04
    +    FW          9000   1.000190e-02   9.976620e-03   2.528359e-05   4.186298e-01   2.149871e+04
    +    FW         10000   1.000141e-02   9.979993e-03   2.141696e-05   4.479271e-01   2.232506e+04
    +  Last         10001   1.000141e-02   9.979981e-03   2.142870e-05   4.482957e-01   2.230893e+04
    +-------------------------------------------------------------------------------------------------
    +
    +Block coordinate Frank-Wolfe (BCFW).
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.StochasticUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   5.732358e-01  -1.014268e+02   1.020000e+02   0.000000e+00            Inf
    +    FW          1000   1.006649e-02   9.797679e-03   2.688115e-04   6.094947e-02   1.640703e+04
    +    FW          2000   1.003282e-02   9.887544e-03   1.452767e-04   9.001869e-02   2.221761e+04
    +    FW          3000   1.001920e-02   9.919860e-03   9.934003e-05   1.193439e-01   2.513744e+04
    +    FW          4000   1.001224e-02   9.935454e-03   7.678946e-05   1.485355e-01   2.692960e+04
    +    FW          5000   1.000812e-02   9.949492e-03   5.863302e-05   1.778452e-01   2.811434e+04
    +    FW          6000   1.000561e-02   9.958403e-03   4.720724e-05   2.069704e-01   2.898966e+04
    +    FW          7000   1.000400e-02   9.964922e-03   3.907771e-05   2.942900e-01   2.378606e+04
    +    FW          8000   1.000288e-02   9.971244e-03   3.163293e-05   3.240107e-01   2.469055e+04
    +    FW          9000   1.000209e-02   9.975610e-03   2.647559e-05   3.552417e-01   2.533486e+04
    +    FW         10000   1.000153e-02   9.979405e-03   2.212997e-05   3.845418e-01   2.600497e+04
    +  Last         10001   1.000153e-02   9.979008e-03   2.252590e-05   3.849023e-01   2.598322e+04
    +-------------------------------------------------------------------------------------------------
    +
    +Block coordinate Frank-Wolfe (BCFW).
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: Main.CustomOrder() UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   1.024074e+02           -Inf            Inf   0.000000e+00            Inf
    +    FW          1000   1.003847e-02   9.875995e-03   1.624779e-04   1.289888e-01   7.752612e+03
    +    FW          2000   1.001380e-02   9.931922e-03   8.188221e-05   1.710828e-01   1.169024e+04
    +    FW          3000   1.000624e-02   9.955789e-03   5.044741e-05   2.109296e-01   1.422276e+04
    +    FW          4000   1.000315e-02   9.969360e-03   3.378772e-05   2.505619e-01   1.596412e+04
    +    FW          5000   1.000169e-02   9.978459e-03   2.323352e-05   2.899875e-01   1.724212e+04
    +    FW          6000   1.000095e-02   9.983540e-03   1.740806e-05   3.917290e-01   1.531671e+04
    +    FW          7000   1.000055e-02   9.987713e-03   1.283319e-05   4.316860e-01   1.621549e+04
    +    FW          8000   1.000032e-02   9.990836e-03   9.486923e-06   4.711115e-01   1.698112e+04
    +    FW          9000   1.000019e-02   9.992954e-03   7.238509e-06   5.121083e-01   1.757441e+04
    +    FW         10000   1.000012e-02   9.994356e-03   5.760023e-06   5.515142e-01   1.813190e+04
    +  Last         10001   1.000012e-02   9.994357e-03   5.759399e-06   5.519201e-01   1.812038e+04
    +-------------------------------------------------------------------------------------------------

    Plotting the results

    labels = ["Full update", "Cyclic order", "Stochstic order", "Custom order"]
    +plot_trajectories(trajectories, labels, xscalelog=true)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Running BCFW with different update methods

    As a second step, we compare different update steps. We consider the FrankWolfe.BPCGStep and the FrankWolfe.FrankWolfeStep. One can either pass a tuple of FrankWolfe.UpdateStep to define for each block the update procedure or pass a single update step so that each block uses the same procedure.

    trajectories = []
    +
    +for us in [(FrankWolfe.BPCGStep(), FrankWolfe.FrankWolfeStep()), (FrankWolfe.FrankWolfeStep(), FrankWolfe.BPCGStep()), FrankWolfe.BPCGStep(), FrankWolfe.FrankWolfeStep()]
    +
    +    _, _, _, _, traj_data = FrankWolfe.block_coordinate_frank_wolfe(
    +        f,
    +        grad!,
    +        prod_lmo,
    +        x0;
    +        verbose=true,
    +        trajectory=true,
    +        update_step=us,
    +    )
    +    push!(trajectories, traj_data)
    +end
    
    +Block coordinate Frank-Wolfe (BCFW).
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.BPCGStep, FrankWolfe.FrankWolfeStep]
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   5.732358e-01  -1.014268e+02   1.020000e+02   0.000000e+00            Inf
    +    FW          1000   1.006522e-02   9.790473e-03   2.747434e-04   5.414172e-01   1.847005e+03
    +    FW          2000   1.002905e-02   9.883695e-03   1.453591e-04   5.799674e-01   3.448470e+03
    +    FW          3000   1.001690e-02   9.923899e-03   9.300514e-05   6.181764e-01   4.852983e+03
    +    FW          4000   1.001088e-02   9.940501e-03   7.037823e-05   6.566480e-01   6.091544e+03
    +    FW          5000   1.000730e-02   9.952154e-03   5.515099e-05   7.524854e-01   6.644647e+03
    +    FW          6000   1.000507e-02   9.960902e-03   4.416633e-05   7.913436e-01   7.582041e+03
    +    FW          7000   1.000360e-02   9.967424e-03   3.617261e-05   8.298248e-01   8.435516e+03
    +    FW          8000   1.000260e-02   9.972504e-03   3.009367e-05   8.679960e-01   9.216633e+03
    +    FW          9000   1.000190e-02   9.976620e-03   2.528359e-05   9.067724e-01   9.925313e+03
    +    FW         10000   1.000141e-02   9.979993e-03   2.141696e-05   9.448296e-01   1.058392e+04
    +  Last         10001   1.000141e-02   9.979981e-03   2.142870e-05   9.452366e-01   1.058042e+04
    +-------------------------------------------------------------------------------------------------
    +
    +Block coordinate Frank-Wolfe (BCFW).
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.BPCGStep]
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   5.732358e-01  -1.014268e+02   1.020000e+02   0.000000e+00            Inf
    +  Last           474   1.000000e-02   9.999910e-03   8.999181e-08   2.000159e-01   2.369811e+03
    +-------------------------------------------------------------------------------------------------
    +
    +Block coordinate Frank-Wolfe (BCFW).
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.BPCGStep, FrankWolfe.BPCGStep]
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   5.732358e-01  -1.014268e+02   1.020000e+02   0.000000e+00            Inf
    +  Last           474   1.000000e-02   9.999910e-03   8.999181e-08   2.694482e-02   1.759150e+04
    +-------------------------------------------------------------------------------------------------
    +
    +Block coordinate Frank-Wolfe (BCFW).
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   5.732358e-01  -1.014268e+02   1.020000e+02   0.000000e+00            Inf
    +    FW          1000   1.006522e-02   9.790473e-03   2.747434e-04   3.061760e-02   3.266096e+04
    +    FW          2000   1.002905e-02   9.883695e-03   1.453591e-04   1.132728e-01   1.765649e+04
    +    FW          3000   1.001690e-02   9.923899e-03   9.300514e-05   1.452280e-01   2.065718e+04
    +    FW          4000   1.001088e-02   9.940501e-03   7.037823e-05   1.750666e-01   2.284845e+04
    +    FW          5000   1.000730e-02   9.952154e-03   5.515099e-05   2.046835e-01   2.442796e+04
    +    FW          6000   1.000507e-02   9.960902e-03   4.416633e-05   2.340556e-01   2.563494e+04
    +    FW          7000   1.000360e-02   9.967424e-03   3.617261e-05   2.634642e-01   2.656907e+04
    +    FW          8000   1.000260e-02   9.972504e-03   3.009367e-05   2.928940e-01   2.731364e+04
    +    FW          9000   1.000190e-02   9.976620e-03   2.528359e-05   3.220756e-01   2.794375e+04
    +    FW         10000   1.000141e-02   9.979993e-03   2.141696e-05   4.135164e-01   2.418284e+04
    +  Last         10001   1.000141e-02   9.979981e-03   2.142870e-05   4.138990e-01   2.416290e+04
    +-------------------------------------------------------------------------------------------------

    Plotting the results

    labels = ["BPCG FW", "FW BPCG", "BPCG", "FW"]
    +plot_trajectories(trajectories, labels, xscalelog=true)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/docs_12_quadratic_symmetric/index.html b/previews/PR539/examples/docs_12_quadratic_symmetric/index.html new file mode 100644 index 000000000..7fa700f02 --- /dev/null +++ b/previews/PR539/examples/docs_12_quadratic_symmetric/index.html @@ -0,0 +1,310 @@ + +Accelerations for quadratic functions and symmetric problems · FrankWolfe.jl
    plot_sparsity (generic function with 1 method)

    Accelerations for quadratic functions and symmetric problems

    This example illustrates how to exploit symmetry to reduce the dimension of the problem via SubspaceLMO. Moreover, active set based algorithms can be accelerated by using the specialized structure ActiveSetQuadraticProductCaching.

    The specific problem we consider here comes from quantum information and some context can be found here. Formally, we want to find the distance between a tensor of size m^N and the N-partite local polytope which is defined by its vertices

    \[d^{\vec{a}^{(1)}\ldots \vec{a}^{(N)}}_{x_1\ldots x_N}\coloneqq\prod_{n=1}^Na^{(n)}_{x_n}\]

    labeled by $\vec{a}^{(n)}=a^{(n)}_1\ldots a^{(n)}_m$ for $n\in[1,N]$, where $a^{(n)}_x=\pm1$. In the bipartite case (N=2), this polytope is affinely equivalent to the cut polytope.

    Import and setup

    We first import the necessary packages.

    import Combinatorics
    +import FrankWolfe
    +import LinearAlgebra
    +import Tullio

    Then we can define our custom LMO, together with the method compute_extreme_point, which simply enumerates the vertices $d^{\vec{a}^{(1)}}$ defined above. This structure is specialized for the case N=5 and contains pre-allocated fields used to accelerate the enumeration. Note that the output type (full tensor) is quite naive, but this is enough to illustrate the syntax in this toy example.

    struct BellCorrelationsLMO{T} <: FrankWolfe.LinearMinimizationOracle
    +    m::Int # size of the tensor
    +    tmp1::Array{T, 1}
    +    tmp2::Array{T, 2}
    +    tmp3::Array{T, 3}
    +    tmp4::Array{T, 4}
    +end
    +
    +function FrankWolfe.compute_extreme_point(lmo::BellCorrelationsLMO{T}, A::Array{T, 5}; kwargs...) where {T <: Number}
    +    ax = [ones(T, lmo.m) for n in 1:5]
    +    sc1 = zero(T)
    +    sc2 = one(T)
    +    axm = [zeros(T, lmo.m) for n in 1:5]
    +    scm = typemax(T)
    +    L = 2^lmo.m
    +    aux = zeros(Int, lmo.m)
    +    for λa5 in 0:(L÷2)-1
    +        digits!(aux, λa5, base=2)
    +        ax[5] .= 2aux .- 1
    +        Tullio.@tullio lmo.tmp4[x1, x2, x3, x4] = A[x1, x2, x3, x4, x5] * ax[5][x5]
    +        for λa4 in 0:L-1
    +            digits!(aux, λa4, base=2)
    +            ax[4] .= 2aux .- 1
    +            Tullio.@tullio lmo.tmp3[x1, x2, x3] = lmo.tmp4[x1, x2, x3, x4] * ax[4][x4]
    +            for λa3 in 0:L-1
    +                digits!(aux, λa3, base=2)
    +                ax[3] .= 2aux .- 1
    +                Tullio.@tullio lmo.tmp2[x1, x2] = lmo.tmp3[x1, x2, x3] * ax[3][x3]
    +                for λa2 in 0:L-1
    +                    digits!(aux, λa2, base=2)
    +                    ax[2] .= 2aux .- 1
    +                    LinearAlgebra.mul!(lmo.tmp1, lmo.tmp2, ax[2])
    +                    for x1 in 1:lmo.m
    +                        ax[1][x1] = lmo.tmp1[x1] > zero(T) ? -one(T) : one(T)
    +                    end
    +                    sc = LinearAlgebra.dot(ax[1], lmo.tmp1)
    +                    if sc < scm
    +                        scm = sc
    +                        for n in 1:5
    +                            axm[n] .= ax[n]
    +                        end
    +                    end
    +                end
    +            end
    +        end
    +    end
    +    return [axm[1][x1]*axm[2][x2]*axm[3][x3]*axm[4][x4]*axm[5][x5] for x1 in 1:lmo.m, x2 in 1:lmo.m, x3 in 1:lmo.m, x4 in 1:lmo.m, x5 in 1:lmo.m]
    +end

    Then we define our specific instance, coming from a GHZ state measured with measurements forming a regular polygon on the equator of the Bloch sphere. See this article for definitions and references.

    function correlation_tensor_GHZ_polygon(::Type{T}, N::Int, m::Int) where {T <: Number}
    +    res = zeros(T, m*ones(Int, N)...)
    +    tab_cos = [cos(x*T(pi)/m) for x in 0:N*m]
    +    tab_cos[abs.(tab_cos) .< Base.rtoldefault(T)] .= zero(T)
    +    for ci in CartesianIndices(res)
    +        res[ci] = tab_cos[sum(ci.I)-N+1]
    +    end
    +    return res
    +end
    +
    +T = Float64
    +verbose = true
    +max_iteration = 10^4
    +m = 5
    +p = 0.23correlation_tensor_GHZ_polygon(T, 5, m)
    +x0 = zeros(T, size(p))

    The objective function is simply $\frac12\|x-p\|_2^2$, which we decompose in different terms for speed.

    normp2 = LinearAlgebra.dot(p, p) / 2
    +f = let p = p, normp2 = normp2
    +    x -> LinearAlgebra.dot(x, x) / 2 - LinearAlgebra.dot(p, x) + normp2
    +end
    +grad! = let p = p
    +    (storage, x) -> begin
    +        @inbounds for i in eachindex(x)
    +            storage[i] = x[i] - p[i]
    +        end
    +    end
    +end

    Naive run

    If we run the blended pairwise conditional gradient algorithm without modifications, convergence is not reached in 10000 iterations.

    lmo_naive = BellCorrelationsLMO{T}(m, zeros(T, m), zeros(T, m, m), zeros(T, m, m, m), zeros(T, m, m, m, m))
    +as_naive = FrankWolfe.ActiveSet([(one(T), x0)])
    +@time FrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_naive, as_naive; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)
    
    +Blended Pairwise Conditional Gradient Algorithm.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: Shortstep EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +GRADIENTTYPE: Array{Float64, 5} LAZY: true lazy_tolerance: 2.0
    +LMO: Main.BellCorrelationsLMO{Float64}
    +
    +----------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec     #ActiveSet
    +----------------------------------------------------------------------------------------------------------------
    +     I             1   4.132812e+01  -4.029553e+01   8.162365e+01   0.000000e+00            Inf              1
    +    LD            46   1.102219e+01  -2.889653e+01   3.991872e+01   4.595633e+00   1.000950e+01             46
    +    LD           103   4.741326e+00  -1.484609e+01   1.958742e+01   8.153061e+00   1.263329e+01             79
    +    LD           217   1.129314e+00  -5.004581e+00   6.133895e+00   1.312947e+01   1.652771e+01            126
    +    LD           351   7.257875e-01  -2.271567e+00   2.997354e+00   1.653206e+01   2.123147e+01            157
    +     P          1000   4.532655e-01  -2.544089e+00   2.997354e+00   3.249967e+01   3.076954e+01            310
    +    LD          1621   2.613257e-01  -1.230782e+00   1.492108e+00   4.680695e+01   3.463161e+01            445
    +     P          2000   2.268145e-01  -1.265294e+00   1.492108e+00   4.715997e+01   4.240885e+01            440
    +     P          3000   1.381013e-01  -1.354007e+00   1.492108e+00   5.488478e+01   5.465996e+01            496
    +     P          4000   6.040867e-02  -1.431699e+00   1.492108e+00   6.810986e+01   5.872865e+01            610
    +    LD          4415   3.072837e-02  -4.006321e-01   4.313605e-01   7.314600e+01   6.035874e+01            647
    +     P          5000   1.738588e-02  -4.139746e-01   4.313605e-01   7.349730e+01   6.802971e+01            627
    +    LD          5663   1.229003e-02  -1.045655e-01   1.168556e-01   7.378709e+01   7.674784e+01            625
    +     P          6000   1.113787e-02  -1.057177e-01   1.168556e-01   7.408513e+01   8.098792e+01            625
    +     P          7000   9.735387e-03  -1.071202e-01   1.168556e-01   7.452778e+01   9.392471e+01            625
    +    LD          7469   9.517109e-03  -2.020889e-02   2.972600e-02   7.473413e+01   9.994095e+01            625
    +     P          8000   9.392674e-03  -2.033332e-02   2.972600e-02   7.505417e+01   1.065897e+02            625
    +     P          9000   9.304994e-03  -2.042100e-02   2.972600e-02   7.548410e+01   1.192304e+02            625
    +    LD          9490   9.290088e-03   1.701123e-03   7.588965e-03   7.569643e+01   1.253692e+02            625
    +     P         10000   9.282251e-03   1.693286e-03   7.588965e-03   7.600393e+01   1.315721e+02            625
    +  Last         10001   9.282230e-03   3.629714e-03   5.652516e-03   7.610122e+01   1.314171e+02            625
    +----------------------------------------------------------------------------------------------------------------
    +    PP         10001   9.282230e-03   3.629714e-03   5.652516e-03   7.619714e+01   1.312516e+02            625
    +----------------------------------------------------------------------------------------------------------------
    + 76.288024 seconds (378.64 M allocations: 45.133 GiB, 11.86% gc time, 0.17% compilation time)

    Faster active set for quadratic functions

    A first acceleration can be obtained by using the active set specialized for the quadratic objective function, whose gradient is here $x-p$, explaining the hessian and linear part provided as arguments. The speedup is obtained by pre-computing some scalar products to quickly obtained, in each iteration, the best and worst atoms currently in the active set.

    asq_naive = FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0)], LinearAlgebra.I, -p)
    +@time FrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_naive, asq_naive; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)
    
    +Blended Pairwise Conditional Gradient Algorithm.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: Shortstep EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +GRADIENTTYPE: Array{Float64, 5} LAZY: true lazy_tolerance: 2.0
    +LMO: Main.BellCorrelationsLMO{Float64}
    +
    +----------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec     #ActiveSet
    +----------------------------------------------------------------------------------------------------------------
    +     I             1   4.132812e+01  -4.029553e+01   8.162365e+01   0.000000e+00            Inf              1
    +    LD            46   1.102219e+01  -2.889653e+01   3.991872e+01   4.571951e+00   1.006135e+01             46
    +    LD           104   4.682362e+00  -1.505762e+01   1.973998e+01   8.150547e+00   1.275988e+01             79
    +    LD           217   1.153286e+00  -4.834945e+00   5.988231e+00   1.317503e+01   1.647055e+01            126
    +    LD           361   7.246254e-01  -2.234291e+00   2.958916e+00   1.668527e+01   2.163586e+01            158
    +     P          1000   4.580028e-01  -2.500913e+00   2.958916e+00   3.208251e+01   3.116964e+01            305
    +    LD          1759   2.293608e-01  -1.236982e+00   1.466343e+00   4.887313e+01   3.599114e+01            460
    +     P          2000   2.035603e-01  -1.262782e+00   1.466343e+00   4.896929e+01   4.084193e+01            458
    +     P          3000   1.211665e-01  -1.345176e+00   1.466343e+00   5.464957e+01   5.489522e+01            500
    +     P          4000   4.749301e-02  -1.418850e+00   1.466343e+00   6.878090e+01   5.815568e+01            632
    +    LD          4227   3.237072e-02  -3.805380e-01   4.129088e-01   7.129930e+01   5.928529e+01            654
    +     P          5000   1.624641e-02  -3.966624e-01   4.129088e-01   7.147601e+01   6.995354e+01            625
    +    LD          5566   1.241685e-02  -1.000254e-01   1.124422e-01   7.149575e+01   7.785078e+01            625
    +     P          6000   1.102951e-02  -1.014127e-01   1.124422e-01   7.160347e+01   8.379482e+01            625
    +     P          7000   9.754199e-03  -1.026880e-01   1.124422e-01   7.163609e+01   9.771611e+01            625
    +    LD          7558   9.511291e-03  -1.988317e-02   2.939446e-02   7.165608e+01   1.054760e+02            625
    +     P          8000   9.410900e-03  -1.998356e-02   2.939446e-02   7.176044e+01   1.114820e+02            625
    +     P          9000   9.314629e-03  -2.007983e-02   2.939446e-02   7.179372e+01   1.253592e+02            625
    +    LD          9702   9.291671e-03   1.444824e-03   7.846848e-03   7.181783e+01   1.350918e+02            625
    +     P         10000   9.286464e-03   1.439616e-03   7.846848e-03   7.191689e+01   1.390494e+02            625
    +  Last         10001   9.286436e-03   2.102908e-03   7.183528e-03   7.207918e+01   1.387502e+02            625
    +----------------------------------------------------------------------------------------------------------------
    +    PP         10001   9.286436e-03   2.102908e-03   7.183528e-03   7.217832e+01   1.385596e+02            625
    +----------------------------------------------------------------------------------------------------------------
    + 72.335800 seconds (374.84 M allocations: 44.687 GiB, 12.72% gc time, 0.17% compilation time)

    In this small example, the acceleration is quite minimal, but as soon as one of the following conditions is met, significant speedups (factor ten at least) can be expected:

    • quite expensive scalar product between atoms, for instance, due to a high dimension (say, more than 10000),
    • high number of atoms in the active set (say, more than 1000),
    • high number of iterations (say, more than 100000), spending most of the time redistributing the weights in the active set.

    Dimension reduction via symmetrization

    Permutation of the tensor axes

    It is easy to see that our specific instance remains invariant under permutation of the dimensions of the tensor. This means that all computations can be performed in the symmetric subspace, which leads to an important speedup, owing to the reduced dimension (hence reduced size of the final active set and reduced number of iterations).

    The way to operate this in the FrankWolfe package is to use a symmetrized LMO, which basically does the following:

    • symmetrize the gradient, which is not necessary here as the gradient remains symmetric throughout the algorithm,
    • call the standard LMO,
    • symmetrize its output, which amounts to averaging over its orbit with respect to the group considered (here the symmetric group permuting the dimensions of the tensor).
    function reynolds_permutedims(atom::Array{T, N}, lmo::BellCorrelationsLMO{T}) where {T <: Number, N}
    +    res = zeros(T, size(atom))
    +    for per in Combinatorics.permutations(1:N)
    +        res .+= permutedims(atom, per)
    +    end
    +    res ./= factorial(N)
    +    return res
    +end

    Note that the second argument lmo is not used here but could in principle be exploited to obtain a very small speedup by precomputing and storing Combinatorics.permutations(1:N) in a dedicated field of our custom LMO.

    lmo_permutedims = FrankWolfe.SubspaceLMO(lmo_naive, reynolds_permutedims)
    +asq_permutedims = FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0)], LinearAlgebra.I, -p)
    +@time FrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_permutedims, asq_permutedims; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)
    
    +Blended Pairwise Conditional Gradient Algorithm.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: Shortstep EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +GRADIENTTYPE: Array{Float64, 5} LAZY: true lazy_tolerance: 2.0
    +LMO: FrankWolfe.SubspaceLMO{Main.BellCorrelationsLMO{Float64}, typeof(Main.reynolds_permutedims), FrankWolfe.var"#10#11"}
    +
    +----------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec     #ActiveSet
    +----------------------------------------------------------------------------------------------------------------
    +     I             1   4.132812e+01  -4.029553e+01   8.162365e+01   0.000000e+00            Inf              1
    +    LD            11   1.153403e+01  -2.734161e+01   3.887563e+01   8.643599e-01   1.272618e+01              9
    +    LD            29   3.294910e+00  -1.375281e+01   1.704772e+01   1.424753e+00   2.035441e+01             13
    +    LD            47   1.630202e+00  -6.744183e+00   8.374385e+00   1.764509e+00   2.663631e+01             15
    +    LD           100   4.530833e-01  -2.912142e+00   3.365226e+00   2.808908e+00   3.560103e+01             23
    +    LD           175   1.770240e-01  -1.434036e+00   1.611060e+00   3.330226e+00   5.254898e+01             23
    +    LD           268   8.360800e-02  -6.726422e-01   7.562502e-01   4.092942e+00   6.547857e+01             29
    +    LD           555   2.209150e-02  -2.970870e-01   3.191785e-01   4.711246e+00   1.178032e+02             30
    +    LD           773   1.139297e-02  -6.500159e-02   7.639456e-02   4.808687e+00   1.607507e+02             26
    +     P          1000   9.617158e-03  -6.677740e-02   7.639456e-02   4.905976e+00   2.038330e+02             26
    +    LD          1086   9.450474e-03  -9.519297e-03   1.896977e-02   4.918961e+00   2.207784e+02             26
    +    LD          1500   9.283632e-03   4.858918e-03   4.424714e-03   5.090803e+00   2.946490e+02             26
    +    LD          1900   9.274785e-03   8.183461e-03   1.091323e-03   5.189915e+00   3.660946e+02             26
    +     P          2000   9.274488e-03   8.183165e-03   1.091323e-03   5.285229e+00   3.784131e+02             26
    +    LD          2326   9.274249e-03   9.015738e-03   2.585111e-04   5.293896e+00   4.393740e+02             26
    +    LD          2740   9.274216e-03   9.214614e-03   5.960203e-05   5.395902e+00   5.077928e+02             26
    +     P          3000   9.274214e-03   9.214612e-03   5.960203e-05   5.493940e+00   5.460562e+02             26
    +    LD          3178   9.274214e-03   9.262304e-03   1.190966e-05   5.498826e+00   5.779416e+02             26
    +    LD          3636   9.274214e-03   9.271595e-03   2.619296e-06   5.667037e+00   6.416052e+02             26
    +     P          4000   9.274214e-03   9.271595e-03   2.619296e-06   5.769581e+00   6.932912e+02             26
    +    LD          4064   9.274214e-03   9.273578e-03   6.357779e-07   5.771592e+00   7.041385e+02             26
    +    LD          4470   9.274214e-03   9.274066e-03   1.484091e-07   5.874184e+00   7.609568e+02             26
    +    LD          4865   9.274214e-03   9.274179e-03   3.537488e-08   5.975528e+00   8.141541e+02             26
    +  Last          4865   9.274214e-03   9.274179e-03   3.537488e-08   6.223840e+00   7.816718e+02             26
    +----------------------------------------------------------------------------------------------------------------
    +    PP          4865   9.274214e-03   9.274179e-03   3.537488e-08   6.317086e+00   7.701336e+02             26
    +----------------------------------------------------------------------------------------------------------------
    +  6.409094 seconds (31.77 M allocations: 3.930 GiB, 12.99% gc time, 2.04% compilation time)

    Now, convergence is reached within 10000 iterations, and the size of the final active set is considerably smaller than before, thanks to the reduced dimension.

    Uniqueness pattern

    In this specific case, there is a bigger symmetry group that we can exploit. Its action roughly allows us to work in the subspace respecting the structure of the objective point p, that is, to average over tensor entries that have the same value in p. Although quite general, this kind of symmetry is not always applicable, and great care has to be taken when using it, in particular, to ensure that there exists a suitable group action whose Reynolds operator corresponds to this averaging procedure. In our current case, the theoretical study enabling this further symmetrization can be found here.

    function build_reynolds_unique(p::Array{T, N}) where {T <: Number, N}
    +    ptol = round.(p; digits=8)
    +    ptol[ptol .== zero(T)] .= zero(T) # transform -0.0 into 0.0 as isequal(0.0, -0.0) is false
    +    uniquetol = unique(ptol[:])
    +    indices = [ptol .== u for u in uniquetol]
    +    return function(A::Array{T, N}, lmo)
    +        res = zeros(T, size(A))
    +        for ind in indices
    +            @view(res[ind]) .= sum(A[ind]) / sum(ind) # average over ind
    +        end
    +        return res
    +    end
    +end
    +
    +lmo_unique = FrankWolfe.SubspaceLMO(lmo_naive, build_reynolds_unique(p))
    +asq_unique = FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0)], LinearAlgebra.I, -p)
    +@time FrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_unique, asq_unique; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)
    
    +Blended Pairwise Conditional Gradient Algorithm.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: Shortstep EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +GRADIENTTYPE: Array{Float64, 5} LAZY: true lazy_tolerance: 2.0
    +LMO: FrankWolfe.SubspaceLMO{Main.BellCorrelationsLMO{Float64}, Main.var"#43#45"{5, Float64, Vector{BitArray{5}}}, FrankWolfe.var"#10#11"}
    +
    +----------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec     #ActiveSet
    +----------------------------------------------------------------------------------------------------------------
    +     I             1   4.132812e+01  -4.029553e+01   8.162365e+01   0.000000e+00            Inf              1
    +    LD             4   2.991558e+00  -4.896575e+00   7.888134e+00   1.673447e-01   2.390276e+01              3
    +    LD            19   4.246112e-01  -2.691388e+00   3.115999e+00   2.981037e-01   6.373621e+01              3
    +    LD            64   1.802165e-01  -4.514355e-01   6.316521e-01   7.299275e-01   8.767995e+01              5
    +    LD            81   2.002637e-02  -1.558821e-01   1.759085e-01   1.069653e+00   7.572547e+01              5
    +    LD           118   1.364017e-02  -4.146471e-02   5.510488e-02   1.172496e+00   1.006400e+02              3
    +    LD           189   9.505756e-03  -8.772067e-03   1.827782e-02   1.354335e+00   1.395518e+02              4
    +    LD           204   9.297335e-03   2.741829e-03   6.555506e-03   1.444415e+00   1.412337e+02              4
    +    LD           219   9.278805e-03   6.432857e-03   2.845948e-03   1.601612e+00   1.367373e+02              4
    +    LD           237   9.274768e-03   8.268553e-03   1.006215e-03   1.693048e+00   1.399842e+02              4
    +    LD           255   9.274310e-03   8.844241e-03   4.300684e-04   1.783597e+00   1.429695e+02              4
    +    LD           270   9.274227e-03   9.117815e-03   1.564121e-04   1.873845e+00   1.440888e+02              4
    +    LD           288   9.274216e-03   9.207613e-03   6.660359e-05   1.965709e+00   1.465120e+02              4
    +    LD           303   9.274214e-03   9.249991e-03   2.422305e-05   2.120122e+00   1.429163e+02              4
    +    LD           321   9.274214e-03   9.263899e-03   1.031492e-05   2.211931e+00   1.451221e+02              4
    +    LD           336   9.274214e-03   9.270465e-03   3.748623e-06   2.302487e+00   1.459292e+02              4
    +    LD           354   9.274214e-03   9.272618e-03   1.595962e-06   2.393147e+00   1.479224e+02              4
    +    LD           369   9.274214e-03   9.273636e-03   5.784864e-07   2.548787e+00   1.447747e+02              4
    +    LD           384   9.274214e-03   9.273964e-03   2.499339e-07   2.635220e+00   1.457184e+02              4
    +    LD           397   9.274214e-03   9.274104e-03   1.101735e-07   2.726400e+00   1.456133e+02              4
    +    LD           412   9.274214e-03   9.274166e-03   4.841374e-08   2.816670e+00   1.462720e+02              4
    +  Last           412   9.274214e-03   9.274166e-03   4.841374e-08   3.059147e+00   1.346781e+02              4
    +----------------------------------------------------------------------------------------------------------------
    +    PP           412   9.274214e-03   9.274166e-03   4.841374e-08   3.150997e+00   1.307523e+02              4
    +----------------------------------------------------------------------------------------------------------------
    +  3.316372 seconds (16.52 M allocations: 1.955 GiB, 14.26% gc time, 3.50% compilation time)

    Reduction of the memory footprint of the iterate

    In the previous run, the dimension reduction is mathematically exploited to accelerate the algorithm, but it is not used to effectively work in a subspace of reduced dimension. Indeed, the iterate, although symmetric, was still a full tensor. As a last example of the speedup obtainable through symmetry reduction, we show how to map the computations into a space whose physical dimension is also reduced during the algorithm. This makes all in-place operations marginally faster, which can lead, in bigger instances, to significant accelerations, especially for active set based algorithms in the regime where many lazy iterations are performed. We refer to the example symmetric.jl for a small benchmark with symmetric matrices.

    function build_deflate_inflate(p::Array{T, N}) where {T <: Number, N}
    +    ptol = round.(p; digits=8)
    +    ptol[ptol .== zero(T)] .= zero(T) # transform -0.0 into 0.0 as isequal(0.0, -0.0) is false
    +    uniquetol = unique(ptol[:])
    +    dim = length(uniquetol) # reduced dimension
    +    indices = [ptol .== u for u in uniquetol]
    +    mul = [sum(ind) for ind in indices] # multiplicities, used to have matching scalar products
    +    sqmul = sqrt.(mul) # precomputed for speed
    +    return function(A::Array{T, N}, lmo)
    +        vec = zeros(T, dim)
    +        for (i, ind) in enumerate(indices)
    +            vec[i] = sum(A[ind]) / sqmul[i]
    +        end
    +        return FrankWolfe.SubspaceVector(A, vec)
    +    end, function(x::FrankWolfe.SubspaceVector, lmo)
    +        for (i, ind) in enumerate(indices)
    +            @view(x.data[ind]) .= x.vec[i] / sqmul[i]
    +        end
    +        return x.data
    +    end
    +end
    +
    +deflate, inflate = build_deflate_inflate(p)
    +p_deflate = deflate(p, nothing)
    +x0_deflate = deflate(x0, nothing)
    +f_deflate = let p_deflate = p_deflate, normp2 = normp2
    +    x -> LinearAlgebra.dot(x, x) / 2 - LinearAlgebra.dot(p_deflate, x) + normp2
    +end
    +grad_deflate! = let p_deflate = p_deflate
    +    (storage, x) -> begin
    +        @inbounds for i in eachindex(x)
    +            storage[i] = x[i] - p_deflate[i]
    +        end
    +    end
    +end

    Note that the objective function and its gradient have to be explicitly rewritten. In this simple example, their shape remains unchanged, but in general this may need some reformulation, which falls to the user.

    lmo_deflate = FrankWolfe.SubspaceLMO(lmo_naive, deflate, inflate)
    +asq_deflate = FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0_deflate)], LinearAlgebra.I, -p_deflate)
    +@time FrankWolfe.blended_pairwise_conditional_gradient(f_deflate, grad_deflate!, lmo_deflate, asq_deflate; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)
    
    +Blended Pairwise Conditional Gradient Algorithm.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: Shortstep EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +GRADIENTTYPE: FrankWolfe.SubspaceVector{false, Float64, Array{Float64, 5}, Vector{Float64}} LAZY: true lazy_tolerance: 2.0
    +LMO: FrankWolfe.SubspaceLMO{Main.BellCorrelationsLMO{Float64}, Main.var"#47#50"{5, Float64, Vector{Float64}, Vector{BitArray{5}}, Int64}, Main.var"#48#51"{Vector{Float64}, Vector{BitArray{5}}}}
    +
    +----------------------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec     #ActiveSet
    +----------------------------------------------------------------------------------------------------------------
    +     I             1   4.132812e+01  -4.029553e+01   8.162365e+01   0.000000e+00            Inf              1
    +    LD             4   2.991558e+00  -4.896575e+00   7.888134e+00   1.759810e-01   2.272972e+01              3
    +    LD            13   2.369634e-01  -2.280882e+00   2.517846e+00   3.994364e-01   3.254586e+01              4
    +    LD            19   1.668285e-01  -3.158581e-01   4.826866e-01   7.397272e-01   2.568515e+01              5
    +    LD            32   1.699135e-02  -5.050512e-02   6.749647e-02   9.190518e-01   3.481849e+01              5
    +    LD           108   9.519110e-03  -6.845621e-03   1.636473e-02   1.166373e+00   9.259470e+01              4
    +    LD           121   9.297134e-03   3.819920e-03   5.477214e-03   1.257585e+00   9.621620e+01              4
    +    LD           130   9.276520e-03   7.486464e-03   1.790056e-03   1.347761e+00   9.645626e+01              4
    +    LD           139   9.274453e-03   8.643094e-03   6.313589e-04   1.437827e+00   9.667369e+01              4
    +    LD           148   9.274257e-03   8.982108e-03   2.921491e-04   1.599401e+00   9.253463e+01              4
    +    LD           161   9.274223e-03   9.143488e-03   1.307348e-04   1.697446e+00   9.484837e+01              4
    +    LD           174   9.274215e-03   9.222314e-03   5.190121e-05   1.788882e+00   9.726746e+01              4
    +    LD           187   9.274214e-03   9.250977e-03   2.323707e-05   1.878820e+00   9.953056e+01              4
    +    LD           202   9.274214e-03   9.265798e-03   8.416106e-06   1.968623e+00   1.026098e+02              4
    +    LD           215   9.274214e-03   9.270455e-03   3.759433e-06   2.120136e+00   1.014086e+02              4
    +    LD           228   9.274214e-03   9.272829e-03   1.384972e-06   2.210476e+00   1.031452e+02              4
    +    LD           244   9.274214e-03   9.273611e-03   6.025805e-07   2.301278e+00   1.060280e+02              4
    +    LD           257   9.274214e-03   9.273974e-03   2.395475e-07   2.391824e+00   1.074494e+02              4
    +    LD           270   9.274214e-03   9.274107e-03   1.073458e-07   2.481536e+00   1.088036e+02              4
    +    LD           285   9.274214e-03   9.274175e-03   3.860101e-08   2.635663e+00   1.081322e+02              4
    +  Last           285   9.274214e-03   9.274175e-03   3.860101e-08   2.817384e+00   1.011577e+02              4
    +----------------------------------------------------------------------------------------------------------------
    +    PP           285   9.274214e-03   9.274175e-03   3.860101e-08   2.907288e+00   9.802949e+01              4
    +----------------------------------------------------------------------------------------------------------------
    +  3.079286 seconds (15.43 M allocations: 1.825 GiB, 13.38% gc time, 4.28% compilation time)

    This page was generated using Literate.jl.

    diff --git a/previews/PR539/examples/plot_utils.jl b/previews/PR539/examples/plot_utils.jl new file mode 100644 index 000000000..048ea4382 --- /dev/null +++ b/previews/PR539/examples/plot_utils.jl @@ -0,0 +1,422 @@ +using Plots + +""" +plot_results +Given a series of list, generate subplots. +list_data_y -> contains a list of a list of lists (where each list refers to a subplot, and a list of lists refers to the y-values of the series inside a subplot). +list_data_x -> contains a list of a list of lists (where each list refers to a subplot, and a list of lists refers to the x-values of the series inside a subplot). +So if we have one plot with two series, these might look like: + list_data_y = [[[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]]] + list_data_x = [[[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]]] +And if we have two plots, each with two series, these might look like: + list_data_y = [[[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]], [[7, 8, 9, 10, 11, 12], [7, 8, 9, 10, 11, 12]]] + list_data_x = [[[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]], [[7, 8, 9, 10, 11, 12], [7, 8, 9, 10, 11, 12]]] +list_label -> contains the labels for the series that will be plotted, +which has to have a length equal to the number of series that are being plotted: + list_label = ["Series 1", "Series 2"] +list_axis_x -> contains the labels for the x-axis that will be plotted, +which has to have a length equal to the number of subplots: + list_axis_x = ["x-axis plot 1", "x-axis plot 1"] +list_axis_y -> Same as list_axis_x but for the y-axis +xscalelog -> A list of values indicating the type of axes to use in each subplot, +must be equal to the number of subplots: + xscalelog = [:log, :identity] +yscalelog -> Same as xscalelog but for the y-axis +""" +function plot_results( + list_data_y, + list_data_x, + list_label, + list_axis_x, + list_axis_y; + filename=nothing, + xscalelog=nothing, + yscalelog=nothing, + legend_position=nothing, + list_style=fill(:solid, length(list_label)), + list_color=get_color_palette(:auto, plot_color(:white)), + list_markers=[ + :circle, + :rect, + :utriangle, + :diamond, + :hexagon, + :+, + :x, + :star5, + :cross, + :xcross, + :dtriangle, + :rtriangle, + :ltriangle, + :pentagon, + :heptagon, + :octagon, + :star4, + :star6, + :star7, + :star8, + :vline, + :hline, + ], + number_markers_per_line=10, + line_width=3.0, + marker_size=5.0, + transparency_markers=0.45, + font_size_axis=12, + font_size_legend=9, +) + gr() + plt = nothing + list_plots = Plots.Plot{Plots.GRBackend}[] + #Plot an appropiate number of plots + for i in eachindex(list_data_x) + for j in eachindex(list_data_x[i]) + if isnothing(xscalelog) + xscale = :identity + else + xscale = xscalelog[i] + end + if isnothing(yscalelog) + yscale = :log + else + yscale = yscalelog[i] + end + if isnothing(legend_position) + position_legend = :best + legend_display = true + else + position_legend = legend_position[i] + if isnothing(position_legend) + legend_display = false + else + legend_display = true + end + end + if j == 1 + if legend_display + plt = plot( + list_data_x[i][j], + list_data_y[i][j], + label="", + xaxis=xscale, + yaxis=yscale, + ylabel=list_axis_y[i], + xlabel=list_axis_x[i], + legend=position_legend, + yguidefontsize=font_size_axis, + xguidefontsize=font_size_axis, + legendfontsize=font_size_legend, + width=line_width, + linestyle=list_style[j], + color=list_color[j], + grid=true, + ) + else + plt = plot( + list_data_x[i][j], + list_data_y[i][j], + label="", + xaxis=xscale, + yaxis=yscale, + ylabel=list_axis_y[i], + xlabel=list_axis_x[i], + yguidefontsize=font_size_axis, + xguidefontsize=font_size_axis, + width=line_width, + linestyle=list_style[j], + color=list_color[j], + grid=true, + ) + end + else + if legend_display + plot!( + list_data_x[i][j], + list_data_y[i][j], + label="", + width=line_width, + linestyle=list_style[j], + color=list_color[j], + legend=position_legend, + ) + else + plot!( + list_data_x[i][j], + list_data_y[i][j], + label="", + width=line_width, + linestyle=list_style[j], + color=list_color[j], + ) + end + end + if xscale == :log + indices = + round.( + Int, + 10 .^ (range( + log10(1), + log10(length(list_data_x[i][j])), + length=number_markers_per_line, + )), + ) + scatter!( + list_data_x[i][j][indices], + list_data_y[i][j][indices], + markershape=list_markers[j], + markercolor=list_color[j], + markersize=marker_size, + markeralpha=transparency_markers, + label=list_label[j], + legend=position_legend, + ) + else + scatter!( + view( + list_data_x[i][j], + 1:length(list_data_x[i][j])÷number_markers_per_line:length( + list_data_x[i][j], + ), + ), + view( + list_data_y[i][j], + 1:length(list_data_y[i][j])÷number_markers_per_line:length( + list_data_y[i][j], + ), + ), + markershape=list_markers[j], + markercolor=list_color[j], + markersize=marker_size, + markeralpha=transparency_markers, + label=list_label[j], + legend=position_legend, + ) + end + end + push!(list_plots, plt) + end + fp = plot(list_plots..., layout=length(list_plots)) + plot!(size=(600, 400)) + if filename !== nothing + savefig(fp, filename) + end + return fp +end + +# Recipe for plotting markers in plot_trajectories +@recipe function f(::Type{Val{:samplemarkers}}, x, y, z; n_markers=10, log=false) + n = length(y) + + # Choose datapoints for markers + if log + xmin = log10(x[1]) + xmax = log10(x[end]) + thresholds = collect(xmin:(xmax-xmin)/(n_markers-1):xmax) + indices = [argmin(i -> abs(t - log10(x[i])), eachindex(x)) for t in thresholds] + else + indices = 1:Int(ceil(length(x) / n_markers)):n + end + sx, sy = x[indices], y[indices] + + # add an empty series with the correct type for legend markers + @series begin + seriestype := :path + markershape --> :auto + x := [] + y := [] + end + # add a series for the line + @series begin + primary := false # no legend entry + markershape := :none # ensure no markers + seriestype := :path + seriescolor := get(plotattributes, :seriescolor, :auto) + x := x + y := y + end + # return a series for the sampled markers + primary := false + seriestype := :scatter + markershape --> :auto + x := sx + y := sy + z_order := 1 +end + +function plot_trajectories( + data, + label; + filename=nothing, + xscalelog=false, + yscalelog=true, + legend_position=:topright, + lstyle=fill(:solid, length(data)), + marker_shapes=nothing, + n_markers=10, + reduce_size=false, + primal_offset=1e-8, + line_width=1.3, + empty_marker=false, + extra_plot=false, + extra_plot_label="", +) + # theme(:dark) + # theme(:vibrant) + Plots.gr() + + x = [] + y = [] + offset = 2 + + function sub_plot(idx_x, idx_y; legend=false, xlabel="", ylabel="", y_offset=0) + + fig = nothing + + for (i, trajectory) in enumerate(data) + + l = length(trajectory) + if reduce_size && l > 1000 + indices = Int.(round.(collect(1:l/1000:l))) + trajectory = trajectory[indices] + end + + x = [trajectory[j][idx_x] for j in offset:length(trajectory)] + y = [trajectory[j][idx_y] + y_offset for j in offset:length(trajectory)] + + if marker_shapes !== nothing && n_markers >= 2 + marker_args = Dict( + :st => :samplemarkers, + :n_markers => n_markers, + :shape => marker_shapes[i], + :log => xscalelog, + :markercolor => empty_marker ? :white : :match, + :markerstrokecolor => empty_marker ? i : :match, + ) + else + marker_args = Dict() + end + + if i == 1 + fig = plot( + x, + y, + label=label[i], + xaxis=xscalelog ? :log : :identity, + yaxis=yscalelog ? :log : :identity, + xlabel=xlabel, + ylabel=ylabel, + legend=legend, + yguidefontsize=8, + xguidefontsize=8, + legendfontsize=8, + width=line_width, + linestyle=lstyle[i]; + marker_args..., + ) + else + plot!(x, y, label=label[i], width=line_width, linestyle=lstyle[i]; marker_args...) + end + end + return fig + end + + pit = sub_plot(1, 2; legend=legend_position, ylabel="Primal", y_offset=primal_offset) + pti = sub_plot(5, 2; y_offset=primal_offset) + dit = sub_plot(1, 4; xlabel="Iterations", ylabel="FW gap") + dti = sub_plot(5, 4; xlabel="Time (s)") + + if extra_plot + iit = sub_plot(1, 6; ylabel=extra_plot_label) + iti = sub_plot(5, 6) + fp = plot(pit, pti, iit, iti, dit, dti, layout=(3, 2)) # layout = @layout([A{0.01h}; [B C; D E]])) + plot!(size=(600, 600)) + else + fp = plot(pit, pti, dit, dti, layout=(2, 2)) # layout = @layout([A{0.01h}; [B C; D E]])) + plot!(size=(600, 400)) + end + if filename !== nothing + savefig(fp, filename) + end + return fp +end + +function plot_sparsity( + data, + label; + filename=nothing, + xscalelog=false, + legend_position=:topright, + yscalelog=true, + lstyle=fill(:solid, length(data)), + marker_shapes=nothing, + n_markers=10, + empty_marker=false, + reduce_size=false, +) + Plots.gr() + + xscale = xscalelog ? :log : :identity + yscale = yscalelog ? :log : :identity + offset = 2 + + function subplot(idx_x, idx_y, ylabel) + + fig = nothing + for (i, trajectory) in enumerate(data) + + l = length(trajectory) + if reduce_size && l > 1000 + indices = Int.(round.(collect(1:l/1000:l))) + trajectory = trajectory[indices] + end + + + x = [trajectory[j][idx_x] for j in offset:length(trajectory)] + y = [trajectory[j][idx_y] for j in offset:length(trajectory)] + if marker_shapes !== nothing && n_markers >= 2 + marker_args = Dict( + :st => :samplemarkers, + :n_markers => n_markers, + :shape => marker_shapes[i], + :log => xscalelog, + :startmark => 5 + 20 * (i - 1), + :markercolor => empty_marker ? :white : :match, + :markerstrokecolor => empty_marker ? i : :match, + ) + else + marker_args = Dict() + end + if i == 1 + fig = plot( + x, + y; + label=label[i], + xaxis=xscale, + yaxis=yscale, + ylabel=ylabel, + legend=legend_position, + yguidefontsize=8, + xguidefontsize=8, + legendfontsize=8, + linestyle=lstyle[i], + marker_args..., + ) + else + plot!(x, y; label=label[i], linestyle=lstyle[i], marker_args...) + end + end + + return fig + end + + ps = subplot(6, 2, "Primal") + ds = subplot(6, 4, "FW gap") + + fp = plot(ps, ds, layout=(1, 2)) # layout = @layout([A{0.01h}; [B C; D E]])) + plot!(size=(600, 200)) + if filename !== nothing + savefig(fp, filename) + end + return fp +end diff --git a/previews/PR539/fw_vs_afw.PNG b/previews/PR539/fw_vs_afw.PNG new file mode 100644 index 0000000000000000000000000000000000000000..d14e903a5e82ace0a3a9e2ba0dde9899dd8c29a9 GIT binary patch literal 54399 zcmX`SbzD^6_dTqlI0y(cl+p~{f`rnY(%sVC-6A<4AuZh@osxqL1IW;w(jY0_2+!sH z`Tm|icnt${&z!sKtiATSFl9w)>=(o@9zA-5Eh{6T`smSrn}N`Qzr;*#m;o=3 zT~(#U9#syJZUb+gT8b)&K6+FWi+OAO40w;>B%|Z{=n=&2;pg$91%=n6M-%w65~Au} zhI^UMy%IIf??t;mNB(Vba1ETl=xE)k{M$l^`;1u|7hH%j21cSsLS-DOaxWfHg)CA{ z#D$#3iGiq|LS$s9+b@Jp{&oBrB9j#pvxxuZeZb$G{l}Za#Swxu+iY99Sa5|GqtQTM z640+Qz>C6HsQ&+clYrK6sD{Y@zkl&aMLPYz4Bd{p~qVCs#(avO?ek*w?diE^v@Lkx|&?sp%)uZ9rc_RRgY zoL{V}N%ap%lxI!qhnjEQTZn_iRKZc)R>m;i*Yn$|Cc?kbwhTosLh`<$mTFReGoPBz zCwAN<9xuHsUXWK!ytjCEUnNgt0+nn+T2xc&`x;=x3&~Y4_X}ho+V;7tN&&1d>#AIC z25sG8!JA?6R()d#t2lUN!qTl9*^KXt*~3`l)dF!$VXEf(m!B2U6Y zDPCqm0&uLx$h7%uq{lX~xU$(}6$}JT(}^^5r&AV{tqQ?MP*{uVU1nqG?{{ujBh&gE zPtV4%QG+YbX(Mn{9A5p#!a;97VDw!galoGhqoz}i4w7YP;?JLV+a~WRKV|Lz_~)Dh zWC)qX=Z`AlFdm4fQjPVY*A&S{tj{eYRGFQ1IDF_1#Jrk z-qbtP{d@=ZwcZ<=%IPlB6mjyftdq2V#4EN zz|rqgmm|sT!$OIpIwha)t}Kp)#LAlES9AleKFq?w_s2Q=SpH|v2p1kw#CGd! zG7PU{>@2K6ZYnUR-(Mc){x&J~Pi4fE*M{vL|MpLm4O4rPZ(4$jBZ<>VZm>@jgI?uW zUj_0m4yr!}EjJ71B%7e=leidXF%>DKyWV-TaiVd{JkP$@)G!vDG+TX4aQ&LV55>84 zey0qiaeXwL%>bsspOnfyh1=?~q-8Sugto|=sixvnpvFxo=gReWT*;6s^}qh&*uvD3 z8N2e+wF%0wf(9VJts$Dy(s}UF z9>FENt=<>k-tJs#$pY14KX*(-E~k3@1IooxxC;55F>FlKfa9J?*0p;42~#IamSYKH zv98zmU`rg`Ab5-YEuw~Gojb{q5s(w-Y84#~HUQQSGN8$F4~Y z>+$o{l3x7baBJ5t=dn9!eJ_-!+H|n}?Z4+P#*;o{2o~#wqoNEi+U8r` z<2==&mW~u=t|2JbiVzs@YvkAsLcr9D&Wltfj}-T zX^Qfu30}txxGZTtIUy0Ch6<`k1`+$sRAbcsVtUnIM_(JDKPCji!a{D1=5v@JL6_Ip z#|E&{H?4wvlV-1H{v>L1D!~|QZtEZo#&vJ4UOu}@_yaGFI3YVm>f~XA4Yjnw$pw9u z?`{sH!(Wn(l&aCY{att+5D;+7O!Ff+jH&tv-jiRm^XBd~EaJ`5S!6J}Een%YZfUN& zHLxb^Uyao$lyIEiWAB%VK=-vyoyF0xoWt|8y%7QQP5Vq<2^iU5IjpZS8hHr0knf+9 ze2-GXd^xc{m&L4SC)M+EQ6XYU-+z8i?)B-}pO<9h8kPLBy|IGluLJ}IHztwp*Qc@> zLOht{H%6a&;rA=`H@xrmolE+vl2V$cx78{S-w8Y+_q~4^8+@>G3UgNo$ZT_HXQ*QW zXW!oXE%+X^3&1^9D%1Ot+kG#1u3D2)AS8L$jJJ=4VwQIhYu{>GyJci?NLE3~}5-^W7dx;LTvDP$lm>F3E;PEPv42{kFsb`8{| zq{&@^mD{jLBmXl3oRJ<8R(9_`dBYzacL(=(vC_D(!4Y%n5e?WMIX|QIIy$!&Uk_v zSW_cPyZ7;{wr$Qd-y)r67uvtA2XLv5PdHA~1~?xFQaN7nd)T#h^n4-z!qJu8nHn1y z#F2d~uM;@4KHVojPt?BH`(-bhqw6k&Lp(5wgW8A5mpc7+?%Yr13s7yyzUO6*oUHJV zy+8&UC+J9OWeST)ZMV-JP!LTXOVm?fLRLw{6-; zbMd4@bMYon#pLJw@uFq%bn588B;U(~FyE^~%cQejg#ZIz_!mCq$ipdB60~A+oRydu zoaJx1Ya9W_k0LLNcjAB7SPc>HdANQahd+%gRT33_OdfE#k{xhJ#^ImqH&t$*|}=|ljZB>cYs{I$@ENK+0*IzGtbO*89Mu| z)|k&o+z4+_n7YREmz1hj+pm!lBQEj9`Q6c0Pe(%L0+1uxeG)Lbe~=k!ihUoIA6K72v&xEycobGxYzM(MwV zsjVHi+@GNY7yF#5*t04YZt5;A=h#(4^d1=uVSL!Wd&TFu7xBD>O$49YHD$kdSs1$~ zz{5@l`@V|2x2!+Gx-;U-7c=2Y9HGlc8mMXJj^~6W^9i`c#l~rkR=7*@NxUVe=gF@| zrjbVjmr(VP}Ir6Skf| zjJi4h<}l^Ki<&!-n*B1z8g@nqW{cpb7_!#o!tT+M4|=faJAs$v0|uppDsQtpJK(La z{dc3B^5D2e9a;9Xtm{V#2?W@y^IrwYB!5 zgT}z}R8=h~jrb0OKM4C{&SQRcJZ-Lo_Q$jkwVXb?mbT8YPF#(BnxtOVFHEMYNSBmG9(}r=-1>Ff+<3av| zk2(_DrS?lDs5CJKWXD>m#l+m+1wqE2NjPc{#YEV#HA0%6L%_FD>T^O@sc$m!FuvB`Iy*O)H`}# z#n9B}?)8mWq|?_@F+*KCxipZYLgZmINzm2FY5@)~mrADNa{a690 z%Kn|DT9jDEndLeh$KbBFwqDu9J+;Dk6eqH1tI{gU)NeWf$Y0tI;1vl|Dz;kxTsV&; z#(;Rzqu)vx6E3*HNDpPgj0Lq+BIlamTAn7&88p=p+XRb#6%&(BcmJ-$_{B29_O~Mc z)IN=ZuY#76WbDvLwvy+2mGe|nIz1a=@mH9Pzk}#^Fpu1KFN;Lp$TJc5#GR3znpf_X zs6tiHH1kw1lX6AN`92@m0G@1+t%GKuiipWGb)@^{2-o8-uXwtSsCicwAbRduYNp>aTF7)B`!19mImyv5*=4f!mWR;0i4a zSIH)D5t>n9-Mc=S|`G$}t zIFE++3ocAwm+4yi!UImB0aZ4=Wv*><%W{%=isDD+c_9tD;? zBeHZwL915Z+tJPZ01T6es@6SPxWKPC{&tM3^V72%pdON}%0TqQn9jCW5xZq#*bPCn z{fQr0>GNbCS{zI}E>7lR)tVZF#Df>xAv#SGLfPIt+v?{z zA>(+cv@Em;49KdPk+$;3_cvmjKQe?Pxdpa%Yp*ILOpN08iG6>WZ7`Zd;sRj}(}4=m zJWb_KVRs1K!<5a}L&4+ZYPQVOQvN|sC;tGp2Ci^^TF1$fnqx)GQS2!Xu7o7xuSl_& z80h40*?4hMsab zkfWWzQwUhuBFc#mwYNw%!hPV`=21Zf|IsLw!SdXFmR-!KMb~?OwM7k6Au!!)k<9UQY!<3ro(8}Z>GirHYCIWfz7E0f#WI>D@%^iimqMJKQ0t4W zv!uwWt4Mm%NzdMRz-Q%*2-vmQZ6AF)y8_2VU4Pa;PTM3*kjuB{@jLFTKqiMYNWN1siWp~D z@7e0dd1X`Z{q`zG0?HxAT{n?oXSLOg^0Wu4;9S8ZG$Zxx^LJix>}kCW$eYs@k~08C zF&zCfH@s)ve@+|Uv&GzwrN+Y?b4&)bwoP&~Vj*~wlf3(wjtg%RNmNC6BBFrIZ6E4T zg?{CF_ROlQ>pP#})q_cSV27t}IaBqj4D9S(KNTX6q;ACgH(m!f#f`Jm#?Omk5E=|I z4-{!)KiE?b=0u%H&~YHNeAMgyEAsv;nTm~hd6`5W&wAlNSXv^*GJm5ukPc&XV8zR; z$IM#ClKrPU<_roLr$QBNnnvnK$?>j0fYK7zp49}nugD_Al)uP>B`PG}js9?qK3-A} zxfJG%%d9AIfk~KfUe8HrrsXl~bb8taKNw;Vno+x=rNADn+o}oRz<(E7lq2j>KnaGZ zjqIXwnO{9OxC2e$nE~h<*lm=P|30>QQG3*nr7xC2*D(4yo)KxNb!@e4Emu&qj=s)E zt_lnpz-MzT2#gnF3f!k$pWo-;2VjKj@ay;$-`nY-U(3+!gL&BVtOz|JE&rBTh z`gMTP4=aZ~R547jqQlE_aX8bbgM|VB*)~Kv0_Lg%*j5JUmci7FDeFUZBqUf_@_&v` zbb^iMreE2={mh`x1wM|Oj~jSl0H^vYGazQPZ7*Y@8Gb_6{}5o>dLg^af>%+0NSB%k z^8Jki?i6ms0FRNI*>~>=Rd7WsKU75yu*3SbySR7cXXEd?%&aeUsBaLMM8tDMzz)Vo zwKBP_N||;C)E){VkX&a3(uqV0yj!+xCz1~|Mk;9r94<18?aYV*|pwirIK5YTEiCN?BML{Kd#KTa;}D|LKPBCB5!u z#g8U`W6GsCZL-MOZf*jWFkXWB?YtQyZG#xy4MR#W5x~c72wprnO)9?pZz0-pTEy7~ ze-cr@eB>*cW&Wbks_d05RUX^MXkr6a%*qvS*gGF;2uanIiNh(_k8m@LDrk4K*YmyM znafXCddsyAdW+SKam>T1Z?uDkj$ZtE>AeECe=f1y1i4cxgb(#Xl|E;3Fq#k%_GbKS z+!Z|>XbRc-tiGTx@Qo`2Lqhh>K+AF&Zx#WU7!miKPr;6d#It#rVN1 z;gP3$$UBVV&Y<1H$UjiRf#*-lJL@rTYG|n*1y{g+CwZl3n5 z0NrytFYXyrs$6C9dF$G^pEk(K`335LSADM(=l?s^SrKRE4(N{;!&=lCk?G-2j$!o- zEKP3e;3nH|BZcKWuqAh`;cChZ{WN9?%7TyNYN=serGI7>R>zgKJl3}Ua!{Cx=_mf& z4_(f%-IJoK5m=Wnll|X~7Jw|DWHjqv5%aiJM7>pw;Kfe5RjD=6D5sao{5`-qQ{~Ir z<3;Pi*6jD%Qw#9bQp)cvnRU<6mP&pT|zSIMvO+ZO``t~uUu z?ma=nBul#B+a27p?fm$79U`0+nH}$f#Eqk>TK1C0xSe0oqOCXES1kQXv|L}W`f3~7 zqP68B0OX{=LWMZv9z}m_xZUN6zvZtp*ZABbAD2FT?)=fDi}X6J@f871vR4kD9TR=7 zDufBIe!547$^Lx?aqhzOOHR?n{&@^nHu9ct1N~_qXka0QAx-~>C3~q_GO{YZKXwFw z-~11fJphd-|rvNDo%x- zTN%k5?b#^`*g6y>e2{yiT*UvKvha7$TU6M1aBtHHYx(+Sdc^NN{Q9=W$iPq}DHiwY z@7a&pQ^4Fyu3jUA#NjV{Z83+f7zf zT)am%a(Q9HStx}soDAynZ2R>C;zrIg-c|609T$%Ob}G@7`!~_yFa4z=p7vJJzw>#Z z-T9T{|wtbNioDAtIYhP-{@q0+%~`!L=7`d&J7uV|8|-tM=iv zhS-CF35Cc;%H3zl9R-D;I~Yn>qfRUX#U$p6cj&)vIF-SWeK$zo-WE66m4HoTo>a1O zV&hDAUtU0qH6-cCAhvKjM)$BKTflg1{mLd*k!W3CUW?c;8P&&NlVBYg^owP1w#ipz znABK%9ZK!VU?s;WTZkai6+=t=5}sZqp7?6t#|b>tPT z*s~nRyzAz4Gz*trSnGJ3ZdassZ$1eh`gW1<6X&{mt=L&;B5kpqTv9o^9oT=HY0G5^ z7>FV~Km3QCh{2W91Po8wejMx0{_@ma9(bKo{)Jt4IG%P6Z*?Lki3N4JvedO}wuE7EH2=2JxnLcl_jBX_R6X%cxy6 z<397g^qBG!|9y}W#WG#b)C@baR1l{v!OKp|VlZX1CO0?|0EVxO!u;d0eh;XAGt#NO zQr%nT=1~iT9&QSS!|mcN^hP6b>HjcA?&2?XD6h6TP7&xpEorfYcd5&*vlZj}Fb&28 zuH_sh^S@1_(E#C;%8bC~{>;wQv7X@9d(K6;3Y{fV)ihI5Wk~0dGAv!+WoqrPm$uOn zVphrJ`|zC=tB>2!#MU>6T;DBpNi;=R_iCnoy7&PAkpdRdVy=Sajt~qk^II&hJkIzr z&}ZdO#TM^R)$Uj_l}`MkuVely4Tpa_aRwcjLqI6fqD8SQ!&RZ{+m>&)m|rsM4xW-z zG9ok(4~uPxr<@Q!0EHMIpyOlKJX9c{3dbYfm5&ZyU-K6dh6PIHp`X5Sd$U36s+Ie3 zKNH;LkQ1N2b>==o@Ws+(0sjF)6-7FA15iscK@Ap78N*p&ot#J=n0%O)jy7ar}o;0Ae(%$O4&eBf1X`8tNJVe&KM0$?TQ zkm}${X2X&;!Z3y^7*E8v5#^|t?#lDeLICG|Bup1Bp4<5@Tt=2#S$13vUIV8BXHNWZ-YE3LusQ8^%oOW8}q57Q-Mj+ zM5K9DTXM&uHKrVi-()zo&#hKJe?Y&CP<^9K3zwb&8VHLXx>T3nR$!+l_iEyXP@GE) z_xSiz`7{+uFbOe80`^8O;ww%om+%{>lMq|TP1E}a^sXk+RO!X$c9qT0A>wRXwUu3U z>!@uIG5(dPy|eVSWk7wa-J=OgH}OJ}U49hyxmyn{d>+n$<-6rGZ(;k8-SWT&w#~Or zY9^|=ZN_qmA(+X5vq0}G@j_>Pw7`ToO-j6rX6`e@B=J@L({Cr-MzaZpKYav`(M7dZ ze|b7cKF|xYA-nzhz(_XSeIV+?KVoNFkn=HP;Q)wx?E%=lCQ$XWC4;P~v){>9zhxt= zA6%Our)*UTZkQwhz%#IkzI}-%`1KPvongifS7w1Px<6~Hg{C|da-EOO+~o>wYm23C zMn2LUzYZLq|C;Hy$cDKuDdIT5NuYv=eU65&ZhK zjM@JYn<`5`Evjm0|KqIV&TH!flflIZCYjEW9PEJ#76JCJ2aQTte?5Mu2^=K?fdH&= zo%Sw^V0_Bi-;`>R@CLC7i2UvoX(@l(F^6~g6J z=%t?H5%$~Ma8zk7;o9Wa~Jb+4*Oj*@JtCqnr#z-L_r`na)Cd za~h|d>|_fWb#(mdFpdd26~sNRuPTtu9)`Sh93u3TiQH8EWrIfn`ws8I0d}lq?=PUe zG5#-A{K1L|F|&-tLt!|{#fpy=EnwaQ97GeyR`m^=IcU?l_Xjm23oTj zL1VtqV_+tC?zFf&_!mgjP9^B=zH|VeN24?`=Fx8zt(gRN!N>iTUa-XO~h4B_Hx_zm5QgPfmBY?}I@HC+u+3jyT-Fo8NqdB@~zbLVi_+ zC&Mx{MdJS;>RNIQtLs_gj88Kjcl(E$)S3UBT+C%?JQdP zQx^D=vm^KBK?ll{7IKm!Tgs*4Ej1yUIL%XU)1c+key7EVm|VVXev1xXtfE+|G1_V> zz1ZHklpg*-Si)3D}Ehl(3j>iZdF_Yj7DcNO)HsH+A*{d*=V$^*-tX{%`eT!}G!F80rZ zShBSTYD%W2n;SXBxm7PVTIVF*fh((=!`LqDw_ap8zQ?Hd1S_hImasVi*w9Rq0o+V3 zb%O}JJ2`*YhWt~r-WqbWTF(0EnrSIde1ksKzwFHRiy|^keSF+ zH02-k)P45$?VLCRu&de9r2&f%yb6Wt~sM1NG#fB))w?Cka}WOBqP7`|+g02#qaXX;_> z1K|)BuG!Ru3f)>vgGS&6VH=dK@?(VOn~aMhA!>QFjuFtF>7!vA%pi#-NI{trGw%n} zxG_;9A&i!>%k0{fb2`MfS3FDDmi44M=6hf#$(s={oFLu2qiS;hLSDD`Rn zHw3csBc}t)zcVpAq*)MlSUbnWLlEtkQA)T#3e*R?8-DxvnOCSOm9EVmTezR}JQv|g zNTnB#Td2`dl7#>FTy`={gKh<5wsH^-#$)uC>zLy?EBuL%V_7+uDu5Yv$L|PV7!tpP z)W+@?p`@$b4@{D-9%#mhO`fD3xH6|IBX>cdOFOQS2%M#9_z8fXHL9OBcRKVQ#@n?a z010SM`J?u!_>*bV>rk}vBISNAfbhD0XhuTe02}bNBxdM&%dMnv64{(MT}D`mpJxDj z7`nZP;oGyNqL28ij_^KSns^=&T~kAV|61?ZBwTx5F`5XXck6b|VZM#8st@vk>U%!E z{yvb+NjaFOq!!}!j=#44Ihg!w3NnN7oTlNoW_ZZES)$E#8Gt-AFHwJrT#qn#1#Xia zUyDnJtc1XMvZ4j2rWbbO9G@4<>& z{hlHz7rDpxvn^^2Fbw4|{+o^w0y1vVh$RUtu;M~fr*Ko!Wju@KnB-J;a*?Bv4mDd1 zDc5G!AavAEO~RO44NAcs!|IO!5GnM6-fbfr5jo#7)MN7Q8yx59?@0U zRyrY$3LvwypedK!S8skgxiN+|Ayt*T=mfcJoU4cTCEn%sQ*@SB&`gOM5mo7{jQr_% zV$hkT2Tbp58jtyB2DEs=h9P)Hevb?{#K{#mjc8sV~N&^f}?cu z>uKU2c!0(25;{4$Gq66%m1xBvMyK~QLcEkDos8@#kvh1J>g*MgU`6&Py{ULx2OY#Z zN!@6utzPU5`(PULQDD5PIeQ8^wWroSyad>qIb z4uPLfUB6I>aIzUI*Se9e6gwry=x-nLEJu4!D@VmvL!(Y|2Vau2$S$ST1%_Dj2u>n6 zHQV%&$w$Kc})KXE)iP=Ghnog02YBIH~x`N%dx$%>8 zO*fYoa20cmSjxB_?ERc4CN8o6i&IHQM&51$IlC&2%FT2Hpe)1i^rYm%zlrZU44Yon ze4kT~{!j{vN?J0w!NXtpCh}t286HOFOwz{YjNI7FOcLTCVBOszV3M!16{*O?D+!+k z0XMu8N6()FAnR(G;FwYw;8xK43Y!OPJ$y~xEP+YXB;JW8hqlCb`_a}AU$aO?bmSv1 zw^4&N-YMY02qy{((!+%yPrqc&AIy4Cz{g|i6B=uEZ+Lk`bufptiz1vpXH>g2A26q> zF5FQVOEet|p!;{%gh?kyk3@p#DHMs71h`#{%2+}3V*XTr*O9!m@jPPEDO}oen1-uB zFWJsU(Xv-LGA(gJ25T76qEHDK!lpOlkz$7W0mQA;es=JaVW2T@1h6rQ;~_SzAbO%syNcs!FEBmb#|Ld1Nu=$uLN_CT0Ba;`X%pSMSKulD{lLXfl>MZZEW!2VJX9CF z`pldlLbm_&pF-Oia#C1Qaqydy9D4X%0De9X#m}GI{G*n$nx`Hvox3m7k5GtcFZWTY zwi>Uui@LSX4ytCtVy6!}n^>P84OXtD9t5E84u_Z+X>&bUg?x?643D(=c4mip>O)Zu zIx5ssJR+-kqZP8dTkD0VL<-d5pkL4hhM)4gyt8T|WSk-F6P;E@GtG58AzsZ8-?ciI z6^itTc4MNNA^xW)F&Uj^w3=!I%U&uO%mI?4;`%&%r)eF~Bp!1gsr{v^qD!;xo%|i9TOMpTs@|EWr|7uPe zh(78~```1kplGm0NEFLY*fsYm6ys=bRrS)a`K4vHvfqzCG(x)Vc=zee#Own)Q8=0o zy+rd1I!;BD?ewQmMdmz#OI=R3BC~4BtPH(R^`D_;gh`b7)lW;WLS;~lBKlG z%R*p+@O{y*+PR>s*UtqwrZy-S4Ob)YZ<`?O>`oSWiz}%VFSA-hqDsH*p;K{S^Ihed zdV}{X1_)L{a$&{Ukm?QG>_)MK-O~o__Id?TbufHutVZvdm;dqc<@247C~iq^tRnAYOqaEENYI->Vqw2nNJ9}(TgzpT{poeEMrd!P;uYYe=cD<6sXMg|tlQ@{;gMNzo+-7OIVKDvz z<5ufscGrck632>To9J!zFxpL5zOx{Ic3^k`*jyxKC;l#K4cMAL0;0DP~P7!Xgmt0MJ{OiQMoCK6*qP85= zYslDfPrx?__ED~F<^?KDngQo=t9V|j2t|uAyZoW@@y3b$-qShd9PDopGhavv zw`8o;!qO$!%o}5+42@sE1ecC)YZHdmGACvhQ!AquM|#7PoBzvaO<&6>Is^c*EpWcM?TkZddbU-;dM}(&iWCAw!H%BU zA{XAfM@9LVQ3*6nRRxxH+Dy>xXWj2!6NEqeE3}s-aY2VdseRr`gWLekE0xec#N!WG z^F@*KdTM}nU>9IK{E4n3*ZidY?bs05$sf5&huSE}sp3KO{1nHJ@2OP1b4DUM1%W|7 zdt+&1Ec-YKsSnU%fSNV5YCxO@{MSPe7ocM(J5b2lKIgSh<2xx9 zuR||)t4^>n#m=V61cP<@dZQu_=^iVJWjt-xWUMSPYgkXLIVcp6Y1^#Ez>K|y-dppy1b+QFPt-`gzT{PvPCCFeto#6m#)nDX5m3aoq)fsaYus1{ zrLavAu?5xh(9=3lYgXj;jo^s;kS>-%M>x-bkEns5>gUNA8mm zZ;2;x``1+-lAT#40OLFHlyS^!xf=Udk`hMFPg@q?sNrgNXBB*K0Km8UmJEEi3TXMm zni%OSCv_fbY@A%fUZ4$Mpx!F(@hrx>D|gT<#v8UqK$KaErS5RF4nE=#s~h4$vQ2*6 zcNB@y->WA>#kTGB0HDO2maAWPDQ95EggBctM&ZfeY+w|)4}$X|oWfJr2BgQ66W&xj z7F-uTRo=BhCb(kih+`+&j(lC5`UzUE?^4Bfan4PLV7OerR}NP3{W}0OS}|E!QMdq{ z^_<9Mg=T!LVRC$AB>O?Midl2j7no%0I?mF623_>EA;{^}P`b`z?#rJxVqeWa`ps0z z)jd6Mr7KC0RGyrsFH;hhWGjf0^6k}k_YzhF^-034?S+d9@e&7~%@7MGwXcIYk0TG#Q!VseceN~k>_7ajk~ZaJ zvsW?$eU@}j+z#^Tly>a%AOq*<*ml0tmaorg!;i@3$2Gx<5s)Q&dPKke+(Od#Mv!L* zxG#pmm8n7Re(DvIWUevJ54=?!$wF-pra11UFY_)DvoEHm`hG5us+-DWHLTZ)Wo@i0 z8I}tCtfy~#%f9Ab)m_m~r~61g!U?tw$Ogny{yjNuX~a&RM-2tm-7x{*%UbDJ2xaGpT7x~s#53=qCU075M8b@Is zhC!B;EcI9U8@nM;eSAA8fJELCz9#uz1i~3q`1qKwbmES)1K_u81Tq?jm3P~>QrVeB zzox!4@9pdN$eRZfmh)y{m_KQ6ccR=Ny}o3z{L9!V73nme*H2>AxM8POLW^K*mBvV3 zvsUpd##UE&~kdkUIrzugUSJahr;bn@$nxo3Fu zI7hk|HrQbl3%0EPVW=lNtM6lw&vJ;HCK_7}i`j;x;kKE(46RV82V2iJ*8{`JG1)Vv zsTwl>l5nYv{ZM1Rx&cJ*J1hIgW3?Ca`DM&Aon}Z0q_~{=M*)_9Pfy+D-Jd|B`hF=N zTk%3cGgXnna+;p`U|T}|qf>(+^dGY?7!iXaMg&iRCf=w48;}8^7Dr1~&$NaQ$!-E@<5r6_+g8Bk(ppj`>-;x@FL4Zi=JFZ6ENFlaYNEjVyxS(Oz5GTD`v^yP zfe&bgw+q$@YQd=W&Rwv7(!m^sTiygPSYCY1;n&;pKoABI|+(?USA*d*j7cwGLXld%k5K7?f5&7GzZzfErygTNHAg*jz4{Hres zX9V7{^VBs9;8ndR)xT@T(H zrvh__#6NF|nq9r^T@khz51S!`3gqX-wMXm?VubEI>9dHlnXvlx325vbe78X3MxG@tW-i)wocifa)M4JF(Pyp*U-mNvAxhu4#4>6z93(f8;hZOQ8xl&U}l zm$Sly+)DxAMfJD2E#;XT(3O9*K3nR*$NUu(Y|?d}BcnMqMfgSRHc9I;3`sZgbVrNG z9=RuOxQ9Psm|9>}>OCrbiK_i?7x*jdXo`j@h1};HsdUgI^!|WxuBz)wdi$V|ru1|w zJVl}k+QuMs8!X+{DD&=g+k#2rFsZ>%&DZuop7PWrgNmnLaX;(DFFGP4pcMZ3C!06o zh$mh{J@PBbMV-`NlB;C?^NVwIF|h*w+zQ5ua+BZ$pZ6`xCUWRYlROh8R{#NBHlY2V zCXE)cCSRNSDu<(7H=MJWS@C(zCj8U8T`p;5&OesIZxf5mW~AFjo}RWEY`h)__@QoM zhO;O8qWjaQ2EyzT#)sX6fr??Nz`5KbMAF1lFB33NkLhFB(vwkPmFBEhw={S(DqSn3 zkKJavI(v}J65MB^y8B9Mo?SxKdKXoY2Iv8js>49MLKR;v%crP@t-oX5PMpO}W^(V$ z6Uk9I=nc^qau^*oOSkRkm4>%n66y1yw30<1e1Q#C9Dh@6Ff*+61(ST|E|P-M-BEJrbWj5cLT<_YJbjvk2UvN+l0t4gH_q>kg1plufeE zLTdAUoELreK#hZ45^EL;j7WP-GNX8cS>OKOPJ*rbv)tUdkZMo=WF5D-2gNFK40;O) zZZ-{ACfdTctm zpA-$|2$!Z_nKJCjEUAjc#1uSVHKJ^|(=}zLD}^!ZCsbTq?YNA^a)s`}zy%;BwtjQz z6?F#&()k}~qN0AzzKRB4Ob?uE8|t`$3o!@Ja(r9IF#;7*iW8?bb?Pbpvnp_Ua_xYK za}+{|Pp!6wnpneUKt9}YV*37DE4%LDgW4{fKiPIbtU(WVqY7=4(h3JeX?C3LRT@v9 z|Im&Hgt2M+hd|d*$E<x|vg{wN~_NOO(=rP&8D0fg5 z%RBZLgchJd)B59a zn3SX6itgoeEGaHy_w}UDYr2bpaQUAd{;HtwF*Zyg7ky!aTy)^*!{BqysC;&58*7a3 zmt*P=CyhMp5DDRLfa zIZTWmD0d^~{^mU3N?&%FU$^)r41;aUe~RSKzzEiVsxk>LH&G@)8Y$vX`2L5RGvzMS zhuC4?jLTO1;!F0uKESv2EmlX_(YQ#&M`ry>&f!7xrB2TGj9?$qO4qUgB&R&qfY$#9 zGx0CHII>>Pr{T2(>S+j!mNX=UMVh(_Aaq~78&OVk*~D6kn@QZ7_;9Mf^`#;R>?d8O zPQ~U;be%E#?2vY~8_H-9jE4R^#U#wBo;lp#U|4AzZ$(77L6m?+@-} zsVWIOr{hCAzAe2pFc;87=g&I`J!vxRqlmyOq`XKVV40*{y^|aN*QA;8r5Le;rQCt;m8<$uB#zA3OfiOW#qV@(f{8A44z-! zQzaXf!{UTl6y$F0cEJjlVrtfrHB$O7oX;YLQKrRom5+)0Qnz-M%e2Uo<%dku4ov(Y zzS!?81fo+O6zq~A&n=9)=Y`}|RLa^%mmFGSs;yzVjMRGVx-Xm?sLD_^Y|oFbcs$ju zO$+exSE{d+KPeql3s41ps1zbfGl|qMn*Dw@8bV-@63ok+dF_t4%x7=jb}M? z9(cb6lMlS1KUQtf5TXlhx}KPrT$%q(e+WA<&(GTMTjM!=g7yF5m8C_jT$ey>Wd7+Uo{aS)C!*7?>YTP>=jog+u0bx%&^+u zGoe|8pzb4LuDo228Pa96-85xV!Y&SK2iJ z98}S(u}>N)4_%$aVpZ2}8lI$VnF(A>rx=Pf2eUr4Y?x5-apE9n{^QZxJpvGo%`V0F z{|yT$Wrhx5wA@M)EdOOTB0ATyg%mOO?2YZEVWz2cN~fZ3l%7Z~jOd#Aku{cZ=s>)OsZf0Tmd4Jj{S3zhGCcSpHsujyX@+?@;U6n~)P3 zdcy@SBLyzXous=UF&xfxL~+|fMh16k_WKXmGt2l5Lt$iJ`0Q9#QLj3x{6w}B#EjKF zh*O)jfivT^v{NO1uz%2m;EtQ#XKo$q@BzB`TW%f;v)8p21<@X)UnJ;MQ<(NF) z``D!%j-;;3a^OMrz%2-(*Sm1&Y+jDd@^g^d#TZtw%aR0=NxEm1W=4_QUCdWp5Yk;w$`LHW-Lz?B`DofJ7a88iMBD6ZwrqxNJ<#in*Cq*=goXgRl{UAS}&0`9C=eeOCrk zRu9^*hg)fI(Lm;*YvIX-!PR<$@WKapc*r=hKb+KqNZkSk*jG+begy9kRKy9thx9=) zf2=nu#`I%Wvb~Dk(U3i-8Bvh_h?t5i?dz4KgYggZG)Xds|)AcWUr_*$PgCAJU3H0X&T~pp2c1Wc$bL zK_rrWDXwNFB=SKc&Z|b$jV4m3cqOz!y8(Z*r3^zoNgxMr0n`i?(aEXcM_3b+SQ-9# zB!hw9fKho*?CZmJ0id6Nx=hSX%l)lKx?aeogLQi3MB2`bID!3NRJQdi(vi9LcI-_H zQIym;7h>~#T9l|B*t{=K3{mk@?Nz8e?!L*}H3(0+Hm4-7>}eL&fVl(bkLZ7JsV8fd zswL4{jN^m#Qm@8M;93PK7$A2+%(eZgz%3g7CZPsWz-E(plHFG1(1<3S#s$hNGf?Od5I$f3RoC1}d4Txn*wQUBYs}(IF)W z6MT_&cDB%_k(CggINbO@_8ioD&i@OO6Ow)?O4}HfmB6q?hnxfTZ`nqN$|+W02yZ{} zwbq%0uUF7Ie;Y&TzE2kTNYse9rr+i_jjNUTA7xCuQC$LA5TMrM>ms#Fz5PsLclcwK zxa=g`lIisUru#)wR`=e~yU~9+0Q$sY4>m@os^+jfPu!5hT~y1F|vS_U)wLC@7 z-f&L)Pum}8v^~8BPbrG64aO;L1r2ctlI@Pn$? zzkU_gOaa0_EQjr!YMKeppR)fQy;1=xSi1nT?{n$zCU;LG;r{1oY{{v~fQsHamcgea zK+5zvX`a|(-F?ImD@u1Xbn};##TBBu1;#ra+ zT2bt}Vyop(Uced>10Z02W1&m^5gjG5T`Mr_Pz=T1U{~WV5P%~8t;~#?LK;fN$7eug z%SAO5KL$aX0WHsB9soVZvFu5ZY|yg|(9#<3=urPIV;2!p2XlQ?`7d^?L-lBA2e{-J9J^|mkzrC#o2YzhfhFw-hSwCbfV~C5AGq4(s zUCGh6W!?*S8eXK{`Ret10zae{KlUqK_n-TLNpmbrf-`tGF2-LW z{~Vo`P6?LQZE6W4;YvF4HI^$7YrLq_w(TJMDiTzHIm$=Ir!*Y+kIO{=n}F0LM3G23 z9{wAh3`Uc8%<3h61~3&fGKR>tBr(|CB+cOs_;6InhRWbdeqxH$VC&JwUUN+vV{_S6$N+_4!k*+YWU6^}d9ROGzx zWY%qcYLMdIjM#Iq;W3YDk3C~2h|*$wbiXce40`>70E=+#U}O3MOi8>kXZwfz>C(># zVr)7%bO(Rk8$%j2iLIajA+7p!37vOsBDf9^J0m&+ctGYV4pJ8wuM5W*146U=u|=#` zh!X?IDE>D8qO>-i|I$5?kG**)yt)yOQ8?Tf5)*t0?_G)>WBns64tTWyEf3JO9J?;2 zTItkPNlHq9 zEL#g0?ss^mLjz*`F43S{?Z-4?3NjGUYcAK62X6I7+w~4iSnIo>^_nY1{FiLz zz+a4a)Y)sJmfQ$Shs~^IF(1PNiJ57WB)Wvn@))4hH35L`ntVW#LJ9n0M9{XT6J`s~BN9@d`-T3jPET;@c>V@o}bVdat`Hbzq^w zKrYiE)MUar>$3Z*>2vRT@qfr1oFyjgi^$R1tWABfg|{Rjj|i0@rj zJ-KSAurUrpH5`=D$IgprS~8u;fiOpOTMS86`0>%_Md5!>f4MsBbnV$ZBI^Hhdn?B* zBehgiIz>vKi;hPgYj?j7d+c=9-%MG!{$=a4_oD@MLBv{^RIaYwTHB7>ekWN3Q8oOU z&u)-roU8G{GWmStB-TScZ1)%&oIMMOhAy6oBhl}$TL?grTVU(z$S|J&+IkPDW0phL z$B4UhZ&te1jj8}F`Mz?IboRYwHN&*snUkUSCnM&SpQi^h^Lw~GM%S@Ck{ZZ`8iMY} zxQ|a`b9Q?fb+_3!v|z5z$lm8(HZ;ShNtO8>%r|4kc<5e&pB7TY%hE-RJ{6T+UsxMa zX+2+^UjSRJbK{M|wg2hTsTYJC6@E-tq#b8TL#3bxY+-R|cV|S0dd!U^N!cNP>jrb* z%1uJjUV|LhZ)NDIJ?pWxK3W6iB@P_#C=EewiITxnhCX|m4j#R`eR`Q$-=3g&f7iD; z{p(`Bh68-u+6HQ~ zCB;6kO)#ZmZjhX6{Pl)jQJaOmakrZM5_ik+U=?2l=Um52m90CM(K(l^16`FtN>-$@ zm;IW|I+u`8Fq5nZ8vOZoFkI7}qhUK$Bqix0XHN5t>+RX+ptc6T6$CT+)xd5~5qomY zXVekHxdoct_Y_)O0!_KgFGE=@NhqP5^GSqJo+KXGoqvciKC_5?vilXBvL5D!Wvzng zn2cU9%t0v>bfY`){vt=0v=Ke?$Lzp%v-73FO0}i5xH|{dDmAM3mntFezaB2Oq!Xw0 zoxzkI`vIy(_-C3yU#&r~;$TVSh<`N3s7zaYi{fl#k6QLrnc6Rbc4X;PhOr2*iN)!+ zRDZF$c6H<-4@KMnR$L~_R{ISdGCKOjT_@uxbX!?H8^i}!#*CxUYFdin;$uoGI#mq? zt6!f>>+39TDc9ftj_&=5?RdXA&*6KbYqBOp)6M~mosFy)S#Au-@%PWAuz0v1yiZ$U z;^Uzx&e_W7gE}f?f%0F1AuWXTxP;>CDfA3?6Kb+Jn~|i3@}Ws1rLAAQp&r-5e+(AA zuTM)Vl)YVIm#Qg0zXNW5oRaB&ny#!Be#C+NMZuBT2n1?2LoiL#s$*FZm-wB z0kRkg48gr=wc&`#`sc|21O<9#;pizO3_@bMbc8WFI@6>)QgAbHa zP5oD66E9LhOWZXp7^ghx1&`)V#RX)Jx2ozx$5O`EKotjzRH>R$0z=;T_~D^4kxRoj zXKm!cn;s+4Q^RrhoPSsknqZSyEDFI1tY)X=PLx{9Wxwsj^@$`sreV zZLM#YA1mPkK_4-(;6aNY#|z%}z=OMSgaF2;z{AY?k1SzO#|b>>dn`6kd|P|=))?haK%<3>`aM3u zkC#j*`Z4|8wxvJ^LCv}vcs*}Yz#`~z-&t~25)0Q!E&<=Nni(14OL8|L*nlo3IF)JG zA(OOjcHr|>>JM#Z{X&0bFtr{TLX?w$KSf)EWYDp}@ zTrSNj9!!ItaM1US5lpOvuH)Pyu<^^aL41PR`B>3VrH}O;#?5w7wZ+6)7BRa+P57Pp zBG*6@Ttob&$dwQAl{j}~Rbe%DXfhb{IAZEk(tN)~h@GzZ2i$U=h>SoNJ1r5=CZ)`6 zmqW}G$&9PYu=bG~CaBn`u?Kt}x+A%aho@@LVEGxYy$*W{GCzthKp6zL0|AQGWOPxd zMUq|^nLyxMy^)7g7Xl>%pQzdnhjX&`7Lj%xeW);)oD|SVqbuwL921I)v#gCrA_}9# zsw1ktA(Pn9$bn=c-5eENg=WHQ2;!!s)GX&$?XMBL3oC+er3DVd?JS1DOXjppA9&vs z2#ES8tX^rt5!q(eH6hI5Z0(Phe>}`UMEUO3fIJhZJ>H*=iOjG8T{KF3OYKXC$>&nr zCeh0CcM*Eq>BvweMx7l`YkR6AJ7O}$4*HS<)Q>lMj>ChiHcHSQG%OJqyFjeU3S)ua zXxXMy0U*~Ib|U%YSHy8V&G6!WSdv+#D6_dO;oy(7wBXr+Mx~C&23nx57G9)RmS{2C zO7uOk+AsyaMM;UMwRkq{8lefct=)(qN>{PrF&BbB?Lrx}4roNdlo)|y-3@G(BIFh! z(5GO3be(ix-Qer3j62JT5qpwdiEZIDcMjOpyt}(S@C5H)r5@*#Pq z9JcTyf4G~O(@p#Ed9uX7cn>=6^O-+K&X0WIstTVsf!x|#>v3uo0?$H z=iNw^42O6vu{**JOUDL--|B=+yLjXqhdi>2ZgAe4a!z%;JEp1(4>GHZ?B%jZxC-^? zoA2drbhuC6SbjejobV>%`Aw_M>H`x-H$9XHP^>S76-HLL24M;6C!?D5Vk6bt2=SM> zXJ{mgr4hS}#E+nfOPcA@jA9-xnDxiY(e717@zW`C`RAwd-`0^XvR6^@jW~fQ*tc=KHbtYl{5h!?$G9`Y;kIJPCW5Ja8+8K6j}Sewg#f`@Wv%}ovh*nG zHIP$4nVNAy#U)%T<{&=1Sz>Qs2TzVylgT(X+aP#K!?2u#a#1=2>-%rfs4whlLX7!d zs4ppw^8`rCGknBW3|*l(RfSdDyYB&VqnXX+FYTxpRnYKs0y#ew4$l<~SQT^j?nfiI zxD5Grmtf~*JLyNUh^pi-$Xe$~ME7v~NOz=P}bFczWEf}(G&5ylILt#7PRU^5oh{&ns@mo9vP zD}PPu(g(Q8-}AtYn{e~8%r`CQ&pQxVDru;7Qk56)5Us`|jFm8$q44K(;E&iXVu;V| zlx+yMml#e2(~-5(me{WUg^d&vCK0p(C{sf-#gd>>tkX^wtT~0^r_6 zy7^GzKK^OfRN}yUMS2^8ETB7(?;f{hBm;y0(p95Ogvfb!3vU zt>krY9L*D9f6uJekmyxAlSJ_KdbD*dv#eZQy4S`@_Wf7q6ssa}Prrh{QOk{4 zl~yt;Wa-&C`b!n?01uxL$oM#TOhmmfDn#!S3}hD%VWP?S>|_?IVQFk2c@(5faVV6z z6iAfX$8W2dFK-&kybK*<^qYq)n9Z~a*1b|r>(PK3hQ{yw?BQ$YrjbxP{Cf^k*``iQ z1X6J~9ecP{sEb&6h2i!1{p*>${iBR~Gqj0#ZzDy|zLd*N_w75fimm318`H$Z@71(P z#_(n0U@N$_I%e++0#VS1yHIU{lA1i(sm=`2)KT^n(G2;1hH`%9h3CKZJQ&`^P&h|v zmS+2JR%pG>VW;Zhwi%=b)_^utuK#&zHQAj4eTm657n+#liz;Q$0v)Q4^H{q&@-5ST zssI(uW|sRhbc%%HdIqFdF<9%*6IQW+KHhcGsYxn$shq%COs0GN4X?D4bR=tSu1Mtg zL6u-((vj#FLk1r0?VfiVNvgClvc}L$bB0|q{-C6s8qVfj2<_xIM;36wp*<?O z?qy};h0ZjcOBi@v>v;?>;K?1jw4~1-fd6Vz%@q?_-;f7b@hf& znAJ%#k;J1kxbFL`B#NXX@H+-(d{OlB@-zUL#X%Ko-RkulE@bHv^D3ukJVv0m8)CPa zdE;hJ;Bv;UBL}iC4uSCUv~TaIOISBHH-k=pGEwt9 zf#nF`#=v(=5IBAfW?YYxfRcq%MhhwrWxb;wBm<$4d}^pph()O-rB_1omwz2 z4YSh~)Zw!3M#BrYXA4u`ihcQdxgshRjK7VYNYCdIg1H}6&K=>~mX40G2oPS%e+Qu} zwEv1e6P;zl!zm$XFyA-)=bx}-zZhg13E2v?q0P_J)JchEJ(b ze4WeH$fWcrLr;qxg{$@EuJB~%LGPMGCkh@Q>}5#Xv%wol+64}&mmTJMtj!bWT`$iR)e_Uj>_b*-&?d0?cccA(2pP(7~R~NhhkI`?%5}HNz|Wk}XvnFEsWHfl_ zh*ji2moau}UU(UCLo}L++v?%AzDvL!T7=v4%4*k}6)0;c231Nn{ZWxm{8j!V7;BeX zg7o?E0^BWeyo%W|h;}lw-tiZ}CG0*wV(M!qC5mx_zNNBZ>Hf%#&>}#W4p3;fdt)<~ zHuh~^EWoh@DYoh&03NdFjz82rmA3zTPSB)Stj^N##A#jF_*+Pv7wOfPon5Up$T$Mg z9uKq7Nb^y#`;?xh4;A*>zxt6s>A>^PKt+}{bpx0~j{J-twi2@LPX0g;_Gr2ujx~K` zm%NdMJaoDOSszNH<>dxV<@~naj$&%3q|~#F<9;L|=@=V>G8h3&;rl8SYrBfe15SZTEk0EDV-j++MWEytU@ zPt+dh5TWzN_2n4UQAFJR-qfLI*LQq5_Wc0WT*4~o>LeHNH!NghGL#KL(w8b5fv!hF zM_b#Hsz<~cGerLpet+=-Y95g8oUe$O5riNbxijcG0q6SRjuY}>-TTb`+}o(9vtCYD zE5wj>`Xj?Igt1CGQ!0|*Xy#ZF0aI@xNyu)_RHpzN$WQxjR&HwvE*Z|&^tlqBq*bgm z$>nd|`~C!tB-1<`f1P)~e%EJR?D|k&AZteX!0^y~@7H4#i`oB@Fx^Px-N7}>8EqLXA)6SWU|LQ-Dv57&7SSB0t zT+3w^N-B{M=#V(5ECfPnMcP$* za@%Or&5AZ#Y(0kZGf_;ARGxVAnyx20y?r>YZMoeIG0x(RQK0;-ee2~P&; zds{hV;}rh38g3Okov(R_JRI1FD;^SnL3-xlMnj zs2ec%hhab@FQGvv%gP!fQ$;7N!f}>tE=W||%6ACgR`%A-fB0uZEO2z(J3&C?OuF9; zMfeY0`iJlX3d#VLXbO23Ku6hp_}d1Ekl4Q`fezP^ft&5ErOTpIQ3xXfT9i2p8533H zY4SI_FLvv1^lNPaD7tCyHYoBl(m)l=tkIsC55$-x2InLkSUhEeyt$Rb7#r-Lj{#@| z_d#h|#QDFd5n%gomM$4vWBjuljz+<$qIPM4t1dh-+9}qa^msiU3>~ViPmmBxPV*$_ zYiz6Espx9=AD05Zq%KyuSPi0+e7mK;uWFB1q*~}ufS0IV&EV!z^@O}b>RDoVS{@^pjJxaFUeo49 zdN&l?rm9u)#O-c{7S*%2w0t*M{puPjO2|8=jw$nX^u5aH=|*W{RRID?y&-dy{+E-2 za@bhRYE4Axw7zjX>^G88(7=Gt<_sLE93bEd04*W6RKae?p97#)QBgg(Z%_wA-hRL3 z!YI?Fgsy7rU-$u9iFlBNQy*7%;_fqO8Oy!T? z;vWh_Hq_Z10qZkBF%;)hcZuAkoZwpx@Zg?d4n_aWXjogu#i*~2yuICsXJw!O$zZf`P zwPqH*{P9J5EO4~!aXc2Vj6qaV;8Vrf08qY8p`lBX-*sZQQR_&z4i8F@NzSH)UaLc+ zIDdQ!Tv0hvh*c(^nNQ6UlZAG%eeiJ^YdC{8t7!!S^{x*8umq6|gFj&Mu?sduokic6 ztGQUHYGmvKX{R;w5_toKtyx~p@sk`a_v}IgsugAYY~ZZ$weG%WFqcca?)aGGKb$xl zTPqRZX{OT!Ncq8(s3oD$vO%L(Cy%#7!YN@KV%$UulPsp+!$N1}->Il-`iFL>SD9OW zUi+niRTto9ZB0ZKz4C6Z?s|ho24zAN7KcV&hxsss?#fu{HpsGZwZ%{%}^nyEA&f^wzEIAX1d9#%}Q~_wXMfG@W0? z%sqv2TWOp>`OS(CX6Hm7BKZO3%RZ+o(IDe|#}qz>yg$*8S`UZf9n0w@0xN{rhTMfh zjzruI6RwA@^g0@bDTqL6uqTCt_n$$J8e%v!I3}HSq)?1p^p~}l+aQ$en~`){&p%ET zUhE^+n)Nt_b1HWwC%`zdrkIZVD=4an{{q9D{$u>_C$eP-6rkdE(^F+u)(%0eJFW1| zoD-hpAF*HU1(h*llFa!YL}ve9G?Qaigz=#ae=qV49_(Tew*+*RJ6PW(0A{*nrALE> za8SNDH^=fA&+&-*V&J`Jks3G0032FK{iXg40ssmoF`gjN)0dnbWINlfl|FfRr6Qdz zs0|4y)~W@l+|?8(&ex0JU}Wm){e`8vVR#=%Q0ckOBWK7j)zwW8f4z2|W?@#s zoAmmg8f(!M{JbQRs7Ai3A6l(EMHnQuBjUj8!Plg5+%~U;;VmeH2(UkQ>7^_Wj#}PL z1n$n6Ybpn*u+0wvyzo>zMo~86AV|wHrK9J7H!^Gcx6!(YJ8?h>lpy3PBtX)XusP3JO4ijt_1?&)_D(?@_%tdvnMVJR zwF8=-XNY* z9EOr{oAI1Ca&o*CN5{Ee$A|%j2wiz?K6>G9MyO~8hmVyzD;+91*U4UK{e%{VyrR_L zuG>Rux~0r)kGtVQ!mM)@@D`^;GsbYNsj07nQz=Zs2fyWTfrlx(_nE z_qImcTPS`1<1o8ky0A5GhMlr!Xb@TSa~Z7MWZu0UKfpdhMpyugu4S4w}Y-{NRve+LX(RrGwn49pZ?CQ)F zqAuC=ghaT86J+q*6+EHyL;ZgiC*GnCtzejo5a96`{kmAdh@{qfWv=O(Fa4Wa!^Mzi zqGk3N7X4cH5jTbtZ^H@s%ah1a6aph4B>AGk=oW!lR2OFdIeG-9wub^R$`N{=fKuzO z`HZ!9d~gE_AQL1NhH42~rU%7uxHF-9rL$AOBfCwD%*9aw<3YNu9EZ$Vk9lqBfH=mS znrIhTB$Tb+2aR6^)o-IBX_fUJjQgdBx|S66L)y>!Mn0}ls7}}&-hKJEKaQv%k0PpS z%|Hl`+*dGE;8|0+_Ju;Lh*ZB6P(Q9e;Vj*jTmd9SEa0l_%)uT~IJZI>X)`J7n~!1S zj$7c}a*+wOdzlwQ)~JcAtcB;vj`-J(|E$LXmLwy)3T!<4ZD1{jD<@>I@RgX8ilaS- z1Nwcgeq^T*5L^KPJ^~-6|DCiEoi^sXFG7nMmBam*WUYDCVMLxP137A%f-f`#gZXqO z@MKMl6g@}%uFXHLl~kttxO4hNU9-1f#timv&on;TU68gjF@I<=NABAea0eHH_@i|V zqG;nk&5>Q&tuBF(EPHH`tZ_Do4W+{uBq0Xd?3r!azZ@g|+gvEL|-owM^hDCWX%1YV82DP@u^X&e>N&Vw; zEOO*m`l~+7u7rRPYqLuoQ{@xj-dV#_Zd*|ofIwY31kmj+60W&jIWy&C^Q;;V8MF(Q z8}pB5PxcqD%)o_1Bjs;=eSQB93~cBd=HXAEu1w?`OFDUY@OB;5<*FubcfX|h&Ai1uyK3CEfchj`SX{Ocs{ysh_;^fu*6CyZwk6cSB=H_Bg+dQgi zInnvKo`Q-F_BAi9SH(Od)nD*=Dm9GxH+?|hbTAnh8VU3L+Ydt#n99vK2z~Nc8SYuD z6N)HT?Z`=fIa&H4+`(UEBVLmS(`3Kpdxi|)!2pgrU)6w1OJCm8f6CAu2o;0mvM$xX zg-xtVs8R2WwEVcn=YrfTiY5>M^k%`+2cN;d(1`@6W2uZkRgDhL@&Bwq`fbOCq7v>n zmD#CH6$15ZRYrE3LY%9pWlSr>1*F<;-Y!eBEQ@qqp|is*f8YjX`dn)3P=S@Pyg-dz zgXVsgP@k=}hVi6E`nSPa6G-|IKfKHIZuZVbHLo;o23n>F=H+SVec>ME9WFzv`(~Yi zDuByPE_ie;S<{ePPNrid7_36R__z+RfaPmQ0Qo>|GnKA&;xLb&DypC98F{>?%kR%< zu61PG&yfxAzOz~o*)n2cI1)P9Y>_R7`(|iTLNX+v z-&JAfKFz_o!*NU?ytM=8<86=e{#h=wGS&*qeO5;N*orUH*q9hPJqnjX09H-=LZtQR zV){QBYE^({JF315bX}qk8CK}~`LkYb)1nk1T2{WlMW*3Aq27ReaLrE4(D!3KFXjce z4+NWt@85U5cIQFyh1k+TXXby+M@$Sljp)tC!i~JV1{1%<|9|auR#WNOFwv9J>fiK7GOHdkF)|JTTzdkYm4O4Qp*KebGLC0 z2>HkF>PesByEx!Av7R^aEEAITdbT_h90c-ph@e?7kHJ1OCtvgf_RR3My614o8S}5G zgDk$1(I4>%TLl z9sMLQuB%eMDHRMm_YzIKHFK;pD1E&X+=p~xd{;f)u1>;*)P-baCAd{lFkjrJOl$M+ zeHN4W<~z_BCw*p619}>m;sC9SHBVB~4-DHY;6ekUyN^vuX(&hW6WAVyCsoEjUt|1; znA=PqEVq49V{oNfh4bJQAMP5T>%R!qQnj;6o6M33M~$;p+q3DtVDvOwkI8L-wUB(D z@{x&TSHz{(sSb{|OZ%;9CoRD$?jl*2W}?ZcmI+QBqe?Cu@xNcUMz>TWvpn_cxD1W7 z5T7f0gZs;O;vb)hfc7t+TfY6Q)KocjD&mBb7a;B;A|mNv6YV#C?0WNPVx*cBT(rXW z#qFFpIqv3fqtegkN=6C!#OrE*fJLmmBK|rvP48Y9Aey^SJpzRzya1edLY_6=2W<}0 z7xR%;$+S#~DJD{Q$=qA2xl;SBL+BuVcQUl#R{lxw>HbQT$bCi&5r3Ks!0~T0XET=w z{+mPUlsq5{q)1a3$ZLkykK+Pf#uT{tq1G}*^{$GQl&L2HHnxhpOWa?r$3N4EplejW zr`bEO%8-ZG*VjK@YbR-HY9Q`amE_CzOaiv-0Z7(%-!KsTVhgQYJ&G~iUHWV7kG89@ z(yzWq+K?CFJfU9OHSi6Pdy1&A=4$g$)(8SoR^YOIPMNf4lrS4)HB>+w=1$t+$EEF9 zCU`E4Ck@_uhY%B*Seqj%#ah zlZ9U7#6NrNpb*B1|_q+Dp#9MVct8S3hvmrIE zcPr*vD=Sjg(!i?+50wMAk9Wn%i=Kjsk-E`D7uVgM!9tk1apkFz zpNoFyc`qP_p3Pr;ud4%0zKj5M0hB8jMZrn;R>wE|k7uP&G z`6ruWzc6q(^N8j5N;lG(t$m^xoE-=4)vBet0G1(CYhuS{#2eQ6b!6#}G+AkN5{{a& z(|J0a1@&$2eo45AowjS5+>u)0zg})JPgh@9u;#GSr8GR7@5s(&**CkkeqqOjMf5P_ z^_s8W_nPRSHieC2?b$oEef={=QcFnwY;(&8aod0gNX2}=AB{BD8{S9uawTLWE54g& zcMhGuo@tm*!VZO9Ar|hB(uGcL{s7khj5J_}a%-7dJG&?$S;t+00R68j1bE2W@S*0V zch@2%@|aqcBai?V9%%t(ltqTA@7>(&j)Dmm2r<{k1ed5zp^K?nI?$%~d$dc*;|25l zhgtfDo$EVxDfL+W83GvIbg{h-VF%btw0$aNg~>jveE5Y8_pF@|lS^Lk_3=$myC}wi zQ#1lMx?i=?&@!78cr1D1&v5|jTE3rZ-R@4}AF7dIC+h^H2@thhLph+P-v!JRKPkEd zlp%s*M72SHO5-3||8!iBGle1K+S-yNw?^iJbc$W(P*g$8C>|1~ zuWP}AhEg~U3!e70&@l1p`97=roCNB5sUKPJ!POBw0Piwv*cH397?gYm0U8h0jNvC{ zg!ElUdTX%jdgAsuExMD14I|1*hS{-&Ftv6b!ZLof1YpJycn!J6#B5$>z&`GX&NGO0 zk>LydZ@1MBQ(0_vbxogC&{r1>tS5b^j36{04*Vl(Tk*athUbOEyKStY5L-u}ZAm+r zC1D0tO&xT^A?{D~O7u(s{cma_UP6i49AwMAFN9_wt2YFZd4+me0o>N3WgRzbFwf86 z34X2$Q-hHtru~A%t$RUx6 za@F}1aVf0$qIt8#!dmm5TOlW8Ab)!IcoyB!VpdHU|xn_YDlcruKlcg3IIK*3xO^k`HI=wX4ls*d+W1900!#=ffZ-1V z=624wHn_D^;()n?MXpuC7$n(?R0;|a&x!`_23 zxC}uXoeQ~?)3$d@bq(*YK8=qTB5f=lMrT8^RPf}OrCv3uTI5~DtNVE=R}vN?zJBj- zHHA(d)8sa!_c?GM`vk5~Mm<9_HY$}e|EkMhb-t`%0gd4<8Msvz1}5`^I_nee*3Z3m?IoOOWgB|suiKDU{x zA8pvipJ)MYz}552gvj9DqXS^aLz$rJ zre<70uj%6680;fxQPtBAJm2rG9^D7t;4Y2Ch4;Xb02}6P9PYVaQ=%R zAzw$TOv-^3dXYu2`Jn5108JVdOy+aovRrL|j|kEMS zYoX=4%D)9yA^I8t=2{mmn?PT@!f>`S0?|g}r*q(j;;{k6txCShs{9UL3;SX9w2W( zEpq*MWu4cjS+G5=6_ZQm?g?*B|r3@7; zI0M?c*Rhts7N**j3scfy1@m4cxa2rQ&1Bh{eT{rH5HGMFxoLKO#EQ%|n{11c)JXC< z$2rN;G%LXQqQ6kBY;VD-y{R%MO4UO6N|pxd_1H_)r<3ySXc_!f3~o`^HS10#QdQ9P zu&wc_1FD%|B!tk@dyci!_A#M}_Z!4`U$$?y><7iQ^F8FgBDS%Rlz%lzcEL}sht24Z zfGKE;`ky9=+feTm{R~*8f$MTa!ZQi1-g;gGw zh=g<9dB9`wxs*NeK0&x`$z3Kl#$SuhynOEV_r31dN_5-K{2x>VR|eHL<5KlQlJL0G zoP1u{-oTUrB`1s9iVY-o-tSM`ui@A*II55ja=f{ue388k0_-}eGUr!>$j3W*pVpue zU6@X3mW$I0ud5CKb1Wo_`9qIKDC&JN8H`^9QX(U49Xe2Pw6zWXXldKqHL8NA?CP%J zc=C}wZDA|KEcdprSMs$nG8U^{A+Iv(C1n2j}&@`4tu$rtop7bnw zA1SgL)|%>FWAze|wi%(Qu+t|oThR<2cRW7di4Q>56m=oRxTf@Krd$waw?;q5vg}R* z;E;05P4AH(Pc#Viykbw;JI8Z666nE(+CRD|zoyufhS^5;y56)ICbOBM>4%QR#=X@z zSvZdeg0fe?^VOjVSo=?YoD&BYN}BmZ`b&xPtX_B*&+-cBw)X^WlJIDpCXhmTj`ZZ9 zU~LibQOr&=qRcE+2e(-f6Aw213!fh1^K)aSzAt+NIk%VUaX}S8a89l)qg^n?&~WEP z09XCdq$|vCEY1J*s6S2g>Ve>^x)=(jO0LW z)$~{yE>6r39EKMO)1O?33uJlWbw_y^ULI(`f&y@qk8_%>&Yy5?RBbVfien0`Vk$ZP z7J30mvF5BpM(*n_|Bmt8+-=rl9!kw{XwzfZFhx52u?ZhWUpt5ya?>*qo}Y@dU09!P zxVpx^*GaKE{8mTjw##E0Zw-5m_Tpr_M+n4n7~?gKqN49AuIQ9(w$-u(w_|AZixWQ? zw68YTbQGideb6;k0??j*Q4O#Kpr^~Hcc^wn@_r4Hf@pu8|At3(&7RI~m{>yCms9%PHw4B{ZKyz&B17|5 zekUY@cR?CFmwU*cC{Ty3_o)v-HgwnlD)Z-2y`Z$SGy1QUd&-g%NY zjwVALK%bLR)EUVr13hClH*ytggU8lI+ytrxrxDik^#T~Zek+j;6*rw){Y&h+h&_NR z{?=yf;~s11T7iKm}?0w?)D}$QGEY`E(m>k_QG-2i*L-GUSpL(t_=wiIbH}wJd_<+Xrlcmmx)w7A(>lOpLouBbq#(MfKem5)VnmfV9^*#tX zrD`&EwfhBqn;Jy}`e62z(-u$Nw{KJXW0vjC2HgT1g7+#2h0UNrF|rY)^2JP=P%N&6 zjq1b?z{B)IN7AHYqQ)!)zrCsjfoc63IG}2xE|NFJV9G-6Y6kH^R|0f34)LR{I$`(| zGGpFQlgg*891E*+^D=b(7Du(yam1`jiZ-mvg&|CAAs>wwUAox2gD;rU00XhyUY2&> zNuFFX;aUO$2?T2^YdL7hkH{0?X9dAdU0)>34+|bgzM3C6(*r^lK(P86Iaw)2_f!L! zv#GzEcWSJeF-;DuS;WuH7O6u;-34e==}<%`WK7+7VJ@x8(mve(ygdUfYkri zzv`g+Q(TPs==(5PnZ=mmFh&9gBC> zYgJ6_ZX46I9VL74pH+YnnlMZaeTy+{6>=n$~uX|92UZbN&+*PIr?$yFz&g#nsx@ zkE0oE$nq^7IE~&be{Pl?U&qyVORS|7w0xPyMW$OoT_DJh1s@BG0{swGgSyobRRgAE z0*v8ghm@lARe%v;GKNBH&IUd<>y;fSHrzy(cch#qZU#RYxm(Q@s<~(19WR_#`5Y)g zjNMz?+RiqDNjBSVR#l9yNfXZstU}K2hxC#4)hqZrrv4C}6^oi`qDZ5ab@iP6`m#-Q z7*hqt4MIkF0yRd50I31Y-VPbB0y{-zEg|6HxpW*u3Vd`x;p^sX&Dg?{q>AV?s-G5J zqb+ZAHkZayGG_$l2a|9T%ZtB7f^PP^cDWC7%6fXft;uLhun^;Ol1z#snm9N(K-g=$ ztxM9W>Jm`7%Y649d_nSP+KQKoG*WD1lgwg*unNAAW6*8Jwy{Y-+2qrur5#+;L;^G} zwwU;$U`ay+!c0dA?ia2(O5$!VAC1tgOqKT(_h8mO6aacN5;Zl)Q%SAw2ekH-z-D8Y zvki0z6&-?9Iq%?P-_#V9rEQ0O@*=t&JZI3VMabZDHEUOI=5@aJh26QI19aESv-r)J zJty40-AoXu1_ZX|-nx6?yL}BsPvkbgnff5 zx8dmDu5KZ1x6_EWi|W*~KK9P8Sc4f1M&tW5(Ap7xk*dz}EhPuG)H)s4Um$*1D-QEX1 z8uCkjuo3#0Ux$r@v$5)VYT7=9O5~ldqd=z~>A-#GmD&bh?HQEkW;3OlX@U86G zc_klRSWQtXzuIUlh1!+CyJD6Rw=TY5@7fM+UpuF#k_A+{cK2u|Dbd*d92=rBnEJvD ztGB_|p#1*=HY$8DmEf`t$gA=?SLHI@cRx{jyLNOF@otO}Whx3nmOobzRQki;as9y7 zHLasMrbaAJcTpbL04yrNGe8R!)lGoI8bz0tQYBrMD-BzI-xmw>Va9ijNtjDGDNUarJpvMya5v%J0O_YBjib*&k1VM*(e%J=yaUySD_on z;y?j?Sc4JpfZE2)2XwdKRI#<(c~~lC`wGOlatK5L`b%pEJ`BOWozLJ3gljvE4BwS4 zwGGRD8Xe~1tkH6@c`cFv1T8_yPZOtW=}16%=}z9*>F@uc?l0e};J&C)SVaV+kxl{W zZX}hI5Tv`iyGx`S=|&nv>5ffzcXvv6!#<1q_dK88_xu6p+t!PV&01@&xn_(x2BM~~ zuPk36vEUsU#~4u#bWS2<#O2q(IU9PX6l186R@s@VYsc0NBFfVnh-5w4 zN#jbo(dpxqN>--QESMIg3w*_LBXx@b~#o>A;Nx9T;vkl}nv!zfuvQ zR7kntmD=k>vu&bBWl`R&oeq~@!Ua?;9Dm+cmq+3ly zn*SoA%_M9jD)1w+lT2Z>c64ou>a+_{@K;H4H*OS>~(8*mF(`K)s5*A{-*^*`zD8Y`iec zM@2SZywYuwth)$~xFLs}*wvW2J4(m3QX=o-l_uow1%Ia78yhbV+-_rc^WLUo$o=eb ze2GlDc56-)vAlKX8y1-v=o1_!Ha$-+Vc^wpY+YiV{x> zGLBw|E5dyOVe16~@IG8saxtf!OteWTq+|No~B|~-;?awY2 z!qDbA5A_#ntS;TXQOaDsNBA9nCewI-t>CX5pmdYrj5;(ms(D+JrS#VDU_q_-(SdY*?0)iKdv*D)vpD{OL-z|fOk)N$s@GX z`k6EkurIV!*c!y*v4ptMLnrZyDQom}!x-VH@*R5&(s{EtV6@8LhhC27ROQBTWht-s z_L`jB;!T86L{Q~B>?{vP3SMHC8AtRvyie)DfT0=8ZK%NScwz-u+sU6#7(v!lBK}D!kZ`GzJ`%huD%(T;&#VahxQlft^ z?9vIS(C?m&>$6+tU$+(PZc=KTMGJ_v-In3wZbZz)Eja*#}}V4{5PMP58| ztn>5ezXRDKFD3DYR+ozd8Xo>6GbpXBHs{1+>o)McF2N0^BHs5U@lyD?D}WC@n0!fe zwEJVnwH$AHqDb-Nib)n++0ZFu)0*6B9>RNTuR^`RRh4K?>V%Qfzy* z0R2@OX5>{>p<#3L|650u!IyUhL}Z_meQC9pT+O#k3dR8i1E^}v+;f8O+6lyun z+w^zTqe7t|m2A;<$*zZF&LW6$Z@R#kl$-%2w@|9%36IV0!_rwY_m0g{nZD-)rw1AH zb`D2yn8XGhOIBcWvmWw(!2h(iP8eRI>+|Z+Xoi1j=i2D}`_lQwkYmx9V+WxGMUnAl zi0hM)pM?08sJ{tjAhd-^vAE3!h#H_PCE}8HM3lM^Zv5XfXZPd}Ruq@|{1uHw zj>eM$8%~9=C;a*kSIY9V<$`lD{PC!-HZM%vzTDPcD{Kk^49)MDwQAS*#L&aoB-;;R zT#4$D>kl!U3ju1e05n}bG?!S~X$WSv2f0`KRNnj_k`X|@t?QR8VjO!WV7Kso+fQgc z4|Cg-u<=*Q*W`BMc>c_IY%jx1e;=;05P^)W zXBIjDkK%2g8q|Pu4(=@Qn_fHX3Un&YW^QbGcg28ST1!q7!q?$@f2?w};cTh)B@oVW z-12D=d0*J5!b?XxcpSqnioB5UY);MMo1)$M%6}e;qTMX~6sQB-N=i3Hit8P@=o7)> z&$V1oBaUAQiNda~ziK*t16T|KrNh=5N;DDU2bd|LBR)@TP?U*LqmrI7JMl5~m81nZ zWzEQ^s7MS}0-4WukHq?LW(E$%ULzXMS(^d6ww#t9lyl6L4ugzJjk;b)?WEs+fvLIzW5%^gp+nbDpatod79f@oV{grw{#>KR4?8K0L-MRkSs+FT z?UhIXtvqyAL~DQi{fLBso#E53yq!tNrEbZ?0t**89e!F-@^@P z$D4PU0eB2gU@gjE0JLb$`Oce#Em(}ugjoNbu_!qOCo;*C zc~zO3ExDt;ghVWk&L)9#|D^W0e_EWhazMv@$tJkjkj!K_o2$p?E+G4~1mZ$PtU>9;dExAVkG{esf0PY^}ys{YP8`VQO0eB@N|fby@=1GQTNk z(Fl!@G7I&^K%ZvN22crCQ=PwTCYy%4*<`;n9LdZCrL?nSA86_$1UZs2Cw@QIo&$5$(T$V6 zdz5~zsD5xjg&haRJp3PYUVn2d4zM}?qQBW$uqJMNuAcyNkWITL`=BkYLPN&DLE^Wf z4r=_LN~DgVmfUYEy0DZlv+z(Se@Up>c^DtGP;NB2u12a%xuhE6x1+7eiS(mg#fjr-$aBkj$k^ z6Zr?-Chi0vpKZ6}T)9xmLq6WRPMmHN0m8@U{dNJvb8dNCfC8u>GA*bhY8?;ez=@Bn z(^1-idZ%TZw!GM6zO!#=S!n*H!pHat%kqNAmKxJ{@@H@7dY&Imga3fJkU6I`uz)|r zd`lGj)Zw*FtN35Q>NAEY}9g$LUbfw zViQOAt=_TU2yIC*P>5r#o2Az=f>6SUhR1RRLe%VjsqeJu?d|&*bMwqO4J22pdRMx;|a z6J{pE$mRWsU?L)*6fv{xlDSEL{r@gQW@E39NK|p$X49Z|VVy{cM|LhSV#R8QZb6P< z!=D&+$u|;}&o67E$3X8>PL90R8x(0=->K6#I5DH6-?j~feuR1-gDc79eLFx^X0AkY zcg4YO7;{32gLyaM`gk|9*1ywGcAORV6j^OCQ_-S;7=Ck~sGO!f&r_l;(=+R<4@DAG zttU#f#ua0JwzIvkld}CH+=i!ZLk;xX+~c>?vy>P+&5Y|41ua{2RxBPhq=5^SMr(T` zT!>uF7X>jLns!nsi5YLdSISb~t3G>5`u3JZ?ady$dLk}=Ea4hKUZ1CH0kAyyywMWn5ykoK9;VuG*TckL7+*d7dC(k^4mMu zpd7vrYgZ_EAv#jox^%)*tjR<@1JghC@_NNbkd}j$B)Mt9Y_RG}G#u+~Kq6+CQmJ+( zpyc0}g%$n=lw6;gpFD(^mRS*$K71*Qwq=@1u(8DYPUK1OqRZLtYy*?~QuVss8c0-EO0~8C;qch?n(Q|@+Jx2gvwzBIycXOjnCSN6 zYC}Zw&#}X$Xk7=3pyer!N(d~V(&;J1moZl&Fz?Ns{hUysp2x3>E#qlT+s@xy-F{%iZV=p&#)=o}t;0vG?%L*#$U;GX)PQBQv) zoC)T|Egi15=vZuZJl-M({aK~6l3%H?1=QtcCZoq@ZMx-u!pJ*H49=3k>0 z5Awj`3Ypp`5W}7&haTA0<+PN-1ek_Rd_rFh#PH>c1u6yo|3PW4Y!U6AJw(k`TE6OL zm=FG%I<0%b=F<}thVq^antzxZ6@^Mim9^p(go1h=)(>ulwXpCAs^BixDaUJ{c7KEin?^6I2FCpt5YK8}ZO>DRCf)%!bERHbLZq&^8RPSK+|kKFyjW}Z>QFI9 zbIM{ws{gI|W(q?O72Z!F-m8;j@LvSOBWU7ucg%}!u z@==b;P8aG8Pfqkqw`T_sn@HCvN$rGk zYIWKCsFz>XsHF#(oJKhrVh z@Q>-RN|18K_YL?C;X?jToB;+suk6-QoUGq%;>oaRe=s$Tx(*2gMhF;2J3Noa_V&`2V`xf#?mzDKT#S`X*i zW8$wr2jYM}XVhO2Y2kfBgof7-&l2748T~xdqP3?3x%)~?1XPvR`x1~c@^IuE$32?2 z9yOs$Y5yGCNr1cq2m-?H$UM(LZ*ussS7dVlJ=ON#5AKbG$E)-%RGXn4x6DDMZ+FRm>c^_R*{r*yKS#bPUL{}T__qLHj@c)1f=-S`wFb=od{H3<#haGmA)F<^FYH@qaCDH5^=JtLwmK^0)%lc)U<c^%>ZKBPo-Srj0!iAVw~Kd zA5q@?Z}39YJjFfI_}nnG8gL7AGYmi1-xlZC<5g@Ow?GA;1nT)buAIwzj~|tf`TdCq zoZoZHJ~GX{^xNqqB4o{8q0Rje z%9f))HX6@e^Enm9UHykK>0Gf9De@8CUBL+O2_i@L0FS#YqXAAGF$W%C@V#Bl?Dji*+*E=PLQ*%MujP ze<5G!FnWHHaxfzML5~$6@|nN;@r|2len-TQ#J>)A;RpPeV!$rZ39eb-=+U#TTN^Kk z3$Zr%KS?BjyiEUy`btvw7b#>R$7n5jB}!b<5?`liWV2kumXr_dW_Cq>LOtc>-c;Dq zN*;VI3(zyZUlMQ~`kY3d)_vfBi1E8#Z)Ckg_3_piI7%2e6hlw|RQjWN+2!&`r(Dm& zM#|~5r}(rqA0ToQQM?|f?KSQKJ1*aOVFQWDi14PX0jZT-I9XF-4kBQNz9~`tpgGhz z>l>IwN`~e`Dt9h{t#GqTF6^1fn`kqOAd@rwR*AMjzm28t7#UQ6c6nTgw7njYx2gda zbO@|c#r?9oXaD*{>-4>aPz5z+KvDBH>26t_4Xr}f&&xM2p9rwSZG4<`zb4x`ui8|* z-k1|=F%8R|S24K&E)4WO2AU2qL=56C@Hc60n)N~om_X{g&RzShZ@wR4eg30*=%(T7 zvIj_};l{fx;ViIBoZsjw3)=0Kp&lW%sf*hkngWSC;p>djGLI(AHO_A8_QvMBHTG9rgk{Gu)2nX%dk6Iu7mSgmTuZ81V@?^Ot zw{u6DX1Z(zlZT+%;m8i1yudne0a)~__drR(PG@zaNYwCNOt7wmze8nD7__gh!xlQt zC5#7|J8veO6`wLP)xLWRl8l-DN^|#z>oM3fS-6qp>uw3kDlUurf)=~<8Z&`^r=|u&gxK}Dc!H_mtw8){9sbgrp1@x zC+Q{v&7r;`y~5uS0UO`jW*ybi+MG}_|6m*QuyPQ#OgIsnTM)>UUNH&uM=VwRbF%w!CcDDs_^LU;v>OM!K4NbCRbao+Q6H1e-c z=Y~3t{{t8peNT^#%NgXp1g*v!F~t9$kuqJrkJRE9k^hpI5BQtTh7}1%z7>4v^g5)W zCnAr$+&_WP1z15=oH*b5JdQwTAGJem0j=kn&&}~UJWw@o=^{HB#2QSYk4*k|(&9B- zL2>muBFpEXyhruWG*iHf*`OPVaS(Z!W-?Bk>pYw6{$uu1^~w9R7A*36=_`LS6UlAD zE06)?jNV^m+#mUE*a-q6QLL@0!E6Og)6s!8to18#HN)jv$V?3M0fP(8gHL3L@6;NQ;T-^!#GMphrbMcOflz zbCYfa>N68U*6}7~|Fe~)>t!m-dOdj|PO)p89sk1t>j|_is-th@7OcA8KL@88s}%|l zhtTXkshUu5{x=MUIj0rXzf6 zkG(GD8tUWYN?{3>$!|TcUcu=Vsc?ecF(+bGPUS`P4UF@flf<0p)Ql08Js}iy?H}AC z?AxZBSdM^VJT@A>Wk17X&0~va1s$;;MLyx%>+y9q=1tU%+uvTSUJaxK0+zVZsfdJp zy@IFjcs5~6T3e}zg`-Hkex~e3jzJG{Jx88X1L@aO#j5ldcSulo8@9>NvarAsLyjl1 zPe+0%Y}U7WZ$E<}UgD?yjsI1XMr z(S)SzfivUg}Hh4OY+DXDpsbn|F}AMm5QN4E;sr}3&l zIpTTw;FyHb*WB{fUAbpWx@UON*GYO*_SU)eBbb-R&4u!)K`cdCDP%|_$%^q)y>-7s z$zOA@cS!oRWGLNeX#p#wJXYT!%7(4X$1d;k!c{ih1!_!?~^KtoNttKn~vo47uS ze`aXswM~j4tgcfwSN0?%%!{~|SHLU~OV?fDUl9C}KjBXQt6S;wx&N+EGNhs&$W04j)6 zNY6kDVz*6n%68F!ZnudtT6A5i^rCuCBOgUYMcs|=2wVYA?gVfg^Q-k?nUZq;w&_d9TYBVuRA@^n?(QtoT%IMVXmg{BF~)Zqz4dMOt9 zdVNm`b||A+5q;SpzVxeNN#DVv?8;1zIO-D?0Nf9-*|zOq=oBG-eS&y1gq3y*q3p{c zfS~jt;K);)Ug%W`sAM>w#W#%NF2=v(1VW$xy{Nrk6@1ccwf>?sXX2Q+elsYfe5j4$ z?|vpluFQm{aTtff6AewEH^WEsua&h(Z_?cxEH}B;T`zmgJwk+oRw@K}ofq>TBv5Aq z_ak{Peq@+Pr-rh#?l`82!W6G?tSD`7e>~AHfur z0SE?kmbABd_1C=C$_fZH`E$pi zyF>7uia*YFB7(!6umWp~_djudSWVThu$0L{e*=h@% z{(-Kv-}Bh^6X(e=3Gl&_8`DVz+O9v%KL5`MTznqCf)EVRdlpp(^^#w}OmdsR#q&df z(LCwrpbqAoQW)SF5HQfSkH3B|a_;P)AAGc%WB?w=gw+?Z^YNH__X_UXSx%yV72J@Z&5yKK{~#?N=I{k+|s~>7@T^#Xv?e+9Vrl zP`{W2b>1&|cmkgIBY3CI2=qfw{^=ZjQUzl+@=@(+WEVb;nBZv$0il;O47TsqdDMDm z7CbOAu=%%iVDn-9;9H`AnU0pA{n4-o>5b8%!peJ6+K|!%)P|WAuj>ztH4!uMVixw& z2%kV%8OnISx^ypS9Kv3W0Or8!R}KO7-pxuF6HSW`I029#T)S3s0b4s3bm+MKc1bW* z5##VY+j84KjDYkS@`#-zNb*HuE%i$3Awb0QuIda*_d=0rm+=d^y#Ws`*~1Pvl1MmW z_b;mGkP!xW0$4Lef~VRMyA5+5ojDRkN8$&8TTUo z%*-5V84&pO8lPf(GVso;@K{_V}SzBY6I; z&cmZdsM4jKoL;Slo%Y!+)roNH6GakE97_TShLhyO0+60yCxE}6j|9)26<#{Ig z*~4vqOAkuP2As@Vvta0HZgQZzr)o}9{Jv3Ex) zXtG~CQ+n5N-!c6ZO=d3m=5cOp>q zbnLv4K#t2{>K&V@aDO*P9tD2+n~RPDlBT9j3MRK|M^M_}KiVPF)IN(zY*KFk>;^0$ zAt5&{1)0Jl+RdkJa3t_9kC#!Y2uy>o9#te#YbRfa`YA(O2)`=^2CTC-mbB?*g!UU6)r2fvU^YkZZY;6*@cU zQa1}^CDryDC|%uo;5U1_tYn_lyl7d-;9u@sfu6Nc3Km>lj_=#7%Z@bZ;(V=7DK5l6 zYC_FIC<5oT66w$t;IKF2uh40B73$$B zC!{{OQG>abkP3xmj}f#9HvoSw$sSJsIac>lP@kx563bQ-SvnKZaPNkys;_k=Qq)?V zSf@zbbX95lhLTJ`1%p|yxaN3E48X6%trw%BU$ba2i{Nd1-PkL#>p7}-M&6x9uG>Ia z&G7hMZs7Zy_NmXklL(d)6-I3ERW{;nK4-l*3*Pgz6}b09>+iUm#0R^jpOMI7E6nt~ z6#4KtX5m~M%LP=1XYuJm?^uFRx!9K!!hLRy-WMTgbjNVFN`!=vM7?kpgPEURy*W|I zk&DiI@}lhoISd55k_E`EV&OI4zW7l}0Rn@ElUwIBUILI*ea^A@XV$P3y^Y9C{~DX& z72(W_@L(^8E8d>ArAoXoz^Zp{cS}ORXaAoZO_i;b~=Y1qeyBB;uUwE zPxbepd~YOc&B0>X_CZRjCz{=QvuUOgaP4*TE)F~4G~Ru5wGBi;Yjou&ks&?LWOR}X zrZWCMd+zX0<$H;q>|KBY~s+dYKEtfsWgwBPg=SS$jc5Eesm zxnl4TKG59bQ}uJb0d?n1@Yka+v(KxF-IQTlH%agw$$(TPj2aClOuCIC)wKRZ?bE|9zEhqdno9W zYBGWQHdG`897e+`^I`z(1!S?)>gkP7vi`}l8%bL2B0p?vg~D6OPIkZGCw|2v@B)bl zl^$s|vy4e7N?dn-0TJw&X)a3yC-%>08J@9T5dMw5r=3XXKIk2a@@)WN$FH@@gm(@*fM%WMfhz7Az+uKD}C zbIlvLeA%UE@v7W|-$eQlSVSa1f|CUxTcz^|V?_<{Me?3T%G+H=iv{)V+yF93WaE}L7_E-tBj0DX#FDX@a`p+E+qM5rv*bH0>FM)}4$a8tWk!ls(32XH z0_>izYKvkxad7tm4?zHsll`AzjR34x1qGSVSKf33AP_XTR zu6kWfheH4Ee8-Sz@4J=G%lnw`uuDiG35nQjaOxgpoChh)5!WD0Y;#Ia%G1+;A@@Hd zV!;^-IRO~=cJ-)ws}nsYP4t_)JQ8%GQ5kdn^H%_L{es{7wLI1u$6aPWoras4iyJX~ zMQMARQ>^hrd9SRg9Tq3fhX^E?j`rKAiMk)-cyFV@zrUEk1;^JEXicj;vjdhN`_;~%jSBG*D)4wx{WDCG4g zz-@IG6ohlC)<@}fbs7^h#7sB=`LyQ1U>6Vy2KTjJviQV1Dgdl}}EK=wHo^U%B8 zNwqW0!_~f+fGql!{jvb(v>C3?>U2T^v`c$5MnN zK)w<4Tqgx^IR*SwPUa2%3{$8XI;|Pe zu>dosk*E>)UqyE%b+T=<_0dZYw4Wcu)QmL%IJE@;89)EvJer)IUOU9ut}u|Q&hqi2 z&O^i)_(UOg4i`fD4bXV$-zDm^qj69IWvQhdi5>XAXD!Laa>^9>FE460G}Y#^;DZ$# z-kb6M>D=AXkHejs#H|W1YyyfA>#X)S|2;@LBf~v_pz0*vHFy)31>pK^ImmoVKd1+J z`YsuVjNMq+zT#nuzhR3Cj3)l4aS2sKXWlOO zG-84xmeMI@TY;TECVzz7oRD?Q2*71CuetL~#noQ?x>hkSm6Y=N?f6T$ExWwtGVe2G zy#oYUqK{GUS5%*qWZPocbc*+8cq#rknehWE`fDC{7)`R8;F*;Omi#eL1tRV-9?;Bx z8_S*}(aZi)Q^XP4(#-1{`R@rTxGc>Yi^lG#6#7*C8)Bs-EGH$3_V@4aP|6FsqIruV zFT74h3^H0#4*5y>Np%#fDS06W_DKwJvds@)BI$i3p8C@2&pn=w=p~HFH14NPx1io> zY&&%`gG-dxmu@Q~THP0d;o(ome_uj>2bI9%2*H#3qpj;viPoY0_fZC<%l{wzbOV#W zC_yefg}c-_ZmKXEE(8u_;hyy|sh4=Z4d25l#+;2%(7Ao% zWMy^m#MILICBWxRpd;gh=MOsAnl+(r$Kl7ipQSC!gCi-i^$N>-x1YI}ua@81SKJgjf^GqvL1J8wwRTbx4Y=7U4O90^wC z!u#lA%A*FdvaPFFtCU4yX)b*}ndErTUK21Rb2=88=eo)tQRQdrLC%&c-gf0WGk#$4 zJLHG{IXGWPnlIu6TH?yN4@2Ggxd-Q#sq-Q8B|M(Wxr+;RM$o>aviD6SGbc&=3a&mU z2!3#=$~sWv(eKNSrkercJ@5;u$5ikBwb&Ti_n6pCL59|gv0x#0kA%ont4gw(#131x z#BB$`1Mlz01=`<0B$X0-Z2vAqsEzg1S*I!vcP-KHEx@O%APQ)BgkG?675%gj^y&+q z<`}DUF^Z@rF6$4Y$c+-zqZ&qg?31b!{5RrkLL7&1O06LO5tk=6Sm$YV#?~iA(QYF^ zPMlf|RSi?qNc==`T9I)3x>t}ha%MTB2i9RE)Ya8~C9Z$$*-oBQkI_l)GJ zQupn+H|9!G8sBOc=(D4=YMmgPwszNKcbwyEQ|oNg8ImovLv&>I(6U&v2Vdr&&bk@Hm{r-F)*_n;^VeE6r z_E@(Q4706FGj(^5lk?Zet(+f8?^$d-|JrxOV1Sbe>%Z{ksHKU)t0=2j8r?eH$CHn# zv0i>>;&F4n`=>*&9#h@Ax({xUq~n#zpMB9VngS`CNus1WyfO52VccS5F-MyW^Xl)e z=j&TK8=I%Dxw0a`_pNc=z7mhgo+ptUiAXJ{0qT75YW}G-5+bP3xT&o`H;H7+Yai?g z4PmiIdmUMprw+`RD3Xm#3v1$p#gUzxn?yT@za0hlVe&c=k9tk3dyzj2G7$% z6Pe)ElP!s;xq%=@K9Znja{B#o-@<4r?R6vk$ik;%+AXX#mykU@lnr8$rC9bi7{fXh zkM~alQ12JoK3VYM^_>q1JnSPkmHY#oDC9o7saaEe!mW|nKYvTtyuLwyFxgTsuj*x_ zXrFC8wTmbmH%35+*W@D=F-oedwtBw|!-T9GcUfqlu{ z{e=DM;YX3-fz**;XD+-84~$7ZL?+#r*N%@Z*Y;kKoir@5((>qa_sCLrCWQ$j2- z4JvcJW!;v+9a*&U!Di5~wnthC`bzomg;D~pBN>-HnAD-hfnw$A4I+$05P5RJOipHV zn$`KT(*XjL$zA>d9pRm%>}EOpuytBr^eiar9NxC;r$PFopK6vV*`2`N@ zH7>oeh2QwGpLWCPkEc*jsXN6flNXop{Vjsj!bX-iYV-6;&EKf`Up`Ce_>A~X?thsY zMEV?gLm^t&wnetA9~0+l&C$x-Ib3T4^CV*(Ym|2Id`eXk0Z?M_*X*EV+)wQ zZb{{*%;?NmEHzov(f#1g-E7%eeExm^2JgFuq@YvU(VFh;p(}^(9X)WL$m$#|`1xIe z-Ku)Xz{@F3^?3*`?CRNp+wQs0Vh!_Yvs|L40T<1w+%rv+Vk24o}f5(eNINb zyWlpYC%&ZJr1k-Z@Z8K5;m(UMkt-j2t`U3CZ~APFt%50v2O}=fwjeRTymyHAu6Dcb zvcI=<%`920%4ajw5ltmBA~LGgCMIt_kxPZzny?WX9E2(DmK_9I1y!;>2&8Uvc!e+@ z)8u19_V&8Ma(vp#r}_JnaQIIVTpldTUk#V;_E%an)|qDJ8-07-V>3r0Nw@jL8A936 zfHapV>J9mv9_hPc!c~xO<8MU8k>@F@Qi_B37{;^nQ2c;7pNO+q#eO6Z+9x$#`O%(w zd8+tix=C=VmwkYo^MYUf-sXMV;_zl?d6fbKyQrw^+yqx%=Gp>_Rbk%P`jX8n12N=m zFf@|nGW|u{lKQy%%EZqpyOZHC7gCBLS~r{+T}P)`pAA`uZn`R>F$g?G@+t6`K!}7> z)$yyAACs7kG5zKt(m`$}eRK{BI}Vox-|ir*fi-q6Vqdk}?}mONU6#ni*KT87%5(dd zzN@s!v+}BitWK@18tF z+UL(`?%TW0BpPVC;wYT<#5Q>0v*?k3@!ULf>5ZRGXehm2`KRtxd_x@Ym4N}O`W>NdKpgtv)bWx8yf zqP8d~e9JQiU)40qnJg`>cWA@cV=3q}FgJ5HpYkv<*f) zCJU$2)J&d8@JzCAo0eittG@1jwEPf@!)R=tNvY`Im8RTQK(x?KhN^IsT1UJlr4&Jx zPFA8Z&*H#4I#58)P&`))+b42$&>llKjUaI(I1l_ID+P;x4Ueq54LyW$kbb9CRlSKL zfrNoZy>)~fe|5~9wB~VCvVQPK0#DPOkIwoXiwEq7qp^ufIVW~T#yb9`lyY8-soq-F zCxHkRr%POAM{njJ7z2%y=~Bs&;+pU`qxd7IzJJI_gqS(Eio z$Ej^8hhTq@;FA(=cNk-LrBVMEA#a9bF?@n*7WH#$C(T8T@=r_7{ad0<3xX*($X=6v z$S&&19-rex+8-X^D+gzLlg&!ys@<4zLKC#s`eSNbO?6D}j;9mWmM3Cv50Jif)a^RJ zns2NmVZTE~b2%d18Sb(ZS;0@YAPOXmX2;I9$HWkx&ptnh5RO{_%}y9+%uB^>V(1S_ z^R>m3bDc2z*@xQ!MD^_Ry^-rJ?R6_MuUNt3p%&f4i*Ic7i#_jV3hpbbO-Z=U?k{FW zlbOuQ_=`48H#N_nTRQ)jr^Yk5j!VRe1lvt~Qu@AD@)nlzSRua&neQ}O|Ye{IzJu+c|&TVC=sB z=RPUkz3S13iil?=e({f~&4{ew$l&ngRKsevMW>0!I77}cLpvf?w7or@MSIWMxqqbb z9k<2qj@ZP67K3+3tkuidp1@_L(c3@oyK-$As`!azQS=j+_Ts$1y8fHsq6pf^aVRix zw3Eu$M9gdMiAAzc+g)j-Hc+UT|NhVR7*ESnI5&N~){AkBe`)FxnQD%6 zBWB+O!Qc?F%JT8m^2C9MC8l-Sd?m-jL{S@b3FVvT{J*QYT^>7JBSaZxc zQhcyK8ye;=Ss;5bB|LG__*3__7KN1l^5R4bqGmcwu{EHd&`}8c)c9k#3A%Du@s1~* ziEaSVfx_1)J>^}MaRGy{bA@*t7cpbT4Lu!Wc>GOQRgrw`@=6NgXL6t6<8}va^%QA= zzl=pcXVqYmi7Zx<;+Ce9GTX<$+#|u%q|mMLTH-&jSPZHaEUr#ww9_l-G)5VOun7}} zEx4_zA5ypvF1BrDf2URRC-}&lLo=1)BjzuBB~oF0EXq+N{UM-6SVf7yj3!*dX>lkX zvRk!0SVQ!U+r1aW_F{@mOzhjQc(&Q^B41h#vHyJRcyC^8)n+jv>tO8-*HBV+6$e7K zyJuIlLBeMC`>$y0Fow?!EW$z31v<&Tiyen7KP}1Ji))Y26Gi2uj!v6u{0It~T<~Hx(Q{9{S2inml->FSBjAQ37Hu`?PMbf@~GO9u#4==R+h+S(o^&&W%$v zc*HZ9AHDGw|ISLkN7w+cq z?bGl0dD0-m4=LA+)vjCbb zbvo?$12>6HDX(%kNE_!#+|ERb#D-!50=sL_C`^37YKsAIO0gn_RzSk8Y_+RuRDv0vJ9@j^SN-uOqK7b%eK;)WA;w%I+d_|C`6g(Avv>>H$xVa zm;*@`e#C9^nlMVC#&rM5!fS1352VDstHbN!=7yF>Jqk(-tajU<1Qt>v zS~+oRI24wbzmIuKicEr;=$egU%I-7XFbAJ{}z22wHj9 z+@2$S{1$ijz`16$NbHbx=V5U;>CL<W5ws&8}+#xjh>tuV?7GW0|fy;456-?;-*Kyp`drEU!-eP$rD;#255d50a?I z+=A$a@%F|O>%PUUs?&utCsM*JktOKJZAQRse>mX%VI0}!L zk6!g9d7v7}7Y2`K?i-Ih!o~Q8C;n&zK+)mU%o>#NKM^yd&bl3*mE{S(wW2(+8V(F6VSRrmC&SXdmFZ*c@h1W?E?-9i)>DCj_ki5>JO2uF+OvAPT^|W^A z{`Gt9-pDJ;B->)xB9{3GVAqlT3(LodNbc_=Ag@e_O|I?9!Tl)93PW zcY+4y(S(bRy+QJlo6S%Cq0j|&tl&{@<}dILLvupKdI0IQs`yK`{NEgkmH4^P+eKTG zlHmt$kGi03`pTKjkugbW+^w#@@>wp8cOdeW4RWcZ3>u@G^NRK6+^CZy@>4R4Fm>;* z7-I}i+j$EqsBt`K+;>vQ9RRpi)LBG`Rhtr}n%||c^}yI4rS_$q3V@&h-(pgQ?}WdtxU7p zYoZ4^%0K`DfmF2xo84JkWmUu zm0!GKev!s_>XhLQ&V)IFvpM=4mSerLS!7Qn@-5vz!mdApOezi#z36e~nqyBl?W(6Z zj72=?v8vYU>Oy$%dh6YKuS%51x_^SkU)E^3$P05Bxc)0=-$^Wo-LW=TUg;*o2-B@L z)(+Ip$* zNbu})tU~B<8x4?Cxbg88yqY|;0|m(0%dyz>nbg%+F0R~0@#VpV*uca6ER^7)}`RNJNVI>S}J<^xuW5W}WjH%INv%47F>o6^I& zD&3(a*y*@qCYP}|J}f_L4Mgt^vcq1fw{*Pi4-UM54;XZrf4KWu@{mTOR&&&L{IyQ&f0m1Kn4n+cYVo0#U_(9FT_q3 zb#KV=PWu;7*A4@pjBm$5-ynyHtY)t5CyEofe#jOb>TNa$!BTt8JQg~CqR-?D5`SJgsoa~b+|14zaFvc@& P_s9p~ggV1?@TdI;rpVFl literal 0 HcmV?d00001 diff --git a/previews/PR539/index.html b/previews/PR539/index.html new file mode 100644 index 000000000..bdf4ae5f7 --- /dev/null +++ b/previews/PR539/index.html @@ -0,0 +1,43 @@ + +Home · FrankWolfe.jl

    FrankWolfe.jl

    Build Status Dev Stable Coverage DOI

    This package is a toolbox for Frank-Wolfe and conditional gradients algorithms.

    Overview

    Frank-Wolfe algorithms were designed to solve optimization problems of the form $\min_{x ∈ C} f(x)$, where $f$ is a differentiable convex function and $C$ is a convex and compact set. They are especially useful when we know how to optimize a linear function over $C$ in an efficient way.

    A paper presenting the package with mathematical explanations and numerous examples can be found here:

    FrankWolfe.jl: A high-performance and flexible toolbox for Frank-Wolfe algorithms and Conditional Gradients.

    Installation

    The most recent release is available via the julia package manager, e.g., with

    using Pkg
    +Pkg.add("FrankWolfe")

    or the master branch:

    Pkg.add(url="https://github.com/ZIB-IOL/FrankWolfe.jl", rev="master")

    Getting started

    Let's say we want to minimize the Euclidian norm over the probability simplex Δ. Using FrankWolfe.jl, this is what the code looks like (in dimension 3):

    julia> using FrankWolfe
    +
    +julia> f(p) = sum(abs2, p)  # objective function
    +
    +julia> grad!(storage, p) = storage .= 2p  # in-place gradient computation
    +
    +# # function d ⟼ argmin ⟨p,d⟩ st. p ∈ Δ
    +julia> lmo = FrankWolfe.ProbabilitySimplexOracle(1.)
    +
    +julia> p0 = [1., 0., 0.]
    +
    +julia> p_opt, _ = frank_wolfe(f, grad!, lmo, p0; verbose=true);
    +
    +Vanilla Frank-Wolfe Algorithm.
    +MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: Adaptive EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
    +MOMENTUM: nothing GRADIENTTYPE: Nothing
    +[ Info: In memory_mode memory iterates are written back into x0!
    +
    +-------------------------------------------------------------------------------------------------
    +  Type     Iteration         Primal           Dual       Dual Gap           Time         It/sec
    +-------------------------------------------------------------------------------------------------
    +     I             1   1.000000e+00  -1.000000e+00   2.000000e+00   0.000000e+00            Inf
    +  Last            24   3.333333e-01   3.333332e-01   9.488992e-08   1.533181e+00   1.565373e+01
    +-------------------------------------------------------------------------------------------------
    +
    +julia> p_opt
    +3-element Vector{Float64}:
    + 0.33333334349923327
    + 0.33333332783841896
    + 0.3333333286623478

    Note that active-set based methods like Away Frank-Wolfe and Blended Pairwise Conditional Gradient also include a post processing step. In post-processing all values are recomputed and in particular the dual gap is computed at the current FW vertex, which might be slightly larger than the best dual gap observed as the gap is not monotonic. This is expected behavior.

    Documentation and examples

    To explore the content of the package, go to the documentation.

    Beyond those presented in the documentation, many more use cases are implemented in the examples folder. To run them, you will need to activate the test environment, which can be done simply with TestEnv.jl (we recommend you install it in your base Julia).

    julia> using TestEnv
    +
    +julia> TestEnv.activate()
    +"/tmp/jl_Ux8wKE/Project.toml"
    +
    +# necessary for plotting
    +julia> include("examples/plot_utils.jl")
    +julia> include("examples/linear_regression.jl")
    +...

    If you need the plotting utilities in your own code, make sure Plots.jl is included in your current project and run:

    using Plots
    +using FrankWolfe
    +
    +include(joinpath(dirname(pathof(FrankWolfe)), "../examples/plot_utils.jl"))
    diff --git a/previews/PR539/reference/0_reference/index.html b/previews/PR539/reference/0_reference/index.html new file mode 100644 index 000000000..cdfb7b1ac --- /dev/null +++ b/previews/PR539/reference/0_reference/index.html @@ -0,0 +1,2 @@ + +API Reference · FrankWolfe.jl diff --git a/previews/PR539/reference/1_algorithms/index.html b/previews/PR539/reference/1_algorithms/index.html new file mode 100644 index 000000000..ee1948b7f --- /dev/null +++ b/previews/PR539/reference/1_algorithms/index.html @@ -0,0 +1,2 @@ + +Algorithms · FrankWolfe.jl

    Algorithms

    This section contains all main algorithms of the package. These are the ones typical users will call.

    The typical signature for these algorithms is:

    my_algorithm(f, grad!, lmo, x0)

    Standard algorithms

    FrankWolfe.frank_wolfeMethod
    frank_wolfe(f, grad!, lmo, x0; ...)

    Simplest form of the Frank-Wolfe algorithm. Returns a tuple (x, v, primal, dual_gap, traj_data) with:

    • x final iterate
    • v last vertex from the LMO
    • primal primal value f(x)
    • dual_gap final Frank-Wolfe gap
    • traj_data vector of trajectory information.
    source
    FrankWolfe.stochastic_frank_wolfeMethod
    stochastic_frank_wolfe(f::StochasticObjective, lmo, x0; ...)

    Stochastic version of Frank-Wolfe, evaluates the objective and gradient stochastically, implemented through the FrankWolfe.StochasticObjective interface.

    Keyword arguments include batch_size to pass a fixed batch_size or a batch_iterator implementing batch_size = FrankWolfe.batchsize_iterate(batch_iterator) for algorithms like Variance-reduced and projection-free stochastic optimization, E Hazan, H Luo, 2016.

    Similarly, a constant momentum can be passed or replaced by a momentum_iterator implementing momentum = FrankWolfe.momentum_iterate(momentum_iterator).

    source
    FrankWolfe.block_coordinate_frank_wolfeFunction
    block_coordinate_frank_wolfe(f, grad!, lmo::ProductLMO{N}, x0; ...) where {N}

    Block-coordinate version of the Frank-Wolfe algorithm. Minimizes objective f over the product of feasible domains specified by the lmo. The optional argument the update_order is of type FrankWolfe.BlockCoordinateUpdateOrder and controls the order in which the blocks are updated. The argument update_step is a single instance or tuple of FrankWolfe.UpdateStep and defines which FW-algorithms to use to update the iterates in the different blocks.

    The method returns a tuple (x, v, primal, dual_gap, traj_data) with:

    • x cartesian product of final iterates
    • v cartesian product of last vertices of the LMOs
    • primal primal value f(x)
    • dual_gap final Frank-Wolfe gap
    • traj_data vector of trajectory information.

    See S. Lacoste-Julien, M. Jaggi, M. Schmidt, and P. Pletscher 2013 and A. Beck, E. Pauwels and S. Sabach 2015 for more details about Block-Coordinate Frank-Wolfe.

    source

    Active-set based methods

    The following algorithms maintain the representation of the iterates as a convex combination of vertices.

    Away-step

    Pairwise Frank-Wolfe

    Blended Conditional Gradient

    FrankWolfe.blended_conditional_gradientMethod
    blended_conditional_gradient(f, grad!, lmo, x0)

    Entry point for the Blended Conditional Gradient algorithm. See Braun, Gábor, et al. "Blended conditonal gradients" ICML 2019. The method works on an active set like FrankWolfe.away_frank_wolfe, performing gradient descent over the convex hull of active vertices, removing vertices when their weight drops to 0 and adding new vertices by calling the linear oracle in a lazy fashion.

    source
    FrankWolfe.build_reduced_problemMethod
    build_reduced_problem(atoms::AbstractVector{<:AbstractVector}, hessian, weights, gradient, tolerance)

    Given an active set formed by vectors , a (constant) Hessian and a gradient constructs a quadratic problem over the unit probability simplex that is equivalent to minimizing the original function over the convex hull of the active set. If λ are the barycentric coordinates of dimension equal to the cardinality of the active set, the objective function is:

    f(λ) = reduced_linear^T λ + 0.5 * λ^T reduced_hessian λ

    In the case where we find that the current iterate has a strong-Wolfe gap over the convex hull of the active set that is below the tolerance we return nothing (as there is nothing to do).

    source
    FrankWolfe.lp_separation_oracleMethod

    Returns either a tuple (y, val) with y an atom from the active set satisfying the progress criterion and val the corresponding gap dot(y, direction) or the same tuple with y from the LMO.

    inplace_loop controls whether the iterate type allows in-place writes. kwargs are passed on to the LMO oracle.

    source
    FrankWolfe.minimize_over_convex_hull!Method
    minimize_over_convex_hull!

    Given a function f with gradient grad! and an active set active_set this function will minimize the function over the convex hull of the active set until the strong-wolfe gap over the active set is below tolerance.

    It will either directly minimize over the convex hull using simplex gradient descent, or it will transform the problem to barycentric coordinates and minimize over the unit probability simplex using gradient descent or Nesterov's accelerated gradient descent.

    source
    FrankWolfe.simplex_gradient_descent_over_convex_hullMethod
    simplex_gradient_descent_over_convex_hull(f, grad!, gradient, active_set, tolerance, t, time_start, non_simplex_iter)

    Minimizes an objective function over the convex hull of the active set until the Strong-Wolfe gap is below tolerance using simplex gradient descent.

    source

    Blended Pairwise Conditional Gradient

    Alternating Methods

    Problems over intersections of convex sets, i.e.

    \[\min_{x \in \bigcap_{i=1}^n P_i} f(x),\]

    pose a challenge as one has to combine the information of two or more LMOs.

    FrankWolfe.alternating_linear_minimization converts the problem into a series of subproblems over single sets. To find a point within the intersection, one minimizes both the distance to the iterates of the other subproblems and the original objective function.

    FrankWolfe.alternating_projections solves feasibility problems over intersections of feasible regions.

    FrankWolfe.alternating_linear_minimizationMethod
    alternating_linear_minimization(bc_algo::BlockCoordinateMethod, f, grad!, lmos::NTuple{N,LinearMinimizationOracle}, x0; ...) where {N}

    Alternating Linear Minimization minimizes the objective f over the intersections of the feasible domains specified by lmos. The tuple x0 defines the initial points for each domain. Returns a tuple (x, v, primal, dual_gap, dist2, traj_data) with:

    • x cartesian product of final iterates
    • v cartesian product of last vertices of the LMOs
    • primal primal value f(x)
    • dual_gap final Frank-Wolfe gap
    • dist2 is 1/2 of the sum of squared, pairwise distances between iterates
    • traj_data vector of trajectory information.
    source
    FrankWolfe.alternating_projectionsMethod
    alternating_projections(lmos::NTuple{N,LinearMinimizationOracle}, x0; ...) where {N}

    Computes a point in the intersection of feasible domains specified by lmos. Returns a tuple (x, v, dual_gap, dist2, traj_data) with:

    • x cartesian product of final iterates
    • v cartesian product of last vertices of the LMOs
    • dual_gap final Frank-Wolfe gap
    • dist2 is 1/2 * sum of squared, pairwise distances between iterates
    • traj_data vector of trajectory information.
    source

    Index

      diff --git a/previews/PR539/reference/2_lmo/index.html b/previews/PR539/reference/2_lmo/index.html new file mode 100644 index 000000000..d17c49532 --- /dev/null +++ b/previews/PR539/reference/2_lmo/index.html @@ -0,0 +1,2 @@ + +Linear Minimization Oracles · FrankWolfe.jl

      Linear Minimization Oracles

      The Linear Minimization Oracle (LMO) is a key component called at each iteration of the FW algorithm. Given $d\in \mathcal{X}$, it returns a vertex of the feasible set:

      \[v\in \argmin_{x\in \mathcal{C}} \langle d,x \rangle.\]

      See Combettes, Pokutta 2021 for references on most LMOs implemented in the package and their comparison with projection operators.

      Interface and wrappers

      FrankWolfe.LinearMinimizationOracleType

      Supertype for linear minimization oracles.

      All LMOs must implement compute_extreme_point(lmo::LMO, direction) and return a vector v of the appropriate type.

      source

      All of them are subtypes of FrankWolfe.LinearMinimizationOracle and implement the following method:

      FrankWolfe.compute_extreme_pointFunction
      compute_extreme_point(lmo::LinearMinimizationOracle, direction; kwargs...)

      Computes the point argmin_{v ∈ C} v ⋅ direction with C the set represented by the LMO. Most LMOs feature v as a keyword argument that allows for an in-place computation whenever v is dense. All LMOs should accept keyword arguments that they can ignore.

      source

      We also provide some meta-LMOs wrapping another one with extended behavior:

      FrankWolfe.CachedLinearMinimizationOracleType
      CachedLinearMinimizationOracle{LMO}

      Oracle wrapping another one of type lmo. Subtypes of CachedLinearMinimizationOracle contain a cache of previous solutions.

      By convention, the inner oracle is named inner. Cached optimizers are expected to implement Base.empty! and Base.length.

      source
      FrankWolfe.SingleLastCachedLMOType
      SingleLastCachedLMO{LMO, VT}

      Caches only the last result from an LMO and stores it in last_vertex. Vertices of LMO have to be of type VT if provided.

      source
      FrankWolfe.MultiCacheLMOType
      MultiCacheLMO{N, LMO, A}

      Cache for a LMO storing up to N vertices in the cache, removed in FIFO style. oldest_idx keeps track of the oldest index in the tuple, i.e. to replace next. VT, if provided, must be the type of vertices returned by LMO

      source
      FrankWolfe.VectorCacheLMOType
      VectorCacheLMO{LMO, VT}

      Cache for a LMO storing an unbounded number of vertices of type VT in the cache. VT, if provided, must be the type of vertices returned by LMO

      source

      Norm balls

      FrankWolfe.EllipsoidLMOType
      EllipsoidLMO(A, c, r)

      Linear minimization over an ellipsoid centered at c of radius r:

      x: (x - c)^T A (x - c) ≤ r

      The LMO stores the factorization F of A that is used to solve linear systems A⁻¹ x. The result of the linear system solve is stored in buffer. The ellipsoid is assumed to be full-dimensional -> A is positive definite.

      source
      FrankWolfe.KNormBallLMOType
      KNormBallLMO{T}(K::Int, right_hand_side::T)

      LMO with feasible set being the K-norm ball in the sense of 2010.07243, i.e., the convex hull over the union of an L1-ball with radius τ and an L∞-ball with radius τ/K:

      C_{K,τ} = conv { B_1(τ) ∪ B_∞(τ / K) }

      with τ the right_hand_side parameter. The K-norm is defined as the sum of the largest K absolute entries in a vector.

      source
      FrankWolfe.LpNormLMOType
      LpNormLMO{T, p}(right_hand_side)

      LMO with feasible set being an L-p norm ball:

      C = {x ∈ R^n, norm(x, p) ≤ right_hand_side}
      source
      FrankWolfe.NuclearNormLMOType
      NuclearNormLMO{T}(radius)

      LMO over matrices that have a nuclear norm less than radius. The LMO returns the best rank-one approximation matrix with singular value radius, computed with Arpack.

      source
      FrankWolfe.OrderWeightNormLMOType
      OrderWeightNormLMO(weights,radius)

      LMO with feasible set being the atomic ordered weighted l1 norm: https://arxiv.org/pdf/1409.4271

      C = {x ∈ R^n, Ω_w(x) ≤ R} 

      The weights are assumed to be positive.

      source
      FrankWolfe.SpectraplexLMOType
      SpectraplexLMO{T,M}(radius::T,gradient_container::M,ensure_symmetry::Bool=true)

      Feasible set

      {X ∈ 𝕊_n^+, trace(X) == radius}

      gradient_container is used to store the symmetrized negative direction. ensure_symmetry indicates whether the linear function is made symmetric before computing the eigenvector.

      source
      FrankWolfe.UnitSpectrahedronLMOType
      UnitSpectrahedronLMO{T,M}(radius::T, gradient_container::M)

      Feasible set of PSD matrices with bounded trace:

      {X ∈ 𝕊_n^+, trace(X) ≤ radius}

      gradient_container is used to store the symmetrized negative direction. ensure_symmetry indicates whether the linear function is made symmetric before computing the eigenvector.

      source

      Simplex

      FrankWolfe.HyperSimplexOracleType
      HyperSimplexOracle(radius)

      Represents the scaled hypersimplex of radius τ, the convex hull of vectors v such that:

      • v_i ∈ {0, τ}
      • ||v||_0 = k

      Equivalently, this is the convex hull of the vertices of the K-sparse polytope lying in the nonnegative orthant.

      source
      FrankWolfe.UnitHyperSimplexOracleType
      UnitHyperSimplexOracle(radius)

      Represents the scaled unit hypersimplex of radius τ, the convex hull of vectors v such that:

      • v_i ∈ {0, τ}
      • ||v||_0 ≤ k

      Equivalently, this is the intersection of the K-sparse polytope and the nonnegative orthant.

      source
      FrankWolfe.compute_dual_solutionMethod

      Dual costs for a given primal solution to form a primal dual pair for scaled probability simplex. Returns two vectors. The first one is the dual costs associated with the constraints and the second is the reduced costs for the variables.

      source
      FrankWolfe.compute_dual_solutionMethod

      Dual costs for a given primal solution to form a primal dual pair for scaled unit simplex. Returns two vectors. The first one is the dual costs associated with the constraints and the second is the reduced costs for the variables.

      source
      FrankWolfe.compute_extreme_pointMethod

      LMO for scaled probability simplex. Returns a vector with one active value equal to RHS in the most improving (or least degrading) direction.

      source
      FrankWolfe.compute_extreme_pointMethod

      LMO for scaled unit simplex: ∑ x_i ≤ τ Returns either vector of zeros or vector with one active value equal to RHS if there exists an improving direction.

      source

      Polytope

      FrankWolfe.BirkhoffPolytopeLMOType
      BirkhoffPolytopeLMO

      The Birkhoff polytope encodes doubly stochastic matrices. Its extreme vertices are all permutation matrices of side-dimension dimension.

      source
      FrankWolfe.KSparseLMOType
      KSparseLMO{T}(K::Int, right_hand_side::T)

      LMO for the K-sparse polytope:

      C = B_1(τK) ∩ B_∞(τ)

      with τ the right_hand_side parameter. The LMO results in a vector with the K largest absolute values of direction, taking values -τ sign(x_i).

      source
      FrankWolfe.ScaledBoundL1NormBallType
      ScaledBoundL1NormBall(lower_bounds, upper_bounds)

      Polytope similar to a L1-ball with shifted bounds. It is the convex hull of two scaled and shifted unit vectors for each axis (shifted to the center of the polytope, i.e., the elementwise midpoint of the bounds). Lower and upper bounds are passed on as abstract vectors, possibly of different types. For the standard L1-ball, all lower and upper bounds would be -1 and 1.

      source
      FrankWolfe.ScaledBoundLInfNormBallType
      ScaledBoundLInfNormBall(lower_bounds, upper_bounds)

      Polytope similar to a L-inf-ball with shifted bounds or general box constraints. Lower- and upper-bounds are passed on as abstract vectors, possibly of different types. For the standard L-inf ball, all lower- and upper-bounds would be -1 and 1.

      source

      MathOptInterface

      FrankWolfe.MathOptLMOType
      MathOptLMO{OT <: MOI.AbstractOptimizer} <: LinearMinimizationOracle

      Linear minimization oracle with feasible space defined through a MathOptInterface.Optimizer. The oracle call sets the direction and reruns the optimizer.

      The direction vector has to be set in the same order of variables as the MOI.ListOfVariableIndices() getter.

      The Boolean use_modify determines if the objective incompute_extreme_point is updated with MOI.modify(o, ::MOI.ObjectiveFunction, ::MOI.ScalarCoefficientChange) or with MOI.set(o, ::MOI.ObjectiveFunction, f). use_modify = true decreases the runtime and memory allocation for models created as an optimizer object and defined directly with MathOptInterface. use_modify = false should be used for CachingOptimizers.

      source
      FrankWolfe.convert_mathoptFunction
      convert_mathopt(lmo::LMO, optimizer::OT; kwargs...) -> MathOptLMO{OT}

      Converts the given LMO to its equivalent MathOptInterface representation using optimizer. Must be implemented by LMOs.

      source

      Index

        diff --git a/previews/PR539/reference/3_backend/index.html b/previews/PR539/reference/3_backend/index.html new file mode 100644 index 000000000..aeb343992 --- /dev/null +++ b/previews/PR539/reference/3_backend/index.html @@ -0,0 +1,28 @@ + +Utilities and data structures · FrankWolfe.jl

        Utilities and data structures

        Active set

        FrankWolfe.AbstractActiveSetType
        AbstractActiveSet{AT, R, IT}

        Abstract type for an active set of atoms of type AT with weights of type R and iterate of type IT. An active set is typically expected to have a field weights, a field atoms, and a field x. Otherwise, all active set methods from src/active_set.jl can be overwritten.

        source
        FrankWolfe.ActiveSetType
        ActiveSet{AT, R, IT}

        Represents an active set of extreme vertices collected in a FW algorithm, along with their coefficients (λ_i, a_i). R is the type of the λ_i, AT is the type of the atoms a_i. The iterate x = ∑λ_i a_i is stored in x with type IT.

        source
        Base.copyMethod

        Copies an active set, the weight and atom vectors and the iterate. Individual atoms are not copied.

        source
        FrankWolfe.active_set_argminMethod
        active_set_argmin(active_set::AbstractActiveSet, direction)

        Computes the linear minimizer in the direction on the active set. Returns (λ_i, a_i, i)

        source
        FrankWolfe.active_set_argminmaxMethod
        active_set_argminmax(active_set::AbstractActiveSet, direction)

        Computes the linear minimizer in the direction on the active set. Returns (λ_min, a_min, i_min, val_min, λ_max, a_max, i_max, val_max, val_max-val_min ≥ Φ)

        source
        FrankWolfe.active_set_update!Method
        active_set_update!(active_set::AbstractActiveSet, lambda, atom)

        Adds the atom to the active set with weight lambda or adds lambda to existing atom.

        source
        FrankWolfe.compute_active_set_iterate!Method
        compute_active_set_iterate!(active_set::AbstractActiveSet) -> x

        Recomputes from scratch the iterate x from the current weights and vertices of the active set. Returns the iterate x.

        source
        FrankWolfe.ActiveSetQuadraticProductCachingType
        ActiveSetQuadraticProductCaching{AT, R, IT}

        Represents an active set of extreme vertices collected in a FW algorithm, along with their coefficients (λ_i, a_i). R is the type of the λ_i, AT is the type of the atoms a_i. The iterate x = ∑λ_i a_i is stored in x with type IT. The objective function is assumed to be of the form f(x)=½⟨x,Ax⟩+⟨b,x⟩+c so that the gradient is simply ∇f(x)=Ax+b.

        source
        FrankWolfe.ActiveSetQuadraticLinearSolveType
        ActiveSetQuadraticLinearSolve{AT, R, IT}

        Represents an active set of extreme vertices collected in a FW algorithm, along with their coefficients (λ_i, a_i). R is the type of the λ_i, AT is the type of the atoms a_i. The iterate x = ∑λ_i a_i is stored in x with type IT. The objective function is assumed to be of the form f(x)=½⟨x,Ax⟩+⟨b,x⟩+c so that the gradient is ∇f(x)=Ax+b.

        This active set stores an inner active_set that keeps track of the current set of vertices and convex decomposition. It therefore delegates all update, deletion, and addition operations to this inner active set. The weight, atoms, and x fields should only be accessed to read and are effectively the same objects as those in the inner active set. The flag wolfe_step determines whether to use a Wolfe step from the min-norm point algorithm or the normal direct solve. The Wolfe step solves the auxiliary subproblem over the affine hull of the current active set (instead of the convex hull).

        The structure also contains a scheduler struct which is called with the should_solve_lp function. To define a new frequency at which the LP should be solved, one can define another scheduler struct and implement the corresponding method.

        source
        FrankWolfe.ActiveSetQuadraticLinearSolveMethod
        ActiveSetQuadraticLinearSolve(tuple_values::Vector{Tuple{R,AT}}, A, b, lp_optimizer)

        Creates an ActiveSetQuadraticLinearSolve from the given Hessian A, linear term b and lp_optimizer by creating an inner ActiveSetQuadraticProductCaching active set.

        source
        FrankWolfe.ActiveSetQuadraticLinearSolveMethod
        ActiveSetQuadraticLinearSolve(tuple_values::Vector{Tuple{R,AT}}, grad!::Function, lp_optimizer)

        Creates an ActiveSetQuadraticLinearSolve by computing the Hessian and linear term from grad!.

        source
        FrankWolfe.solve_quadratic_activeset_lp!Method
        solve_quadratic_activeset_lp!(as::ActiveSetQuadraticLinearSolve{AT, R, IT, H}))

        Solves the auxiliary LP over the current active set. The method is specialized by type H of the Hessian matrix A.

        source

        Functions and gradients

        FrankWolfe.ObjectiveFunctionType
        ObjectiveFunction

        Represents an objective function optimized by algorithms. Subtypes of ObjectiveFunction must implement at least

        • compute_value(::ObjectiveFunction, x) for primal value evaluation
        • compute_gradient(::ObjectiveFunction, x) for gradient evaluation.

        and optionally compute_value_gradient(::ObjectiveFunction, x) returning the (primal, gradient) pair. compute_gradient may always use the same storage and return a reference to it.

        source
        FrankWolfe.SimpleFunctionObjectiveType
        SimpleFunctionObjective{F,G,S}

        An objective function built from separate primal objective f(x) and in-place gradient function grad!(storage, x). It keeps an internal storage of type s used to evaluate the gradient in-place.

        source
        FrankWolfe.StochasticObjectiveType
        StochasticObjective{F, G, XT, S}(f::F, grad!::G, xs::XT, storage::S)

        Represents a composite function evaluated with stochastic gradient. f(θ, x) evaluates the loss for a single data point x and parameter θ. grad!(storage, θ, x) adds to storage the partial gradient with respect to data point x at parameter θ. xs must be an indexable iterable (Vector{Vector{Float64}} for instance). Functions using a StochasticObjective have optional keyword arguments rng, batch_size and full_evaluation controlling whether the function should be evaluated over all data points.

        Note: grad! must not reset the storage to 0 before adding to it.

        source
        FrankWolfe.compute_gradientFunction
        compute_gradient(f::ObjectiveFunction, x; [kwargs...])

        Computes the gradient of f at x. May return a reference to an internal storage.

        source
        FrankWolfe.compute_value_gradientMethod
        compute_value_gradient(f::ObjectiveFunction, x; [kwargs...])

        Computes in one call the pair (value, gradient) evaluated at x. By default, calls compute_value and compute_gradient with keywords kwargs passed down to both.

        source

        Callbacks

        Custom vertex storage

        Custom extreme point types

        For some feasible sets, the extreme points of the feasible set returned by the LMO possess a specific structure that can be represented in an efficient manner both for storage and for common operations like scaling and addition with an iterate. They are presented below:

        FrankWolfe.SubspaceVectorType
        SubspaceVector{HasMultiplicities, T}

        Companion structure of SubspaceLMO containing three fields:

        • data is the full structure to be deflated,
        • vec is a vector in the reduced subspace in which computations are performed,
        • mul is only used to compute scalar products when HasMultiplicities = true,

        which should be avoided (when possible) for performance reasons.

        source

        Utils

        FrankWolfe.DeletedVertexStorageType

        Vertex storage to store dropped vertices or find a suitable direction in lazy settings. The algorithm will look for at most return_kth suitable atoms before returning the best. See Extra-lazification with a vertex storage for usage.

        A vertex storage can be any type that implements two operations:

        1. Base.push!(storage, atom) to add an atom to the storage.

        Note that it is the storage type responsibility to ensure uniqueness of the atoms present.

        1. storage_find_argmin_vertex(storage, direction, lazy_threshold) -> (found, vertex)

        returning whether a vertex with sufficient progress was found and the vertex. It is up to the storage to remove vertices (or not) when they have been picked up.

        source
        FrankWolfe.ExpMomentumIteratorType
        ExpMomentumIterator{T}

        Iterator for the momentum used in the variant of Stochastic Frank-Wolfe. Momentum coefficients are the values of the iterator: ρ_t = 1 - num / (offset + t)^exp

        The state corresponds to the iteration count.

        Source: Stochastic Conditional Gradient Methods: From Convex Minimization to Submodular Maximization Aryan Mokhtari, Hamed Hassani, Amin Karbasi, JMLR 2020.

        source
        FrankWolfe.IncrementBatchIteratorType
        IncrementBatchIterator(starting_batch_size, max_batch_size, [increment = 1])

        Batch size starting at startingbatchsize and incrementing by increment at every iteration.

        source
        FrankWolfe.batchsize_iterateFunction
        batchsize_iterate(iter::BatchSizeIterator) -> b

        Method to implement for a batch size iterator of type BatchSizeIterator. Calling batchsize_iterate returns the next batch size and typically update the internal state of iter.

        source
        FrankWolfe.momentum_iterateFunction
        momentum_iterate(iter::MomentumIterator) -> ρ

        Method to implement for a type MomentumIterator. Returns the next momentum value ρ and updates the iterator internal state.

        source
        FrankWolfe.muladd_memory_modeMethod
        (memory_mode::MemoryEmphasis, storage, x, gamma::Real, d)

        Performs storage = x - gamma * d in-place or not depending on MemoryEmphasis

        source
        FrankWolfe.trajectory_callbackMethod
        trajectory_callback(storage)

        Callback pushing the state at each iteration to the passed storage. The state data is only the 5 first fields, usually: (t,primal,dual,dual_gap,time)

        source

        Oracle counting trackers

        The following structures are wrapping given oracles to behave similarly but additionally track the number of calls.

        Also see the example Tracking, counters and custom callbacks for Frank Wolfe.

        Update order for block-coordinate methods

        Block-coordinate methods can be run with different update orders. All update orders are subtypes of FrankWolfe.BlockCoordinateUpdateOrder. They have to implement the method FrankWolfe.select_update_indices which selects which blocks to update in what order.

        FrankWolfe.BlockCoordinateUpdateOrderType

        Update order for a block-coordinate method. A BlockCoordinateUpdateOrder must implement

        select_update_indices(::BlockCoordinateUpdateOrder, s::CallbackState, dual_gaps)
        source
        FrankWolfe.select_update_indicesFunction
        select_update_indices(::BlockCoordinateUpdateOrder, s::CallbackState, dual_gaps)

        Returns a list of lists of the block indices. Each sublist represents one round of updates in an iteration. The indices in a list show which blocks should be updated parallely in one round. For example, a full update is given by [1:l] and a blockwise update by [[i] for i=1:l], where l is the number of blocks.

        source
        FrankWolfe.CyclicUpdateType

        The cyclic update initiates a sequence of update rounds. In each round only one block is updated. The order of the blocks is determined by the given order of the LMOs.

        source
        FrankWolfe.StochasticUpdateType

        The stochastic update initiates a sequence of update rounds. In each round only one block is updated. The order of the blocks is a random.

        source
        FrankWolfe.LazyUpdateType

        The Lazy update order is discussed in "Flexible block-iterative analysis for the Frank-Wolfe algorithm," by Braun, Pokutta, & Woodstock (2024). 'lazyblock' is an index of a computationally expensive block to update; 'refreshrate' describes the frequency at which we perform a full activation; and 'blocksize' describes the number of "faster" blocks (i.e., those excluding 'lazyblock') activated (chosen uniformly at random) during each of the "faster" iterations; for more detail, see the article. If 'block_size' is unspecified, this defaults to

        Note: This methodology is currently only proven to work with 'FrankWolfe.Shortstep' linesearches and a (not-yet implemented) adaptive method; see the article for details.

        source

        Update step for block-coordinate Frank-Wolfe

        Block-coordinate Frank-Wolfe (BCFW) can run different FW algorithms on different blocks. All update steps are subtypes of FrankWolfe.UpdateStep and implement FrankWolfe.update_iterate which defines one iteration of the corresponding method.

        FrankWolfe.UpdateStepType

        Update step for block-coordinate Frank-Wolfe. These are implementations of different FW-algorithms to be used in a blockwise manner. Each update step must implement

        update_iterate(
        +    step::UpdateStep,
        +    x,
        +    lmo,
        +    f,
        +    gradient,
        +    grad!,
        +    dual_gap,
        +    t,
        +    line_search,
        +    linesearch_workspace,
        +    memory_mode,
        +    epsilon,
        +)
        source
        FrankWolfe.update_iterateFunction
        update_iterate(
        +    step::UpdateStep,
        +    x,
        +    lmo,
        +    f,
        +    gradient,
        +    grad!,
        +    dual_gap,
        +    t,
        +    line_search,
        +    linesearch_workspace,
        +    memory_mode,
        +    epsilon,
        +)

        Executes one iteration of the defined FrankWolfe.UpdateStep and updates the iterate x implicitly. The function returns a tuple (dual_gap, v, d, gamma, step_type):

        • dual_gap is the updated FrankWolfe gap
        • v is the used vertex
        • d is the update direction
        • gamma is the applied step-size
        • step_type is the applied step-type
        source
        FrankWolfe.BPCGStepType

        Implementation of the blended pairwise conditional gradient (BPCG) method as an update step for block-coordinate Frank-Wolfe.

        source

        Block vector

        FrankWolfe.BlockVectorType
        BlockVector{T, MT <: AbstractArray{T}, ST <: Tuple} <: AbstractVector{T}

        Represents a vector consisting of blocks. T is the element type of the vector, MT is the type of the underlying data array, and ST is the type of the tuple representing the sizes of each block. Each block can be accessed with the blocks field, and the sizes of the blocks are stored in the block_sizes field.

        source

        Index

        diff --git a/previews/PR539/reference/4_linesearch/index.html b/previews/PR539/reference/4_linesearch/index.html new file mode 100644 index 000000000..8fd726eda --- /dev/null +++ b/previews/PR539/reference/4_linesearch/index.html @@ -0,0 +1,2 @@ + +Line search and step size settings · FrankWolfe.jl

        Line search and step size settings

        The step size dictates how far one traverses along a local descent direction. More specifically, the step size $\gamma_t$ is used at each iteration to determine how much the next iterate moves towards the new vertex:

        \[x_{t+1} = x_t - \gamma_t (x_t - v_t).\]

        $\gamma_t = 1$ implies that the next iterate is exactly the vertex, a zero $\gamma_t$ implies that the iterate is not moving.

        The following are step size selection rules for Frank Wolfe algorithms. Some methodologies (e.g. FixedStep and Agnostic) depend only on the iteration number and induce series $\gamma_t$ that are independent of the problem data, while others (e.g. GoldenSearch and Adaptive) change according to local information about the function; the adaptive methods often require extra function and/or gradient computations. The typical options for convex optimization are Agnostic or Adaptive.

        All step size computation strategies are subtypes of FrankWolfe.LineSearchMethod. The key method they have to implement is FrankWolfe.perform_line_search which is called at every iteration to compute the step size gamma.

        FrankWolfe.LineSearchMethodType

        Line search method to apply once the direction is computed. A LineSearchMethod must implement

        perform_line_search(ls::LineSearchMethod, t, f, grad!, gradient, x, d, gamma_max, workspace)

        with d = x - v. It may also implement build_linesearch_workspace(x, gradient) which creates a workspace structure that is passed as last argument to perform_line_search.

        source
        FrankWolfe.perform_line_searchFunction
        perform_line_search(ls::LineSearchMethod, t, f, grad!, gradient, x, d, gamma_max, workspace)

        Returns the step size gamma for step size strategy ls.

        source
        FrankWolfe.AdaptiveType

        Modified adaptive line search test from:

        S. Pokutta "The Frank-Wolfe algorith: a short introduction" (2023), preprint, https://arxiv.org/abs/2311.05313

        It replaces the original test implemented in the AdaptiveZerothOrder line search based on:

        Pedregosa, F., Negiar, G., Askari, A., and Jaggi, M. (2020). "Linearly convergent Frank–Wolfe with backtracking line-search", Proceedings of AISTATS.

        source
        FrankWolfe.AdaptiveZerothOrderType

        Slight modification of the Adaptive Step Size strategy from Pedregosa, Negiar, Askari, Jaggi (2018)

        \[ f(x_t + \gamma_t (x_t - v_t)) - f(x_t) \leq - \alpha \gamma_t \langle \nabla f(x_t), x_t - v_t \rangle + \alpha^2 \frac{\gamma_t^2 \|x_t - v_t\|^2}{2} M ~.\]

        The parameter alpha ∈ (0,1] relaxes the original smoothness condition to mitigate issues with nummerical errors. Its default value is 0.5. The Adaptive struct keeps track of the Lipschitz constant estimate L_est. The keyword argument relaxed_smoothness allows testing with an alternative smoothness condition,

        \[ \langle \nabla f(x_t + \gamma_t (x_t - v_t) ) - \nabla f(x_t), x_t - v_t \rangle \leq \gamma_t M \|x_t - v_t\|^2 ~.\]

        This condition yields potentially smaller and more stable estimations of the Lipschitz constant while being more computationally expensive due to the additional gradient computation.

        It is also the fallback when the Lipschitz constant estimation fails due to numerical errors. perform_line_search also has a should_upgrade keyword argument on whether there should be a temporary upgrade to BigFloat for extended precision.

        source
        FrankWolfe.AgnosticType

        Computes step size: l/(l + t) at iteration t, given l > 0.

        Using l > 2 leads to faster convergence rates than l = 2 over strongly and some uniformly convex set.

        Accelerated Affine-Invariant Convergence Rates of the Frank-Wolfe Algorithm with Open-Loop Step-Sizes, Wirth, Peña, Pokutta (2023), https://arxiv.org/abs/2310.04096

        See also the paper that introduced the study of open-loop step-sizes with l > 2:

        Acceleration of Frank-Wolfe Algorithms with Open-Loop Step-Sizes, Wirth, Kerdreux, Pokutta, (2023), https://arxiv.org/abs/2205.12838

        Fixing l = -1, results in the step size gamma_t = (2 + log(t+1)) / (t + 2 + log(t+1))

        S. Pokutta "The Frank-Wolfe algorith: a short introduction" (2023), https://arxiv.org/abs/2311.05313

        source
        FrankWolfe.GeneralizedAgnosticType

        Computes step size: g(t)/(t + g(t)) at iteration t, given g: R_{>= 0} -> R_{>= 0}.

        Defaults to the best open-loop step-size gamma_t = (2 + log(t+1)) / (t + 2 + log(t+1))

        S. Pokutta "The Frank-Wolfe algorith: a short introduction" (2023), https://arxiv.org/abs/2311.05313

        This step-size is as fast as the step-size gammat = 2 / (t + 2) up to polylogarithmic factors. Further, over strongly convex and some uniformly convex sets, it is faster than any traditional step-size gammat = l / (t + l) for any l in N.

        source
        FrankWolfe.MonotonicNonConvexStepSizeType
        MonotonicNonConvexStepSize{F}

        Represents a monotonic open-loop non-convex step size. Contains a halving factor N increased at each iteration until there is primal progress gamma = 1 / sqrt(t + 1) * 2^(-N).

        source
        FrankWolfe.MonotonicStepSizeType
        MonotonicStepSize{F}

        Represents a monotonic open-loop step size. Contains a halving factor N increased at each iteration until there is primal progress gamma = 2 / (t + 2) * 2^(-N).

        source
        FrankWolfe.SecantType
        Secant(limit_num_steps, tol, domain_oracle)

        Secant line search strategy, which iteratively refines the step size using the secant method. This method is geared towards problems with self-concordant functions (but might require extra structure) and potentially faster than the backtracking line search. The order of convergence is superlinear with exponent 1.618 (Golden Ratio) but not quite quadratic. Convergence is not guaranteed in general.

        Arguments

        • inner_ls::LSM: A fallback line search in case the last gamma in Secant does not satisfy the tolerance. Is only used if safe==true. (default Backtracking)
        • safe::Bool: Flag indicating whether the fallback line search should be used. If false, the best gamma from Secant is used. (default true)
        • limit_num_steps::Int: Maximum number of iterations for the secant method. (default 40)
        • tol::Float64: Tolerance for convergence. (default 1e-8)
        • domain_oracle::Function, returns true if the argument x is in the domain of the objective function f.

        References

        source
        FrankWolfe.ShortstepType

        Computes the 'Short step' step size: dual_gap / (L * norm(x - v)^2), where L is the Lipschitz constant of the gradient, x is the current iterate, and v is the current Frank-Wolfe vertex.

        source

        See Pedregosa, Negiar, Askari, Jaggi (2020) for the adaptive step size, Carderera, Besançon, Pokutta (2021) for the monotonic step size.

        Index

        diff --git a/previews/PR539/search/index.html b/previews/PR539/search/index.html new file mode 100644 index 000000000..5015a574a --- /dev/null +++ b/previews/PR539/search/index.html @@ -0,0 +1,2 @@ + +Search · FrankWolfe.jl diff --git a/previews/PR539/search_index.js b/previews/PR539/search_index.js new file mode 100644 index 000000000..a25e363a2 --- /dev/null +++ b/previews/PR539/search_index.js @@ -0,0 +1,3 @@ +var documenterSearchIndex = {"docs": +[{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"EditURL = \"../../../examples/docs_09_extra_vertex_storage.jl\"","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/#Extra-lazification","page":"Extra-lazification","title":"Extra-lazification","text":"","category":"section"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"Sometimes the Frank-Wolfe algorithm will be run multiple times with slightly different settings under which vertices collected in a previous run are still valid.","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"The extra-lazification feature can be used for this purpose. It consists of a storage that can collect dropped vertices during a run, and the ability to use these vertices in another run, when they are not part of the current active set. The vertices that are part of the active set do not need to be duplicated in the extra-lazification storage. The extra-vertices can be used instead of calling the LMO when it is a relatively expensive operation.","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"using FrankWolfe\nusing Test\nusing LinearAlgebra","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"We will use a parameterized objective function 12 x - c^2 over the unit simplex.","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"const n = 100\nconst center0 = 5.0 .+ 3 * rand(n)\nf(x) = 0.5 * norm(x .- center0)^2\nfunction grad!(storage, x)\n return storage .= x .- center0\nend","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"The TrackingLMO will let us count how many real calls to the LMO are performed by a single run of the algorithm.","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"lmo = FrankWolfe.UnitSimplexOracle(4.3)\ntlmo = FrankWolfe.TrackingLMO(lmo)\nx0 = FrankWolfe.compute_extreme_point(lmo, randn(n));\nnothing #hide","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/#Adding-a-vertex-storage","page":"Extra-lazification","title":"Adding a vertex storage","text":"","category":"section"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"FrankWolfe offers a simple FrankWolfe.DeletedVertexStorage storage type which has as parameter return_kth, the number of good directions to find before returning the best. return_kth larger than the number of vertices means that the best-aligned vertex will be found. return_kth = 1 means the first acceptable vertex (with the specified threhsold) is returned.","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"See FrankWolfe.DeletedVertexStorage","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"vertex_storage = FrankWolfe.DeletedVertexStorage(typeof(x0)[], 5)\ntlmo.counter = 0\n\nresults = FrankWolfe.blended_pairwise_conditional_gradient(\n f,\n grad!,\n tlmo,\n x0,\n max_iteration=4000,\n verbose=true,\n lazy=true,\n epsilon=1e-5,\n add_dropped_vertices=true,\n extra_vertex_storage=vertex_storage,\n)","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"The counter indicates the number of initial calls to the LMO. We will now construct different objective functions based on new centers, call the BPCG algorithm while accumulating vertices in the storage, in addition to warm-starting with the active set of the previous iteration. This allows for a \"double-warmstarted\" algorithm, reducing the number of LMO calls from one problem to the next.","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"active_set = results[end]\ntlmo.counter\n\nfor iter in 1:10\n center = 5.0 .+ 3 * rand(n)\n f_i(x) = 0.5 * norm(x .- center)^2\n function grad_i!(storage, x)\n return storage .= x .- center\n end\n tlmo.counter = 0\n FrankWolfe.blended_pairwise_conditional_gradient(\n f_i,\n grad_i!,\n tlmo,\n active_set,\n max_iteration=4000,\n lazy=true,\n epsilon=1e-5,\n add_dropped_vertices=true,\n use_extra_vertex_storage=true,\n extra_vertex_storage=vertex_storage,\n verbose=false,\n )\n @info \"Number of LMO calls in iter $iter: $(tlmo.counter)\"\n @info \"Vertex storage size: $(length(vertex_storage.storage))\"\nend","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"","category":"page"},{"location":"examples/docs_09_extra_vertex_storage/","page":"Extra-lazification","title":"Extra-lazification","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"EditURL = \"../../../examples/docs_02_polynomial_regression.jl\"","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_02_polynomial_regression/#Polynomial-Regression","page":"Polynomial Regression","title":"Polynomial Regression","text":"","category":"section"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"The following example features the LMO for polynomial regression on the ell_1 norm ball. Given input/output pairs x_iy_i_i=1^N and sparse coefficients c_j, where","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"y_i=sum_j=1^m c_j f_j(x_i)","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"and f_j mathbbR^ntomathbbR, the task is to recover those c_j that are non-zero alongside their corresponding values. Under certain assumptions, this problem can be convexified into","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"min_cinmathcalCy-Ac^2","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"for a convex set mathcalC. It can also be found as example 4.1 in the paper. In order to evaluate the polynomial, we generate a total of 1000 data points x_i_i=1^N from the standard multivariate Gaussian, with which we will compute the output variables y_i_i=1^N. Before evaluating the polynomial, these points will be contaminated with noise drawn from a standard multivariate Gaussian. We run the away_frank_wolfe and blended_conditional_gradient algorithms, and compare them to Projected Gradient Descent using a smoothness estimate. We will evaluate the output solution on test points drawn in a similar manner as the training points.","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"using FrankWolfe\n\nusing LinearAlgebra\nimport Random\n\nusing MultivariatePolynomials\nusing DynamicPolynomials\n\nusing Plots\n\nusing LaTeXStrings\n\nconst N = 10\n\nDynamicPolynomials.@polyvar X[1:15]\n\nconst max_degree = 4\ncoefficient_magnitude = 10\nnoise_magnitude = 1\n\nconst var_monomials = MultivariatePolynomials.monomials(X, 0:max_degree)\n\nRandom.seed!(42)\nconst all_coeffs = map(var_monomials) do m\n d = MultivariatePolynomials.degree(m)\n return coefficient_magnitude * rand() .* (rand() .> 0.95 * d / max_degree)\nend\n\nconst true_poly = dot(all_coeffs, var_monomials)\n\nconst training_data = map(1:500) do _\n x = 0.1 * randn(N)\n y = MultivariatePolynomials.subs(true_poly, Pair(X, x)) + noise_magnitude * randn()\n return (x, y.a[1])\nend\n\nconst extended_training_data = map(training_data) do (x, y)\n x_ext = MultivariatePolynomials.coefficient.(MultivariatePolynomials.subs.(var_monomials, X => x))\n return (x_ext, y)\nend\n\nconst test_data = map(1:1000) do _\n x = 0.4 * randn(N)\n y = MultivariatePolynomials.subs(true_poly, Pair(X, x)) + noise_magnitude * randn()\n return (x, y.a[1])\nend\n\nconst extended_test_data = map(test_data) do (x, y)\n x_ext = MultivariatePolynomials.coefficient.(MultivariatePolynomials.subs.(var_monomials, X => x))\n return (x_ext, y)\nend\n\nfunction f(coefficients)\n return 0.5 / length(extended_training_data) * sum(extended_training_data) do (x, y)\n return (dot(coefficients, x) - y)^2\n end\nend\n\nfunction f_test(coefficients)\n return 0.5 / length(extended_test_data) * sum(extended_test_data) do (x, y)\n return (dot(coefficients, x) - y)^2\n end\nend\n\nfunction coefficient_errors(coeffs)\n return 0.5 * sum(eachindex(all_coeffs)) do idx\n return (all_coeffs[idx] - coeffs[idx])^2\n end\nend\n\nfunction grad!(storage, coefficients)\n storage .= 0\n for (x, y) in extended_training_data\n p_i = dot(coefficients, x) - y\n @. storage += x * p_i\n end\n storage ./= length(training_data)\n return nothing\nend\n\nfunction build_callback(trajectory_arr)\n return function callback(state, args...)\n return push!(\n trajectory_arr,\n (FrankWolfe.callback_state(state)..., f_test(state.x), coefficient_errors(state.x)),\n )\n end\nend\n\ngradient = similar(all_coeffs)\n\nmax_iter = 10000\nrandom_initialization_vector = rand(length(all_coeffs))\n\nlmo = FrankWolfe.LpNormLMO{1}(0.95 * norm(all_coeffs, 1))\n\n# Estimating smoothness parameter\nnum_pairs = 1000\nL_estimate = -Inf\ngradient_aux = similar(gradient)\n\nfor i in 1:num_pairs # hide\n global L_estimate # hide\n x = compute_extreme_point(lmo, randn(size(all_coeffs))) # hide\n y = compute_extreme_point(lmo, randn(size(all_coeffs))) # hide\n grad!(gradient, x) # hide\n grad!(gradient_aux, y) # hide\n new_L = norm(gradient - gradient_aux) / norm(x - y) # hide\n if new_L > L_estimate # hide\n L_estimate = new_L # hide\n end # hide\nend # hide\n\nfunction projnorm1(x, τ)\n n = length(x)\n if norm(x, 1) ≤ τ\n return x\n end\n u = abs.(x)\n # simplex projection\n bget = false\n s_indices = sortperm(u, rev=true)\n tsum = zero(τ)\n\n @inbounds for i in 1:n-1\n tsum += u[s_indices[i]]\n tmax = (tsum - τ) / i\n if tmax ≥ u[s_indices[i+1]]\n bget = true\n break\n end\n end\n if !bget\n tmax = (tsum + u[s_indices[n]] - τ) / n\n end\n\n @inbounds for i in 1:n\n u[i] = max(u[i] - tmax, 0)\n u[i] *= sign(x[i])\n end\n return u\nend\nxgd = FrankWolfe.compute_extreme_point(lmo, random_initialization_vector) # hide\ntraining_gd = Float64[] # hide\ntest_gd = Float64[] # hide\ncoeff_error = Float64[] # hide\ntime_start = time_ns() # hide\ngd_times = Float64[] # hide\nfor iter in 1:max_iter # hide\n global xgd # hide\n grad!(gradient, xgd) # hide\n xgd = projnorm1(xgd - gradient / L_estimate, lmo.right_hand_side) # hide\n push!(training_gd, f(xgd)) # hide\n push!(test_gd, f_test(xgd)) # hide\n push!(coeff_error, coefficient_errors(xgd)) # hide\n push!(gd_times, (time_ns() - time_start) * 1e-9) # hide\nend # hide\n\nx00 = FrankWolfe.compute_extreme_point(lmo, random_initialization_vector) # hide\nx0 = deepcopy(x00) # hide\n\ntrajectory_lafw = [] # hide\ncallback = build_callback(trajectory_lafw) # hide\nx_lafw, v, primal, dual_gap, _ = FrankWolfe.away_frank_wolfe( # hide\n f, # hide\n grad!, # hide\n lmo, # hide\n x0, # hide\n max_iteration=max_iter, # hide\n line_search=FrankWolfe.Adaptive(L_est=L_estimate), # hide\n print_iter=max_iter ÷ 10, # hide\n memory_mode=FrankWolfe.InplaceEmphasis(), # hide\n verbose=false, # hide\n lazy=true, # hide\n gradient=gradient, # hide\n callback=callback, # hide\n) # hide\n\ntrajectory_bcg = [] # hide\ncallback = build_callback(trajectory_bcg) # hide\nx0 = deepcopy(x00) # hide\nx_bcg, v, primal, dual_gap, _, _ = FrankWolfe.blended_conditional_gradient( # hide\n f, # hide\n grad!, # hide\n lmo, # hide\n x0, # hide\n max_iteration=max_iter, # hide\n line_search=FrankWolfe.Adaptive(L_est=L_estimate), # hide\n print_iter=max_iter ÷ 10, # hide\n memory_mode=FrankWolfe.InplaceEmphasis(), # hide\n verbose=false, # hide\n weight_purge_threshold=1e-10, # hide\n callback=callback, # hide\n) # hide\nx0 = deepcopy(x00) # hide\ntrajectory_lafw_ref = [] # hide\ncallback = build_callback(trajectory_lafw_ref) # hide\n_, _, primal_ref, _, _ = FrankWolfe.away_frank_wolfe( # hide\n f, # hide\n grad!, # hide\n lmo, # hide\n x0, # hide\n max_iteration=2 * max_iter, # hide\n line_search=FrankWolfe.Adaptive(L_est=L_estimate), # hide\n print_iter=max_iter ÷ 10, # hide\n memory_mode=FrankWolfe.InplaceEmphasis(), # hide\n verbose=false, # hide\n lazy=true, # hide\n gradient=gradient, # hide\n callback=callback, # hide\n) # hide\n\n\nfor i in 1:num_pairs\n global L_estimate\n x = compute_extreme_point(lmo, randn(size(all_coeffs)))\n y = compute_extreme_point(lmo, randn(size(all_coeffs)))\n grad!(gradient, x)\n grad!(gradient_aux, y)\n new_L = norm(gradient - gradient_aux) / norm(x - y)\n if new_L > L_estimate\n L_estimate = new_L\n end\nend","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"We can now perform projected gradient descent:","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"xgd = FrankWolfe.compute_extreme_point(lmo, random_initialization_vector)\ntraining_gd = Float64[]\ntest_gd = Float64[]\ncoeff_error = Float64[]\ntime_start = time_ns()\ngd_times = Float64[]\nfor iter in 1:max_iter\n global xgd\n grad!(gradient, xgd)\n xgd = projnorm1(xgd - gradient / L_estimate, lmo.right_hand_side)\n push!(training_gd, f(xgd))\n push!(test_gd, f_test(xgd))\n push!(coeff_error, coefficient_errors(xgd))\n push!(gd_times, (time_ns() - time_start) * 1e-9)\nend\n\nx00 = FrankWolfe.compute_extreme_point(lmo, random_initialization_vector)\nx0 = deepcopy(x00)\n\ntrajectory_lafw = []\ncallback = build_callback(trajectory_lafw)\nx_lafw, v, primal, dual_gap, _ = FrankWolfe.away_frank_wolfe(\n f,\n grad!,\n lmo,\n x0,\n max_iteration=max_iter,\n line_search=FrankWolfe.Adaptive(L_est=L_estimate),\n print_iter=max_iter ÷ 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=false,\n lazy=true,\n gradient=gradient,\n callback=callback,\n)\n\ntrajectory_bcg = []\ncallback = build_callback(trajectory_bcg)\n\nx0 = deepcopy(x00)\nx_bcg, v, primal, dual_gap, _, _ = FrankWolfe.blended_conditional_gradient(\n f,\n grad!,\n lmo,\n x0,\n max_iteration=max_iter,\n line_search=FrankWolfe.Adaptive(L_est=L_estimate),\n print_iter=max_iter ÷ 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=false,\n weight_purge_threshold=1e-10,\n callback=callback,\n)\n\nx0 = deepcopy(x00)\n\ntrajectory_lafw_ref = []\ncallback = build_callback(trajectory_lafw_ref)\n_, _, primal_ref, _, _ = FrankWolfe.away_frank_wolfe(\n f,\n grad!,\n lmo,\n x0,\n max_iteration=2 * max_iter,\n line_search=FrankWolfe.Adaptive(L_est=L_estimate),\n print_iter=max_iter ÷ 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=false,\n lazy=true,\n gradient=gradient,\n callback=callback,\n)\n\niteration_list = [\n [x[1] + 1 for x in trajectory_lafw],\n [x[1] + 1 for x in trajectory_bcg],\n collect(eachindex(training_gd)),\n]\ntime_list = [[x[5] for x in trajectory_lafw], [x[5] for x in trajectory_bcg], gd_times]\nprimal_list = [\n [x[2] - primal_ref for x in trajectory_lafw],\n [x[2] - primal_ref for x in trajectory_bcg],\n [x - primal_ref for x in training_gd],\n]\ntest_list = [[x[6] for x in trajectory_lafw], [x[6] for x in trajectory_bcg], test_gd]\nlabel = [L\"\\textrm{L-AFW}\", L\"\\textrm{BCG}\", L\"\\textrm{GD}\"]\ncoefficient_error_values =\n [[x[7] for x in trajectory_lafw], [x[7] for x in trajectory_bcg], coeff_error]\n\n\nplot_results(\n [primal_list, primal_list, test_list, test_list],\n [iteration_list, time_list, iteration_list, time_list],\n label,\n [L\"\\textrm{Iteration}\", L\"\\textrm{Time}\", L\"\\textrm{Iteration}\", L\"\\textrm{Time}\"],\n [L\"\\textrm{Primal Gap}\", L\"\\textrm{Primal Gap}\", L\"\\textrm{Test loss}\", L\"\\textrm{Test loss}\"],\n xscalelog=[:log, :identity, :log, :identity],\n legend_position=[:bottomleft, nothing, nothing, nothing],\n)","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"","category":"page"},{"location":"examples/docs_02_polynomial_regression/","page":"Polynomial Regression","title":"Polynomial Regression","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"EditURL = \"../../../examples/docs_08_callback_and_tracking.jl\"","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_08_callback_and_tracking/#Tracking,-counters-and-custom-callbacks-for-Frank-Wolfe","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"","category":"section"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"In this example we will run the standard Frank-Wolfe algorithm while tracking the number of calls to the different oracles, namely function, gradient evaluations, and LMO calls. In order to track each of these metrics, a \"Tracking\" version of the Gradient, LMO and Function methods have to be supplied to the frank_wolfe algorithm, which are wrapping a standard one.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"using FrankWolfe\nusing Test\nusing LinearAlgebra\nusing FrankWolfe: ActiveSet","category":"page"},{"location":"examples/docs_08_callback_and_tracking/#The-trackers-for-primal-objective,-gradient-and-LMO.","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"The trackers for primal objective, gradient and LMO.","text":"","category":"section"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"In order to count the number of function calls, a TrackingObjective is built from a standard objective function f, which will act in the same way as the original function does, but with an additional .counter field which tracks the number of calls.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"f(x) = norm(x)^2\ntf = FrankWolfe.TrackingObjective(f)\n@show tf.counter\ntf(rand(3))\n@show tf.counter\n# Resetting the counter\ntf.counter = 0;\nnothing #hide","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"Similarly, the tgrad! function tracks the number of gradient calls:","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"function grad!(storage, x)\n return storage .= 2x\nend\ntgrad! = FrankWolfe.TrackingGradient(grad!)\n@show tgrad!.counter;\nnothing #hide","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"The tracking LMO operates in a similar fashion and tracks the number of compute_extreme_point calls.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"lmo_prob = FrankWolfe.ProbabilitySimplexOracle(1)\ntlmo_prob = FrankWolfe.TrackingLMO(lmo_prob)\n@show tlmo_prob.counter;\nnothing #hide","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"The tracking LMO can be applied for all types of LMOs and even in a nested way, which can be useful to track the number of calls to a lazified oracle. We can now pass the tracking versions tf, tgrad and tlmo_prob to frank_wolfe and display their call counts after the optimization process.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"x0 = FrankWolfe.compute_extreme_point(tlmo_prob, ones(5))\nfw_results = FrankWolfe.frank_wolfe(\n tf,\n tgrad!,\n tlmo_prob,\n x0,\n max_iteration=1000,\n line_search=FrankWolfe.Agnostic(),\n callback=nothing,\n)\n\n@show tf.counter\n@show tgrad!.counter\n@show tlmo_prob.counter;\nnothing #hide","category":"page"},{"location":"examples/docs_08_callback_and_tracking/#Adding-a-custom-callback","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Adding a custom callback","text":"","category":"section"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"A callback is a user-defined function called at every iteration of the algorithm with the current state passed as a named tuple.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"We can implement our own callback, for example with:","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"Extended trajectory logging, similar to the trajectory = true option\nStop criterion after a certain number of calls to the primal objective function","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"To reuse the same tracking functions, Let us first reset their counters:","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"tf.counter = 0\ntgrad!.counter = 0\ntlmo_prob.counter = 0;\nnothing #hide","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"The storage variable stores in the trajectory array the number of calls to each oracle at each iteration.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"storage = []","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"Now define our own trajectory logging function that extends the five default logged elements (iterations, primal, dual, dual_gap, time) with \".counter\" field arguments present in the tracking functions.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"function push_tracking_state(state, storage)\n base_tuple = FrankWolfe.callback_state(state)\n if state.lmo isa FrankWolfe.CachedLinearMinimizationOracle\n complete_tuple = tuple(\n base_tuple...,\n state.gamma,\n state.f.counter,\n state.grad!.counter,\n state.lmo.inner.counter,\n )\n else\n complete_tuple = tuple(\n base_tuple...,\n state.gamma,\n state.f.counter,\n state.grad!.counter,\n state.lmo.counter,\n )\n end\n return push!(storage, complete_tuple)\nend","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"In case we want to stop the frank_wolfe algorithm prematurely after a certain condition is met, we can return a boolean stop criterion false. Here, we will implement a callback that terminates the algorithm if the primal objective function is evaluated more than 500 times.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"function make_callback(storage)\n return function callback(state, args...)\n push_tracking_state(state, storage)\n return state.f.counter < 500\n end\nend\n\ncallback = make_callback(storage)","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"We can show the difference between this standard run and the lazified conditional gradient algorithm which does not call the LMO at each iteration.","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"FrankWolfe.lazified_conditional_gradient(\n tf,\n tgrad!,\n tlmo_prob,\n x0,\n max_iteration=1000,\n traj_data=storage,\n line_search=FrankWolfe.Agnostic(),\n callback=callback,\n)\n\ntotal_iterations = storage[end][1]\n@show total_iterations\n@show tf.counter\n@show tgrad!.counter\n@show tlmo_prob.counter;\nnothing #hide","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"","category":"page"},{"location":"examples/docs_08_callback_and_tracking/","page":"Tracking, counters and custom callbacks for Frank Wolfe","title":"Tracking, counters and custom callbacks for Frank Wolfe","text":"This page was generated using Literate.jl.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"EditURL = \"https://github.com/ZIB-IOL/FrankWolfe.jl/blob/master/CONTRIBUTING.md\"","category":"page"},{"location":"contributing/#Contributing-to-FrankWolfe","page":"Contributing","title":"Contributing to FrankWolfe","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"First, thanks for taking the time to contribute. Contributions in any form, such as documentation, bug fix, examples or algorithms, are appreciated and welcome.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"We list below some guidelines to help you contribute to the package.","category":"page"},{"location":"contributing/#Community-Standards","page":"Contributing","title":"Community Standards","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Interactions on this repository must follow the Julia Community Standards including Pull Requests and issues.","category":"page"},{"location":"contributing/#Where-can-I-get-an-overview?","page":"Contributing","title":"Where can I get an overview?","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Check out the paper presenting the package for a high-level overview of the feature and algorithms and the documentation for more details.","category":"page"},{"location":"contributing/#I-just-have-a-question","page":"Contributing","title":"I just have a question","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"If your question is related to Julia, its syntax or tooling, the best places to get help will be tied to the Julia community, see the Julia community page for a number of communication channels (Slack, Zulip, and Discourse being the most active).","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"For now, the best way to ask a question is to file an issue or reach out to Mathieu Besançon or Sebastian Pokutta. You can also ask your question on discourse.julialang.org in the optimization topic or on the Julia Slack on #mathematical-optimization, see the Julia community page to gain access.","category":"page"},{"location":"contributing/#How-can-I-file-an-issue?","page":"Contributing","title":"How can I file an issue?","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"If you found a bug or want to propose a feature, we track our issues within the GitHub repository. Once opened, you can edit the issue or add new comments to continue the conversation.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"If you encounter a bug, send the stack trace (the lines appearing after the error occurred containing some source files) and ideally a Minimal Working Example (MWE), a small program that reproduces the bug.","category":"page"},{"location":"contributing/#How-can-I-contribute","page":"Contributing","title":"How can I contribute","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Contributing to the repository will likely be made in a Pull Request (PR). You will need to:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Fork the repository\nClone it on your machine to perform the changes\nCreate a branch for your modifications, based on the branch you want to merge on (typically master)\nPush to this branch on your fork\nThe GitHub web interface will then automatically suggest opening a PR onto the original repository.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"See the GitHub guide to creating PRs for more help on workflows using Git and GitHub.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"A PR should do a single thing to reduce the amount of code that must be reviewed. Do not run the formatter on the whole repository except if your PR is specifically about formatting.","category":"page"},{"location":"contributing/#Improve-the-documentation","page":"Contributing","title":"Improve the documentation","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"The documentation can be improved by changing the files in docs/src, for example to add a section in the documentation, expand a paragraph or add a plot. The documentation attached to a given type of function can be modified in the source files directly, it appears above the function / type / thingy you try to document with three double quotation marks like this:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"\"\"\"\nThis explains what the function `f` does, it supports markdown.\n\"\"\"\nfunction f(x)\n # ...\nend","category":"page"},{"location":"contributing/#Provide-a-new-example-or-test","page":"Contributing","title":"Provide a new example or test","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"If you fix a bug, one would typically expect to add a test that validates that the bug is gone. A test would be added in a file in the test/ folder, for which the entry point is runtests.jl.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"The examples/ folder features several examples covering different problem settings and algorithms. The examples are expected to run with the same environment and dependencies as the tests using TestEnv. If the example is lightweight enough, it can be added to the docs/src/examples/ folder which generates pages for the documentation based on Literate.jl.","category":"page"},{"location":"contributing/#Provide-a-new-feature","page":"Contributing","title":"Provide a new feature","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Contributions bringing new features are also welcome. If the feature is likely to impact performance, some benchmarks should be run with BenchmarkTools on several of the examples to assert the effect at different problem sizes. If the feature should only be active in some cases, a keyword should be added to the main algorithms to support it.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Some typical features to implement are:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"A new Linear Minimization Oracle (LMO)\nA new step size\nA new algorithm (less frequent) following the same API.","category":"page"},{"location":"contributing/#Code-style","page":"Contributing","title":"Code style","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"We try to follow the Julia documentation guidelines. We run JuliaFormatter.jl on the repo in the way set in the .JuliaFormatter.toml file, which enforces a number of conventions.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"This contribution guide was inspired by ColPrac and the one in Manopt.jl.","category":"page"},{"location":"basics/#How-does-it-work?","page":"How does it work?","title":"How does it work?","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"FrankWolfe.jl contains generic routines to solve optimization problems of the form","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"min_x in mathcalC f(x)","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"where mathcalC is a compact convex set and f is a differentiable function. These routines work by solving a sequence of linear subproblems:","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"min_x in mathcalC langle d_k x rangle quad textwhere quad d_k = nabla f(x_k)","category":"page"},{"location":"basics/#Linear-Minimization-Oracles","page":"How does it work?","title":"Linear Minimization Oracles","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"The Linear Minimization Oracle (LMO) is a key component, which is called at each iteration of the FW algorithm. Given a direction d, it returns an optimal vertex of the feasible set:","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"v in arg min_xin mathcalC langle dx rangle","category":"page"},{"location":"basics/#Custom-LMOs","page":"How does it work?","title":"Custom LMOs","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"To be used by the algorithms provided here, an LMO must be a subtype of FrankWolfe.LinearMinimizationOracle and implement the following method:","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"compute_extreme_point(lmo::LMO, direction; kwargs...) -> v","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"This method should minimize v mapsto langle d v rangle over the set mathcalC defined by the LMO. Note that this means the set mathcalC doesn't have to be represented explicitly: all we need is to be able to minimize a linear function over it, even if the minimization procedure is a black box.","category":"page"},{"location":"basics/#Pre-defined-LMOs","page":"How does it work?","title":"Pre-defined LMOs","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"If you don't want to define your LMO manually, several common implementations are available out-of-the-box:","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"Simplices: unit simplex, probability simplex\nBalls in various norms\nPolytopes: K-sparse, Birkhoff","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"You can use an oracle defined via a Linear Programming solver (e.g. SCIP or HiGHS) with MathOptInferface: see FrankWolfe.MathOptLMO.","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"Finally, we provide wrappers to combine oracles easily, for example in a product.","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"See Combettes, Pokutta (2021) for references on most LMOs implemented in the package and their comparison with projection operators.","category":"page"},{"location":"basics/#Optimization-algorithms","page":"How does it work?","title":"Optimization algorithms","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"The package features several variants of Frank-Wolfe that share the same basic API.","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"Most of the algorithms listed below also have a lazified version: see Braun, Pokutta, Zink (2016).","category":"page"},{"location":"basics/#Standard-Frank-Wolfe-(FW)","page":"How does it work?","title":"Standard Frank-Wolfe (FW)","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"It is implemented in the frank_wolfe function.","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"See Jaggi (2013) for an overview.","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"This algorithm works both for convex and non-convex functions (use step size rule FrankWolfe.Nonconvex() in the second case).","category":"page"},{"location":"basics/#Away-step-Frank-Wolfe-(AFW)","page":"How does it work?","title":"Away-step Frank-Wolfe (AFW)","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"It is implemented in the away_frank_wolfe function.","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"See Lacoste-Julien, Jaggi (2015) for an overview.","category":"page"},{"location":"basics/#Stochastic-Frank-Wolfe-(SFW)","page":"How does it work?","title":"Stochastic Frank-Wolfe (SFW)","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"It is implemented in the FrankWolfe.stochastic_frank_wolfe function.","category":"page"},{"location":"basics/#Blended-Conditional-Gradients-(BCG)","page":"How does it work?","title":"Blended Conditional Gradients (BCG)","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"It is implemented in the blended_conditional_gradient function, with a built-in stability feature that temporarily increases accuracy.","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"See Braun, Pokutta, Tu, Wright (2018).","category":"page"},{"location":"basics/#Pairwise-Frank-Wolfe-(PFW)","page":"How does it work?","title":"Pairwise Frank-Wolfe (PFW)","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"It is implemented in the pairwise_frank_wolfe function. See Lacoste-Julien, Jaggi (2015) for an overview.","category":"page"},{"location":"basics/#Blended-Pairwise-Conditional-Gradients-(BPCG)","page":"How does it work?","title":"Blended Pairwise Conditional Gradients (BPCG)","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"It is implemented in the FrankWolfe.blended_pairwise_conditional_gradient function, with a minor modification to improve sparsity.","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"See Tsuji, Tanaka, Pokutta (2021)","category":"page"},{"location":"basics/#Comparison","page":"How does it work?","title":"Comparison","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"The following table compares the characteristics of the algorithms presented in the package:","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"Algorithm Progress/Iteration Time/Iteration Sparsity Numerical Stability Active Set Lazifiable\nFW Low Low Low High No Yes\nAFW Medium Medium-High Medium Medium-High Yes Yes\nB(P)CG High Medium-High High Medium Yes By design\nSFW Low Low Low High No No","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"While the standard Frank-Wolfe algorithm can only move towards extreme points of the compact convex set mathcalC, Away-step Frank-Wolfe can move away from them. The following figure from our paper illustrates this behaviour:","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"(Image: FW vs AFW).","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"Both algorithms minimize a quadratic function (whose contour lines are depicted) over a simple polytope (the black square). When the minimizer lies on a face, the standard Frank-Wolfe algorithm zig-zags towards the solution, while its Away-step variant converges more quickly.","category":"page"},{"location":"basics/#Block-Coordinate-Frank-Wolfe-(BCFW)","page":"How does it work?","title":"Block-Coordinate Frank-Wolfe (BCFW)","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"It is implemented in the FrankWolfe.block_coordinate_frank_wolfe function.","category":"page"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"See Lacoste-Julien, Jaggi, Schmidt, Pletscher (2013) and Beck, Pauwels, Sabach (2015) for more details about different variants of Block-Coordinate Frank-Wolfe.","category":"page"},{"location":"basics/#Alternating-Linear-Minimization-(ALM)","page":"How does it work?","title":"Alternating Linear Minimization (ALM)","text":"","category":"section"},{"location":"basics/","page":"How does it work?","title":"How does it work?","text":"It is implemented in the FrankWolfe.alternating_linear_minimization function.","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"EditURL = \"../../../examples/docs_01_mathopt_lmo.jl\"","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_01_mathopt_lmo/#Comparison-with-MathOptInterface-on-a-Probability-Simplex","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"","category":"section"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"In this example, we project a random point onto a probability simplex with the Frank-Wolfe algorithm using either the specialized LMO defined in the package or a generic LP formulation using MathOptInterface.jl (MOI) and GLPK as underlying LP solver. It can be found as Example 4.4 in the paper.","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"using FrankWolfe\n\nusing LinearAlgebra\nusing LaTeXStrings\n\nusing Plots\n\nusing JuMP\nconst MOI = JuMP.MOI\n\nimport GLPK\n\nn = Int(1e3)\nk = 10000\n\nxpi = rand(n);\ntotal = sum(xpi);\nconst xp = xpi ./ total;\n\nf(x) = norm(x - xp)^2\nfunction grad!(storage, x)\n @. storage = 2 * (x - xp)\n return nothing\nend\n\nlmo_radius = 2.5\nlmo = FrankWolfe.FrankWolfe.ProbabilitySimplexOracle(lmo_radius)\n\nx00 = FrankWolfe.compute_extreme_point(lmo, zeros(n))\ngradient = collect(x00)\n\nx_lmo, v, primal, dual_gap, trajectory_lmo = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo,\n collect(copy(x00)),\n max_iteration=k,\n line_search=FrankWolfe.Shortstep(2.0),\n print_iter=k / 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=false,\n trajectory=true,\n);\nnothing #hide","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"Create a MathOptInterface Optimizer and build the same linear constraints:","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"o = GLPK.Optimizer()\nx = MOI.add_variables(o, n)\n\nfor xi in x\n MOI.add_constraint(o, xi, MOI.GreaterThan(0.0))\nend\n\nMOI.add_constraint(\n o,\n MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(1.0, x), 0.0),\n MOI.EqualTo(lmo_radius),\n)\n\nlmo_moi = FrankWolfe.MathOptLMO(o)\n\nx, v, primal, dual_gap, trajectory_moi = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo_moi,\n collect(copy(x00)),\n max_iteration=k,\n line_search=FrankWolfe.Shortstep(2.0),\n print_iter=k / 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=false,\n trajectory=true,\n);\nnothing #hide","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"Alternatively, we can use one of the modelling interfaces based on MOI to formulate the LP. The following example builds the same set of constraints using JuMP:","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"m = JuMP.Model(GLPK.Optimizer)\n@variable(m, y[1:n] ≥ 0)\n\n@constraint(m, sum(y) == lmo_radius)\n\nlmo_jump = FrankWolfe.MathOptLMO(m.moi_backend)\n\nx, v, primal, dual_gap, trajectory_jump = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo_jump,\n collect(copy(x00)),\n max_iteration=k,\n line_search=FrankWolfe.Shortstep(2.0),\n print_iter=k / 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=false,\n trajectory=true,\n);\n\nx_lmo, v, primal, dual_gap, trajectory_lmo_blas = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo,\n x00,\n max_iteration=k,\n line_search=FrankWolfe.Shortstep(2.0),\n print_iter=k / 10,\n memory_mode=FrankWolfe.OutplaceEmphasis(),\n verbose=false,\n trajectory=true,\n);\n\nx, v, primal, dual_gap, trajectory_jump_blas = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo_jump,\n x00,\n max_iteration=k,\n line_search=FrankWolfe.Shortstep(2.0),\n print_iter=k / 10,\n memory_mode=FrankWolfe.OutplaceEmphasis(),\n verbose=false,\n trajectory=true,\n);\nnothing #hide","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"We can now plot the results","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"iteration_list = [[x[1] + 1 for x in trajectory_lmo], [x[1] + 1 for x in trajectory_moi]]\ntime_list = [[x[5] for x in trajectory_lmo], [x[5] for x in trajectory_moi]]\nprimal_gap_list = [[x[2] for x in trajectory_lmo], [x[2] for x in trajectory_moi]]\ndual_gap_list = [[x[4] for x in trajectory_lmo], [x[4] for x in trajectory_moi]]\n\nlabel = [L\"\\textrm{Closed-form LMO}\", L\"\\textrm{MOI LMO}\"]\n\nplot_results(\n [primal_gap_list, primal_gap_list, dual_gap_list, dual_gap_list],\n [iteration_list, time_list, iteration_list, time_list],\n label,\n [\"\", \"\", L\"\\textrm{Iteration}\", L\"\\textrm{Time}\"],\n [L\"\\textrm{Primal Gap}\", \"\", L\"\\textrm{Dual Gap}\", \"\"],\n xscalelog=[:log, :identity, :log, :identity],\n yscalelog=[:log, :log, :log, :log],\n legend_position=[:bottomleft, nothing, nothing, nothing],\n)","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"","category":"page"},{"location":"examples/docs_01_mathopt_lmo/","page":"Comparison with MathOptInterface on a Probability Simplex","title":"Comparison with MathOptInterface on a Probability Simplex","text":"This page was generated using Literate.jl.","category":"page"},{"location":"reference/2_lmo/#Linear-Minimization-Oracles","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"","category":"section"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"The Linear Minimization Oracle (LMO) is a key component called at each iteration of the FW algorithm. Given din mathcalX, it returns a vertex of the feasible set:","category":"page"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"vin argmin_xin mathcalC langle dx rangle","category":"page"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"See Combettes, Pokutta 2021 for references on most LMOs implemented in the package and their comparison with projection operators.","category":"page"},{"location":"reference/2_lmo/#Interface-and-wrappers","page":"Linear Minimization Oracles","title":"Interface and wrappers","text":"","category":"section"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"FrankWolfe.LinearMinimizationOracle","category":"page"},{"location":"reference/2_lmo/#FrankWolfe.LinearMinimizationOracle","page":"Linear Minimization Oracles","title":"FrankWolfe.LinearMinimizationOracle","text":"Supertype for linear minimization oracles.\n\nAll LMOs must implement compute_extreme_point(lmo::LMO, direction) and return a vector v of the appropriate type.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"All of them are subtypes of FrankWolfe.LinearMinimizationOracle and implement the following method:","category":"page"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"compute_extreme_point","category":"page"},{"location":"reference/2_lmo/#FrankWolfe.compute_extreme_point","page":"Linear Minimization Oracles","title":"FrankWolfe.compute_extreme_point","text":"compute_extreme_point(lmo::LinearMinimizationOracle, direction; kwargs...)\n\nComputes the point argmin_{v ∈ C} v ⋅ direction with C the set represented by the LMO. Most LMOs feature v as a keyword argument that allows for an in-place computation whenever v is dense. All LMOs should accept keyword arguments that they can ignore.\n\n\n\n\n\n","category":"function"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"We also provide some meta-LMOs wrapping another one with extended behavior:","category":"page"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"FrankWolfe.CachedLinearMinimizationOracle\nFrankWolfe.ProductLMO\nFrankWolfe.SingleLastCachedLMO\nFrankWolfe.MultiCacheLMO\nFrankWolfe.VectorCacheLMO","category":"page"},{"location":"reference/2_lmo/#FrankWolfe.CachedLinearMinimizationOracle","page":"Linear Minimization Oracles","title":"FrankWolfe.CachedLinearMinimizationOracle","text":"CachedLinearMinimizationOracle{LMO}\n\nOracle wrapping another one of type lmo. Subtypes of CachedLinearMinimizationOracle contain a cache of previous solutions.\n\nBy convention, the inner oracle is named inner. Cached optimizers are expected to implement Base.empty! and Base.length.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.ProductLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.ProductLMO","text":"ProductLMO(lmos)\n\nLinear minimization oracle over the Cartesian product of multiple LMOs.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.SingleLastCachedLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.SingleLastCachedLMO","text":"SingleLastCachedLMO{LMO, VT}\n\nCaches only the last result from an LMO and stores it in last_vertex. Vertices of LMO have to be of type VT if provided.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.MultiCacheLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.MultiCacheLMO","text":"MultiCacheLMO{N, LMO, A}\n\nCache for a LMO storing up to N vertices in the cache, removed in FIFO style. oldest_idx keeps track of the oldest index in the tuple, i.e. to replace next. VT, if provided, must be the type of vertices returned by LMO\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.VectorCacheLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.VectorCacheLMO","text":"VectorCacheLMO{LMO, VT}\n\nCache for a LMO storing an unbounded number of vertices of type VT in the cache. VT, if provided, must be the type of vertices returned by LMO\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#Norm-balls","page":"Linear Minimization Oracles","title":"Norm balls","text":"","category":"section"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"Modules = [FrankWolfe]\nPages = [\"norm_oracles.jl\"]","category":"page"},{"location":"reference/2_lmo/#FrankWolfe.EllipsoidLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.EllipsoidLMO","text":"EllipsoidLMO(A, c, r)\n\nLinear minimization over an ellipsoid centered at c of radius r:\n\nx: (x - c)^T A (x - c) ≤ r\n\nThe LMO stores the factorization F of A that is used to solve linear systems A⁻¹ x. The result of the linear system solve is stored in buffer. The ellipsoid is assumed to be full-dimensional -> A is positive definite.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.KNormBallLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.KNormBallLMO","text":"KNormBallLMO{T}(K::Int, right_hand_side::T)\n\nLMO with feasible set being the K-norm ball in the sense of 2010.07243, i.e., the convex hull over the union of an L1-ball with radius τ and an L∞-ball with radius τ/K:\n\nC_{K,τ} = conv { B_1(τ) ∪ B_∞(τ / K) }\n\nwith τ the right_hand_side parameter. The K-norm is defined as the sum of the largest K absolute entries in a vector.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.LpNormLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.LpNormLMO","text":"LpNormLMO{T, p}(right_hand_side)\n\nLMO with feasible set being an L-p norm ball:\n\nC = {x ∈ R^n, norm(x, p) ≤ right_hand_side}\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.NuclearNormLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.NuclearNormLMO","text":"NuclearNormLMO{T}(radius)\n\nLMO over matrices that have a nuclear norm less than radius. The LMO returns the best rank-one approximation matrix with singular value radius, computed with Arpack.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.OrderWeightNormLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.OrderWeightNormLMO","text":"OrderWeightNormLMO(weights,radius)\n\nLMO with feasible set being the atomic ordered weighted l1 norm: https://arxiv.org/pdf/1409.4271\n\nC = {x ∈ R^n, Ω_w(x) ≤ R} \n\nThe weights are assumed to be positive.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.SpectraplexLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.SpectraplexLMO","text":"SpectraplexLMO{T,M}(radius::T,gradient_container::M,ensure_symmetry::Bool=true)\n\nFeasible set\n\n{X ∈ 𝕊_n^+, trace(X) == radius}\n\ngradient_container is used to store the symmetrized negative direction. ensure_symmetry indicates whether the linear function is made symmetric before computing the eigenvector.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.UnitSpectrahedronLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.UnitSpectrahedronLMO","text":"UnitSpectrahedronLMO{T,M}(radius::T, gradient_container::M)\n\nFeasible set of PSD matrices with bounded trace:\n\n{X ∈ 𝕊_n^+, trace(X) ≤ radius}\n\ngradient_container is used to store the symmetrized negative direction. ensure_symmetry indicates whether the linear function is made symmetric before computing the eigenvector.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#Simplex","page":"Linear Minimization Oracles","title":"Simplex","text":"","category":"section"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"Modules = [FrankWolfe]\nPages = [\"simplex_oracles.jl\"]","category":"page"},{"location":"reference/2_lmo/#FrankWolfe.HyperSimplexOracle","page":"Linear Minimization Oracles","title":"FrankWolfe.HyperSimplexOracle","text":"HyperSimplexOracle(radius)\n\nRepresents the scaled hypersimplex of radius τ, the convex hull of vectors v such that:\n\nv_i ∈ {0, τ}\n||v||_0 = k\n\nEquivalently, this is the convex hull of the vertices of the K-sparse polytope lying in the nonnegative orthant.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.ProbabilitySimplexOracle","page":"Linear Minimization Oracles","title":"FrankWolfe.ProbabilitySimplexOracle","text":"ProbabilitySimplexOracle(right_side)\n\nRepresents the scaled probability simplex:\n\nC = {x ∈ R^n_+, ∑x = right_side}\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.UnitHyperSimplexOracle","page":"Linear Minimization Oracles","title":"FrankWolfe.UnitHyperSimplexOracle","text":"UnitHyperSimplexOracle(radius)\n\nRepresents the scaled unit hypersimplex of radius τ, the convex hull of vectors v such that:\n\nv_i ∈ {0, τ}\n||v||_0 ≤ k\n\nEquivalently, this is the intersection of the K-sparse polytope and the nonnegative orthant.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.UnitSimplexOracle","page":"Linear Minimization Oracles","title":"FrankWolfe.UnitSimplexOracle","text":"UnitSimplexOracle(right_side)\n\nRepresents the scaled unit simplex:\n\nC = {x ∈ R^n_+, ∑x ≤ right_side}\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.compute_dual_solution-Union{Tuple{T}, Tuple{FrankWolfe.ProbabilitySimplexOracle{T}, Any, Any}} where T","page":"Linear Minimization Oracles","title":"FrankWolfe.compute_dual_solution","text":"Dual costs for a given primal solution to form a primal dual pair for scaled probability simplex. Returns two vectors. The first one is the dual costs associated with the constraints and the second is the reduced costs for the variables.\n\n\n\n\n\n","category":"method"},{"location":"reference/2_lmo/#FrankWolfe.compute_dual_solution-Union{Tuple{T}, Tuple{FrankWolfe.UnitSimplexOracle{T}, Any, Any}} where T","page":"Linear Minimization Oracles","title":"FrankWolfe.compute_dual_solution","text":"Dual costs for a given primal solution to form a primal dual pair for scaled unit simplex. Returns two vectors. The first one is the dual costs associated with the constraints and the second is the reduced costs for the variables.\n\n\n\n\n\n","category":"method"},{"location":"reference/2_lmo/#FrankWolfe.compute_extreme_point-Union{Tuple{T}, Tuple{FrankWolfe.ProbabilitySimplexOracle{T}, Any}} where T","page":"Linear Minimization Oracles","title":"FrankWolfe.compute_extreme_point","text":"LMO for scaled probability simplex. Returns a vector with one active value equal to RHS in the most improving (or least degrading) direction.\n\n\n\n\n\n","category":"method"},{"location":"reference/2_lmo/#FrankWolfe.compute_extreme_point-Union{Tuple{T}, Tuple{FrankWolfe.UnitSimplexOracle{T}, Any}} where T","page":"Linear Minimization Oracles","title":"FrankWolfe.compute_extreme_point","text":"LMO for scaled unit simplex: ∑ x_i ≤ τ Returns either vector of zeros or vector with one active value equal to RHS if there exists an improving direction.\n\n\n\n\n\n","category":"method"},{"location":"reference/2_lmo/#Polytope","page":"Linear Minimization Oracles","title":"Polytope","text":"","category":"section"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"Modules = [FrankWolfe]\nPages = [\"polytope_oracles.jl\"]","category":"page"},{"location":"reference/2_lmo/#FrankWolfe.BirkhoffPolytopeLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.BirkhoffPolytopeLMO","text":"BirkhoffPolytopeLMO\n\nThe Birkhoff polytope encodes doubly stochastic matrices. Its extreme vertices are all permutation matrices of side-dimension dimension.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.ConvexHullOracle","page":"Linear Minimization Oracles","title":"FrankWolfe.ConvexHullOracle","text":"ConvexHullOracle{AT,VT}\n\nConvex hull of a finite number of vertices of type AT, stored in a vector of type VT.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.KSparseLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.KSparseLMO","text":"KSparseLMO{T}(K::Int, right_hand_side::T)\n\nLMO for the K-sparse polytope:\n\nC = B_1(τK) ∩ B_∞(τ)\n\nwith τ the right_hand_side parameter. The LMO results in a vector with the K largest absolute values of direction, taking values -τ sign(x_i).\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.ScaledBoundL1NormBall","page":"Linear Minimization Oracles","title":"FrankWolfe.ScaledBoundL1NormBall","text":"ScaledBoundL1NormBall(lower_bounds, upper_bounds)\n\nPolytope similar to a L1-ball with shifted bounds. It is the convex hull of two scaled and shifted unit vectors for each axis (shifted to the center of the polytope, i.e., the elementwise midpoint of the bounds). Lower and upper bounds are passed on as abstract vectors, possibly of different types. For the standard L1-ball, all lower and upper bounds would be -1 and 1.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.ScaledBoundLInfNormBall","page":"Linear Minimization Oracles","title":"FrankWolfe.ScaledBoundLInfNormBall","text":"ScaledBoundLInfNormBall(lower_bounds, upper_bounds)\n\nPolytope similar to a L-inf-ball with shifted bounds or general box constraints. Lower- and upper-bounds are passed on as abstract vectors, possibly of different types. For the standard L-inf ball, all lower- and upper-bounds would be -1 and 1.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.ZeroOneHypercube","page":"Linear Minimization Oracles","title":"FrankWolfe.ZeroOneHypercube","text":"ZeroOneHypercube\n\n{0,1} hypercube polytope.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#MathOptInterface","page":"Linear Minimization Oracles","title":"MathOptInterface","text":"","category":"section"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"Modules = [FrankWolfe]\nPages = [\"moi_oracle.jl\"]","category":"page"},{"location":"reference/2_lmo/#FrankWolfe.MathOptLMO","page":"Linear Minimization Oracles","title":"FrankWolfe.MathOptLMO","text":"MathOptLMO{OT <: MOI.AbstractOptimizer} <: LinearMinimizationOracle\n\nLinear minimization oracle with feasible space defined through a MathOptInterface.Optimizer. The oracle call sets the direction and reruns the optimizer.\n\nThe direction vector has to be set in the same order of variables as the MOI.ListOfVariableIndices() getter.\n\nThe Boolean use_modify determines if the objective incompute_extreme_point is updated with MOI.modify(o, ::MOI.ObjectiveFunction, ::MOI.ScalarCoefficientChange) or with MOI.set(o, ::MOI.ObjectiveFunction, f). use_modify = true decreases the runtime and memory allocation for models created as an optimizer object and defined directly with MathOptInterface. use_modify = false should be used for CachingOptimizers.\n\n\n\n\n\n","category":"type"},{"location":"reference/2_lmo/#FrankWolfe.convert_mathopt","page":"Linear Minimization Oracles","title":"FrankWolfe.convert_mathopt","text":"convert_mathopt(lmo::LMO, optimizer::OT; kwargs...) -> MathOptLMO{OT}\n\nConverts the given LMO to its equivalent MathOptInterface representation using optimizer. Must be implemented by LMOs.\n\n\n\n\n\n","category":"function"},{"location":"reference/2_lmo/#Index","page":"Linear Minimization Oracles","title":"Index","text":"","category":"section"},{"location":"reference/2_lmo/","page":"Linear Minimization Oracles","title":"Linear Minimization Oracles","text":"Pages = [\"1_lmo.md\"]","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"EditURL = \"../../../examples/docs_00_fw_visualized.jl\"","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_00_fw_visualized/#Visualization-of-Frank-Wolfe-running-on-a-2-dimensional-polytope","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"","category":"section"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"This example provides an intuitive view of the Frank-Wolfe algorithm by running it on a polyhedral set with a quadratic function. The Linear Minimization Oracle (LMO) corresponds to a call to a generic simplex solver from MathOptInterface.jl (MOI).","category":"page"},{"location":"examples/docs_00_fw_visualized/#Import-and-setup","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Import and setup","text":"","category":"section"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"We first import the necessary packages, including Polyhedra to visualize the feasible set.","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"using LinearAlgebra\nusing FrankWolfe\n\nimport MathOptInterface\nconst MOI = MathOptInterface\nusing GLPK\n\nusing Polyhedra\nusing Plots","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"We can then define the objective function, here the squared distance to a point in the place, and its in-place gradient.","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"n = 2\ny = [3.2, 0.5]\n\nfunction f(x)\n return 1 / 2 * norm(x - y)^2\nend\nfunction grad!(storage, x)\n @. storage = x - y\nend","category":"page"},{"location":"examples/docs_00_fw_visualized/#Custom-callback","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Custom callback","text":"","category":"section"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"FrankWolfe.jl lets users define custom callbacks to record information about each iteration. In that case, the callback will copy the current iterate x, the current vertex v, and the current step size gamma to an array thanks to a closure. We then declare the array and the callback over this array. Each iteration will then push to this array.","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"function build_callback(trajectory_arr)\n return function callback(state, args...)\n return push!(trajectory_arr, (copy(state.x), copy(state.v), state.gamma))\n end\nend\n\niterates_information_vector = []\ncallback = build_callback(iterates_information_vector)","category":"page"},{"location":"examples/docs_00_fw_visualized/#Creating-the-Linear-Minimization-Oracle","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Creating the Linear Minimization Oracle","text":"","category":"section"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"The LMO is defined as a call to a linear optimization solver, each iteration resets the objective and calls the solver. The linear constraints must be defined only once at the beginning and remain identical along iterations. We use here MathOptInterface directly but the constraints could also be defined with JuMP or Convex.jl.","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"o = GLPK.Optimizer()\nx = MOI.add_variables(o, n)\n\n# −x + y ≤ 2\nc1 = MOI.add_constraint(o, -1.0x[1] + x[2], MOI.LessThan(2.0))\n\n# x + 2 y ≤ 4\nc2 = MOI.add_constraint(o, x[1] + 2.0x[2], MOI.LessThan(4.0))\n\n# −2 x − y ≤ 1\nc3 = MOI.add_constraint(o, -2.0x[1] - x[2], MOI.LessThan(1.0))\n\n# x − 2 y ≤ 2\nc4 = MOI.add_constraint(o, x[1] - 2.0x[2], MOI.LessThan(2.0))\n\n# x ≤ 2\nc5 = MOI.add_constraint(o, x[1] + 0.0x[2], MOI.LessThan(2.0))","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"The LMO is then built by wrapping the current MOI optimizer","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"lmo_moi = FrankWolfe.MathOptLMO(o)","category":"page"},{"location":"examples/docs_00_fw_visualized/#Calling-Frank-Wolfe","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Calling Frank-Wolfe","text":"","category":"section"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"We can now compute an initial starting point from any direction and call the Frank-Wolfe algorithm. Note that we copy x0 before passing it to the algorithm because it is modified in-place by frank_wolfe.","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"x0 = FrankWolfe.compute_extreme_point(lmo_moi, zeros(n))\n\nxfinal, vfinal, primal_value, dual_gap, traj_data = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo_moi,\n copy(x0),\n line_search=FrankWolfe.Adaptive(),\n max_iteration=10,\n epsilon=1e-8,\n callback=callback,\n verbose=true,\n print_iter=1,\n)","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"We now collect the iterates and vertices across iterations.","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"iterates = Vector{Vector{Float64}}()\npush!(iterates, x0)\nvertices = Vector{Vector{Float64}}()\nfor s in iterates_information_vector\n push!(iterates, s[1])\n push!(vertices, s[2])\nend","category":"page"},{"location":"examples/docs_00_fw_visualized/#Plotting-the-algorithm-run","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Plotting the algorithm run","text":"","category":"section"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"We define another method for f adapted to plot its contours.","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"function f(x1, x2)\n x = [x1, x2]\n return f(x)\nend\n\nxlist = collect(range(-1, 3, step=0.2))\nylist = collect(range(-1, 3, step=0.2))\n\nX = repeat(reshape(xlist, 1, :), length(ylist), 1)\nY = repeat(ylist, 1, length(xlist))","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"The feasible space is represented using Polyhedra.","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"h =\n HalfSpace([-1, 1], 2) ∩ HalfSpace([1, 2], 4) ∩ HalfSpace([-2, -1], 1) ∩ HalfSpace([1, -2], 2) ∩\n HalfSpace([1, 0], 2)\n\np = polyhedron(h)\n\np1 = contour(xlist, ylist, f, fill=true, line_smoothing=0.85)\nplot(p1, opacity=0.5)\nplot!(\n p,\n ratio=:equal,\n opacity=0.5,\n label=\"feasible region\",\n framestyle=:zerolines,\n legend=true,\n color=:blue,\n);\nnothing #hide","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"Finally, we add all iterates and vertices to the plot.","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"colors = [\"gold\", \"purple\", \"darkorange2\", \"firebrick3\"]\niterates = unique!(iterates)\nfor i in 1:3\n scatter!(\n [iterates[i][1]],\n [iterates[i][2]],\n label=string(\"x_\", i - 1),\n markersize=6,\n color=colors[i],\n )\nend\nscatter!(\n [last(iterates)[1]],\n [last(iterates)[2]],\n label=string(\"x_\", length(iterates) - 1),\n markersize=6,\n color=last(colors),\n)","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"plot chosen vertices","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"scatter!([vertices[1][1]], [vertices[1][2]], m=:diamond, markersize=6, color=colors[1], label=\"v_1\")\nscatter!(\n [vertices[2][1]],\n [vertices[2][2]],\n m=:diamond,\n markersize=6,\n color=colors[2],\n label=\"v_2\",\n legend=:outerleft,\n colorbar=true,\n)","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"","category":"page"},{"location":"examples/docs_00_fw_visualized/","page":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","title":"Visualization of Frank-Wolfe running on a 2-dimensional polytope","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"EditURL = \"../../../examples/docs_04_rational_opt.jl\"","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_04_rational_opt/#Exact-Optimization-with-Rational-Arithmetic","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"","category":"section"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"This example can be found in section 4.3 in the paper. The package allows for exact optimization with rational arithmetic. For this, it suffices to set up the LMO to be rational and choose an appropriate step-size rule as detailed below. For the LMOs included in the package, this simply means initializing the radius with a rational-compatible element type, e.g., 1, rather than a floating-point number, e.g., 1.0. Given that numerators and denominators can become quite large in rational arithmetic, it is strongly advised to base the used rationals on extended-precision integer types such as BigInt, i.e., we use Rational{BigInt}.","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"The second requirement ensuring that the computation runs in rational arithmetic is a rational-compatible step-size rule. The most basic step-size rule compatible with rational optimization is the agnostic step-size rule with gamma_t = 2(2 + t). With this step-size rule, the gradient does not even need to be rational as long as the atom computed by the LMO is of a rational type. Assuming these requirements are met, all iterates and the computed solution will then be rational.","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"using FrankWolfe\nusing LinearAlgebra\n\nn = 100\nk = n\n\nx = fill(big(1) // 100, n)\n\nf(x) = dot(x, x)\nfunction grad!(storage, x)\n @. storage = 2 * x\nend","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"pick feasible region radius needs to be integer or rational","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"lmo = FrankWolfe.ProbabilitySimplexOracle{Rational{BigInt}}(1)","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"compute some initial vertex","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"x0 = FrankWolfe.compute_extreme_point(lmo, zeros(n));\n\nx, v, primal, dual_gap, trajectory = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo,\n x0,\n max_iteration=k,\n line_search=FrankWolfe.Agnostic(),\n print_iter=k / 10,\n verbose=true,\n memory_mode=FrankWolfe.OutplaceEmphasis(),\n);\n\nprintln(\"\\nOutput type of solution: \", eltype(x))","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"Another possible step-size rule is rationalshortstep which computes the step size by minimizing the smoothness inequality as gamma_t=fraclangle nabla f(x_t)x_t-v_trangle2Lx_t-v_t^2. However, as this step size depends on an upper bound on the Lipschitz constant L as well as the inner product with the gradient nabla f(x_t), both have to be of a rational type.","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"@time x, v, primal, dual_gap, trajectory = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo,\n x0,\n max_iteration=k,\n line_search=FrankWolfe.Shortstep(2 // 1),\n print_iter=k / 10,\n verbose=true,\n memory_mode=FrankWolfe.OutplaceEmphasis(),\n);\nnothing #hide","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"Note: at the last step, we exactly close the gap, finding the solution 1//n * ones(n)","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"","category":"page"},{"location":"examples/docs_04_rational_opt/","page":"Exact Optimization with Rational Arithmetic","title":"Exact Optimization with Rational Arithmetic","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/docs_07_shifted_norm_polytopes/","page":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","title":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","text":"EditURL = \"../../../examples/docs_07_shifted_norm_polytopes.jl\"","category":"page"},{"location":"examples/docs_07_shifted_norm_polytopes/","page":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","title":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide\nusing FrankWolfe\nusing LinearAlgebra\nusing LaTeXStrings\nusing Plots","category":"page"},{"location":"examples/docs_07_shifted_norm_polytopes/#FrankWolfe-for-scaled,-shifted-\\ell1-and-\\ell{\\infty}-norm-balls","page":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","title":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","text":"","category":"section"},{"location":"examples/docs_07_shifted_norm_polytopes/","page":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","title":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","text":"In this example, we run the vanilla FrankWolfe algorithm on a scaled and shifted ell^1 and ell^infty norm ball, using the ScaledBoundL1NormBall and ScaledBoundLInfNormBall LMOs. We shift both onto the point (10) and then scale them by a factor of 2 along the x-axis. We project the point (21) onto the polytopes.","category":"page"},{"location":"examples/docs_07_shifted_norm_polytopes/","page":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","title":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","text":"n = 2\n\nk = 1000\n\nxp = [2.0, 1.0]\n\nf(x) = norm(x - xp)^2\n\nfunction grad!(storage, x)\n @. storage = 2 * (x - xp)\n return nothing\nend\n\nlower = [-1.0, -1.0]\nupper = [3.0, 1.0]\n\nl1 = FrankWolfe.ScaledBoundL1NormBall(lower, upper)\n\nlinf = FrankWolfe.ScaledBoundLInfNormBall(lower, upper)\n\nx1 = FrankWolfe.compute_extreme_point(l1, zeros(n))\ngradient = collect(x1)\n\nx_l1, v_1, primal_1, dual_gap_1, trajectory_1 = FrankWolfe.frank_wolfe(\n f,\n grad!,\n l1,\n collect(copy(x1)),\n max_iteration=k,\n line_search=FrankWolfe.Shortstep(2.0),\n print_iter=50,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=true,\n trajectory=true,\n);\n\nprintln(\"\\nFinal solution: \", x_l1)\n\nx2 = FrankWolfe.compute_extreme_point(linf, zeros(n))\ngradient = collect(x2)\n\nx_linf, v_2, primal_2, dual_gap_2, trajectory_2 = FrankWolfe.frank_wolfe(\n f,\n grad!,\n linf,\n collect(copy(x2)),\n max_iteration=k,\n line_search=FrankWolfe.Shortstep(2.0),\n print_iter=50,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=true,\n trajectory=true,\n);\n\nprintln(\"\\nFinal solution: \", x_linf)","category":"page"},{"location":"examples/docs_07_shifted_norm_polytopes/","page":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","title":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","text":"We plot the polytopes alongside the solutions from above:","category":"page"},{"location":"examples/docs_07_shifted_norm_polytopes/","page":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","title":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","text":"xcoord1 = [1, 3, 1, -1, 1]\nycoord1 = [-1, 0, 1, 0, -1]\n\nxcoord2 = [3, 3, -1, -1, 3]\nycoord2 = [-1, 1, 1, -1, -1]\n\nplot(\n xcoord1,\n ycoord1,\n title=\"Visualization of scaled shifted norm balls\",\n lw=2,\n label=L\"\\ell^1 \\textrm{ norm}\",\n)\nplot!(xcoord2, ycoord2, lw=2, label=L\"\\ell^{\\infty} \\textrm{ norm}\")\nplot!(\n [x_l1[1]],\n [x_l1[2]],\n seriestype=:scatter,\n lw=5,\n color=\"blue\",\n label=L\"\\ell^1 \\textrm{ solution}\",\n)\nplot!(\n [x_linf[1]],\n [x_linf[2]],\n seriestype=:scatter,\n lw=5,\n color=\"orange\",\n label=L\"\\ell^{\\infty} \\textrm{ solution}\",\n legend=:bottomleft,\n)","category":"page"},{"location":"examples/docs_07_shifted_norm_polytopes/","page":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","title":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","text":"","category":"page"},{"location":"examples/docs_07_shifted_norm_polytopes/","page":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","title":"FrankWolfe for scaled, shifted ell^1 and ell^infty norm balls","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"EditURL = \"../../../examples/docs_06_spectrahedron.jl\"","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_06_spectrahedron/#Spectrahedron","page":"Spectrahedron","title":"Spectrahedron","text":"","category":"section"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"This example shows an optimization problem over the spectraplex:","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"S = X in mathbbS_+^n Tr(X) = 1","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"with mathbbS_+^n the set of positive semidefinite matrices. Linear optimization with symmetric objective D over the spetraplex consists in computing the leading eigenvector of D.","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"The package also exposes UnitSpectrahedronLMO which corresponds to the feasible set:","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"S_u = X in mathbbS_+^n Tr(X) leq 1","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"using FrankWolfe\nusing LinearAlgebra\nusing Random\nusing SparseArrays","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"The objective function will be the symmetric squared distance to a set of known or observed entries Y_ij of the matrix.","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"f(X) = sum_(ij) in L 12 (X_ij - Y_ij)^2","category":"page"},{"location":"examples/docs_06_spectrahedron/#Setting-up-the-input-data,-objective,-and-gradient","page":"Spectrahedron","title":"Setting up the input data, objective, and gradient","text":"","category":"section"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"Dimension, number of iterations and number of known entries:","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"n = 1500\nk = 5000\nn_entries = 1000\n\nRandom.seed!(41)\n\nconst entry_indices = unique!([minmax(rand(1:n, 2)...) for _ in 1:n_entries])\nconst entry_values = randn(length(entry_indices))\n\nfunction f(X)\n r = zero(eltype(X))\n for (idx, (i, j)) in enumerate(entry_indices)\n r += 1 / 2 * (X[i, j] - entry_values[idx])^2\n r += 1 / 2 * (X[j, i] - entry_values[idx])^2\n end\n return r / length(entry_values)\nend\n\nfunction grad!(storage, X)\n storage .= 0\n for (idx, (i, j)) in enumerate(entry_indices)\n storage[i, j] += (X[i, j] - entry_values[idx])\n storage[j, i] += (X[j, i] - entry_values[idx])\n end\n return storage ./= length(entry_values)\nend","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"Note that the ensure_symmetry = false argument to SpectraplexLMO. It skips an additional step making the used direction symmetric. It is not necessary when the gradient is a LinearAlgebra.Symmetric (or more rarely a LinearAlgebra.Diagonal or LinearAlgebra.UniformScaling).","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"const lmo = FrankWolfe.SpectraplexLMO(1.0, n, false)\nconst x0 = FrankWolfe.compute_extreme_point(lmo, spzeros(n, n))\n\ntarget_tolerance = 1e-8;\nnothing #hide","category":"page"},{"location":"examples/docs_06_spectrahedron/#Running-standard-and-lazified-Frank-Wolfe","page":"Spectrahedron","title":"Running standard and lazified Frank-Wolfe","text":"","category":"section"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"Xfinal, Vfinal, primal, dual_gap, trajectory = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo,\n x0,\n max_iteration=k,\n line_search=FrankWolfe.MonotonicStepSize(),\n print_iter=k / 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=true,\n trajectory=true,\n epsilon=target_tolerance,\n)\n\nXfinal, Vfinal, primal, dual_gap, trajectory_lazy = FrankWolfe.lazified_conditional_gradient(\n f,\n grad!,\n lmo,\n x0,\n max_iteration=k,\n line_search=FrankWolfe.MonotonicStepSize(),\n print_iter=k / 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=true,\n trajectory=true,\n epsilon=target_tolerance,\n);\nnothing #hide","category":"page"},{"location":"examples/docs_06_spectrahedron/#Plotting-the-resulting-trajectories","page":"Spectrahedron","title":"Plotting the resulting trajectories","text":"","category":"section"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"data = [trajectory, trajectory_lazy]\nlabel = [\"FW\", \"LCG\"]\nplot_trajectories(data, label, xscalelog=true)","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"","category":"page"},{"location":"examples/docs_06_spectrahedron/","page":"Spectrahedron","title":"Spectrahedron","text":"This page was generated using Literate.jl.","category":"page"},{"location":"reference/4_linesearch/#Line-search-and-step-size-settings","page":"Line search and step size settings","title":"Line search and step size settings","text":"","category":"section"},{"location":"reference/4_linesearch/","page":"Line search and step size settings","title":"Line search and step size settings","text":"The step size dictates how far one traverses along a local descent direction. More specifically, the step size gamma_t is used at each iteration to determine how much the next iterate moves towards the new vertex:","category":"page"},{"location":"reference/4_linesearch/","page":"Line search and step size settings","title":"Line search and step size settings","text":"x_t+1 = x_t - gamma_t (x_t - v_t)","category":"page"},{"location":"reference/4_linesearch/","page":"Line search and step size settings","title":"Line search and step size settings","text":"gamma_t = 1 implies that the next iterate is exactly the vertex, a zero gamma_t implies that the iterate is not moving.","category":"page"},{"location":"reference/4_linesearch/","page":"Line search and step size settings","title":"Line search and step size settings","text":"The following are step size selection rules for Frank Wolfe algorithms. Some methodologies (e.g. FixedStep and Agnostic) depend only on the iteration number and induce series gamma_t that are independent of the problem data, while others (e.g. GoldenSearch and Adaptive) change according to local information about the function; the adaptive methods often require extra function and/or gradient computations. The typical options for convex optimization are Agnostic or Adaptive.","category":"page"},{"location":"reference/4_linesearch/","page":"Line search and step size settings","title":"Line search and step size settings","text":"All step size computation strategies are subtypes of FrankWolfe.LineSearchMethod. The key method they have to implement is FrankWolfe.perform_line_search which is called at every iteration to compute the step size gamma.","category":"page"},{"location":"reference/4_linesearch/","page":"Line search and step size settings","title":"Line search and step size settings","text":"FrankWolfe.LineSearchMethod\nFrankWolfe.perform_line_search","category":"page"},{"location":"reference/4_linesearch/#FrankWolfe.LineSearchMethod","page":"Line search and step size settings","title":"FrankWolfe.LineSearchMethod","text":"Line search method to apply once the direction is computed. A LineSearchMethod must implement\n\nperform_line_search(ls::LineSearchMethod, t, f, grad!, gradient, x, d, gamma_max, workspace)\n\nwith d = x - v. It may also implement build_linesearch_workspace(x, gradient) which creates a workspace structure that is passed as last argument to perform_line_search.\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.perform_line_search","page":"Line search and step size settings","title":"FrankWolfe.perform_line_search","text":"perform_line_search(ls::LineSearchMethod, t, f, grad!, gradient, x, d, gamma_max, workspace)\n\nReturns the step size gamma for step size strategy ls.\n\n\n\n\n\n","category":"function"},{"location":"reference/4_linesearch/","page":"Line search and step size settings","title":"Line search and step size settings","text":"Modules = [FrankWolfe]\nPages = [\"linesearch.jl\"]","category":"page"},{"location":"reference/4_linesearch/#FrankWolfe.Adaptive","page":"Line search and step size settings","title":"FrankWolfe.Adaptive","text":"Modified adaptive line search test from:\n\nS. Pokutta \"The Frank-Wolfe algorith: a short introduction\" (2023), preprint, https://arxiv.org/abs/2311.05313\n\nIt replaces the original test implemented in the AdaptiveZerothOrder line search based on:\n\nPedregosa, F., Negiar, G., Askari, A., and Jaggi, M. (2020). \"Linearly convergent Frank–Wolfe with backtracking line-search\", Proceedings of AISTATS.\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.AdaptiveZerothOrder","page":"Line search and step size settings","title":"FrankWolfe.AdaptiveZerothOrder","text":"Slight modification of the Adaptive Step Size strategy from Pedregosa, Negiar, Askari, Jaggi (2018)\n\n f(x_t + gamma_t (x_t - v_t)) - f(x_t) leq - alpha gamma_t langle nabla f(x_t) x_t - v_t rangle + alpha^2 fracgamma_t^2 x_t - v_t^22 M \n\nThe parameter alpha ∈ (0,1] relaxes the original smoothness condition to mitigate issues with nummerical errors. Its default value is 0.5. The Adaptive struct keeps track of the Lipschitz constant estimate L_est. The keyword argument relaxed_smoothness allows testing with an alternative smoothness condition,\n\n langle nabla f(x_t + gamma_t (x_t - v_t) ) - nabla f(x_t) x_t - v_t rangle leq gamma_t M x_t - v_t^2 \n\nThis condition yields potentially smaller and more stable estimations of the Lipschitz constant while being more computationally expensive due to the additional gradient computation.\n\nIt is also the fallback when the Lipschitz constant estimation fails due to numerical errors. perform_line_search also has a should_upgrade keyword argument on whether there should be a temporary upgrade to BigFloat for extended precision.\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.Agnostic","page":"Line search and step size settings","title":"FrankWolfe.Agnostic","text":"Computes step size: l/(l + t) at iteration t, given l > 0.\n\nUsing l > 2 leads to faster convergence rates than l = 2 over strongly and some uniformly convex set.\n\nAccelerated Affine-Invariant Convergence Rates of the Frank-Wolfe Algorithm with Open-Loop Step-Sizes, Wirth, Peña, Pokutta (2023), https://arxiv.org/abs/2310.04096 \n\nSee also the paper that introduced the study of open-loop step-sizes with l > 2:\n\nAcceleration of Frank-Wolfe Algorithms with Open-Loop Step-Sizes, Wirth, Kerdreux, Pokutta, (2023), https://arxiv.org/abs/2205.12838\n\nFixing l = -1, results in the step size gamma_t = (2 + log(t+1)) / (t + 2 + log(t+1))\n\nS. Pokutta \"The Frank-Wolfe algorith: a short introduction\" (2023), https://arxiv.org/abs/2311.05313\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.Backtracking","page":"Line search and step size settings","title":"FrankWolfe.Backtracking","text":"Backtracking(limit_num_steps, tol, tau)\n\nBacktracking line search strategy, see Pedregosa, Negiar, Askari, Jaggi (2018).\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.FixedStep","page":"Line search and step size settings","title":"FrankWolfe.FixedStep","text":"Fixed step size strategy. The step size can still be truncated by the gamma_max argument.\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.GeneralizedAgnostic","page":"Line search and step size settings","title":"FrankWolfe.GeneralizedAgnostic","text":"Computes step size: g(t)/(t + g(t)) at iteration t, given g: R_{>= 0} -> R_{>= 0}.\n\nDefaults to the best open-loop step-size gamma_t = (2 + log(t+1)) / (t + 2 + log(t+1))\n\nS. Pokutta \"The Frank-Wolfe algorith: a short introduction\" (2023), https://arxiv.org/abs/2311.05313\n\nThis step-size is as fast as the step-size gammat = 2 / (t + 2) up to polylogarithmic factors. Further, over strongly convex and some uniformly convex sets, it is faster than any traditional step-size gammat = l / (t + l) for any l in N.\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.Goldenratio","page":"Line search and step size settings","title":"FrankWolfe.Goldenratio","text":"Goldenratio\n\nSimple golden-ratio based line search Golden Section Search, based on Combettes, Pokutta (2020) code and adapted.\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.MonotonicNonConvexStepSize","page":"Line search and step size settings","title":"FrankWolfe.MonotonicNonConvexStepSize","text":"MonotonicNonConvexStepSize{F}\n\nRepresents a monotonic open-loop non-convex step size. Contains a halving factor N increased at each iteration until there is primal progress gamma = 1 / sqrt(t + 1) * 2^(-N).\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.MonotonicStepSize","page":"Line search and step size settings","title":"FrankWolfe.MonotonicStepSize","text":"MonotonicStepSize{F}\n\nRepresents a monotonic open-loop step size. Contains a halving factor N increased at each iteration until there is primal progress gamma = 2 / (t + 2) * 2^(-N).\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.Nonconvex","page":"Line search and step size settings","title":"FrankWolfe.Nonconvex","text":"Computes step size: 1/sqrt(t + 1).\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.Secant","page":"Line search and step size settings","title":"FrankWolfe.Secant","text":"Secant(limit_num_steps, tol, domain_oracle)\n\nSecant line search strategy, which iteratively refines the step size using the secant method. This method is geared towards problems with self-concordant functions (but might require extra structure) and potentially faster than the backtracking line search. The order of convergence is superlinear with exponent 1.618 (Golden Ratio) but not quite quadratic. Convergence is not guaranteed in general.\n\nArguments\n\ninner_ls::LSM: A fallback line search in case the last gamma in Secant does not satisfy the tolerance. Is only used if safe==true. (default Backtracking)\nsafe::Bool: Flag indicating whether the fallback line search should be used. If false, the best gamma from Secant is used. (default true) \nlimit_num_steps::Int: Maximum number of iterations for the secant method. (default 40)\ntol::Float64: Tolerance for convergence. (default 1e-8)\ndomain_oracle::Function, returns true if the argument x is in the domain of the objective function f.\n\nReferences\n\nSecant Method\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/#FrankWolfe.Shortstep","page":"Line search and step size settings","title":"FrankWolfe.Shortstep","text":"Computes the 'Short step' step size: dual_gap / (L * norm(x - v)^2), where L is the Lipschitz constant of the gradient, x is the current iterate, and v is the current Frank-Wolfe vertex.\n\n\n\n\n\n","category":"type"},{"location":"reference/4_linesearch/","page":"Line search and step size settings","title":"Line search and step size settings","text":"See Pedregosa, Negiar, Askari, Jaggi (2020) for the adaptive step size, Carderera, Besançon, Pokutta (2021) for the monotonic step size.","category":"page"},{"location":"reference/4_linesearch/#Index","page":"Line search and step size settings","title":"Index","text":"","category":"section"},{"location":"reference/4_linesearch/","page":"Line search and step size settings","title":"Line search and step size settings","text":"Pages = [\"4_linesearch.md\"]","category":"page"},{"location":"examples/docs_05_blended_cg/","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"EditURL = \"../../../examples/docs_05_blended_cg.jl\"","category":"page"},{"location":"examples/docs_05_blended_cg/","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_05_blended_cg/#Blended-Conditional-Gradients","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"","category":"section"},{"location":"examples/docs_05_blended_cg/","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"The FW and AFW algorithms, and their lazy variants share one feature: they attempt to make primal progress over a reduced set of vertices. The AFW algorithm does this through away steps (which do not increase the cardinality of the active set), and the lazy variants do this through the use of previously exploited vertices. A third strategy that one can follow is to explicitly blend Frank-Wolfe steps with gradient descent steps over the convex hull of the active set (note that this can be done without requiring a projection oracle over C, thus making the algorithm projection-free). This results in the Blended Conditional Gradient (BCG) algorithm, which attempts to make as much progress as possible through the convex hull of the current active set S_t until it automatically detects that in order to make further progress it requires additional calls to the LMO.","category":"page"},{"location":"examples/docs_05_blended_cg/","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"See also Blended Conditional Gradients: the unconditioning of conditional gradients, Braun et al, 2019, https://arxiv.org/abs/1805.07311","category":"page"},{"location":"examples/docs_05_blended_cg/","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"using FrankWolfe\nusing LinearAlgebra\nusing Random\nusing SparseArrays\n\nn = 1000\nk = 10000\n\nRandom.seed!(41)\n\nmatrix = rand(n, n)\nhessian = transpose(matrix) * matrix\nlinear = rand(n)\nf(x) = dot(linear, x) + 0.5 * transpose(x) * hessian * x\nfunction grad!(storage, x)\n return storage .= linear + hessian * x\nend\nL = eigmax(hessian)","category":"page"},{"location":"examples/docs_05_blended_cg/","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"We run over the probability simplex and call the LMO to get an initial feasible point:","category":"page"},{"location":"examples/docs_05_blended_cg/","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"lmo = FrankWolfe.ProbabilitySimplexOracle(1.0);\nx00 = FrankWolfe.compute_extreme_point(lmo, zeros(n))\n\ntarget_tolerance = 1e-5\n\nx0 = deepcopy(x00)\nx, v, primal, dual_gap, trajectoryBCG_accel_simplex, _ = FrankWolfe.blended_conditional_gradient(\n f,\n grad!,\n lmo,\n x0,\n epsilon=target_tolerance,\n max_iteration=k,\n line_search=FrankWolfe.Adaptive(L_est=L),\n print_iter=k / 10,\n hessian=hessian,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n accelerated=true,\n verbose=true,\n trajectory=true,\n lazy_tolerance=1.0,\n weight_purge_threshold=1e-10,\n)\n\nx0 = deepcopy(x00)\nx, v, primal, dual_gap, trajectoryBCG_simplex, _ = FrankWolfe.blended_conditional_gradient(\n f,\n grad!,\n lmo,\n x0,\n epsilon=target_tolerance,\n max_iteration=k,\n line_search=FrankWolfe.Adaptive(L_est=L),\n print_iter=k / 10,\n hessian=hessian,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n accelerated=false,\n verbose=true,\n trajectory=true,\n lazy_tolerance=1.0,\n weight_purge_threshold=1e-10,\n)\n\nx0 = deepcopy(x00)\nx, v, primal, dual_gap, trajectoryBCG_convex, _ = FrankWolfe.blended_conditional_gradient(\n f,\n grad!,\n lmo,\n x0,\n epsilon=target_tolerance,\n max_iteration=k,\n line_search=FrankWolfe.Adaptive(L_est=L),\n print_iter=k / 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=true,\n trajectory=true,\n lazy_tolerance=1.0,\n weight_purge_threshold=1e-10,\n)\n\ndata = [trajectoryBCG_accel_simplex, trajectoryBCG_simplex, trajectoryBCG_convex]\nlabel = [\"BCG (accel simplex)\", \"BCG (simplex)\", \"BCG (convex)\"]\nplot_trajectories(data, label, xscalelog=true)\n\n\n\nmatrix = rand(n, n)\nhessian = transpose(matrix) * matrix\nlinear = rand(n)\nf(x) = dot(linear, x) + 0.5 * transpose(x) * hessian * x + 10\nfunction grad!(storage, x)\n return storage .= linear + hessian * x\nend\nL = eigmax(hessian)\n\nlmo = FrankWolfe.KSparseLMO(100, 100.0)\nx00 = FrankWolfe.compute_extreme_point(lmo, zeros(n))\n\nx0 = deepcopy(x00)\nx, v, primal, dual_gap, trajectoryBCG_accel_simplex, _ = FrankWolfe.blended_conditional_gradient(\n f,\n grad!,\n lmo,\n x0,\n epsilon=target_tolerance,\n max_iteration=k,\n line_search=FrankWolfe.Adaptive(L_est=L),\n print_iter=k / 10,\n hessian=hessian,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n accelerated=true,\n verbose=true,\n trajectory=true,\n lazy_tolerance=1.0,\n weight_purge_threshold=1e-10,\n)\n\nx0 = deepcopy(x00)\nx, v, primal, dual_gap, trajectoryBCG_simplex, _ = FrankWolfe.blended_conditional_gradient(\n f,\n grad!,\n lmo,\n x0,\n epsilon=target_tolerance,\n max_iteration=k,\n line_search=FrankWolfe.Adaptive(L_est=L),\n print_iter=k / 10,\n hessian=hessian,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n accelerated=false,\n verbose=true,\n trajectory=true,\n lazy_tolerance=1.0,\n weight_purge_threshold=1e-10,\n)\n\nx0 = deepcopy(x00)\nx, v, primal, dual_gap, trajectoryBCG_convex, _ = FrankWolfe.blended_conditional_gradient(\n f,\n grad!,\n lmo,\n x0,\n epsilon=target_tolerance,\n max_iteration=k,\n line_search=FrankWolfe.Adaptive(L_est=L),\n print_iter=k / 10,\n memory_mode=FrankWolfe.InplaceEmphasis(),\n verbose=true,\n trajectory=true,\n lazy_tolerance=1.0,\n weight_purge_threshold=1e-10,\n)\n\ndata = [trajectoryBCG_accel_simplex, trajectoryBCG_simplex, trajectoryBCG_convex]\nlabel = [\"BCG (accel simplex)\", \"BCG (simplex)\", \"BCG (convex)\"]\nplot_trajectories(data, label, xscalelog=true)","category":"page"},{"location":"examples/docs_05_blended_cg/","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"","category":"page"},{"location":"examples/docs_05_blended_cg/","page":"Blended Conditional Gradients","title":"Blended Conditional Gradients","text":"This page was generated using Literate.jl.","category":"page"},{"location":"advanced/#Advanced-features","page":"Advanced features","title":"Advanced features","text":"","category":"section"},{"location":"advanced/#Multi-precision","page":"Advanced features","title":"Multi-precision","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"All algorithms can run in various precisions modes: Float16, Float32, Float64, BigFloat and also for rationals based on various integer types Int32, Int64, BigInt (see e.g., the approximate Carathéodory example)","category":"page"},{"location":"advanced/#Step-size-computation","page":"Advanced features","title":"Step size computation","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"For all Frank-Wolfe algorithms, a step size must be determined to move from the current iterate to the next one. This step size can be determined by exact line search or any other rule represented by a subtype of FrankWolfe.LineSearchMethod, which must implement FrankWolfe.perform_line_search.","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Multiple line search and step size determination rules are already available. See Pedregosa, Negiar, Askari, Jaggi (2020) and Pokutta (2023) for the adaptive step size and Carderera, Besançon, Pokutta (2021) for the monotonic step size.","category":"page"},{"location":"advanced/#Callbacks","page":"Advanced features","title":"Callbacks","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"All top-level algorithms can take an optional callback argument, which must be a function taking a FrankWolfe.CallbackState struct and additional arguments:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"callback(state::FrankWolfe.CallbackState, args...)","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"The callback can be used to log additional information or store some values of interest in an external array. If a callback is passed, the trajectory keyword is ignored since it is a special case of callback pushing the 5 first elements of the state to an array returned from the algorithm.","category":"page"},{"location":"advanced/#Custom-extreme-point-types","page":"Advanced features","title":"Custom extreme point types","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"For some feasible sets, the extreme points of the feasible set returned by the LMO possess a specific structure that can be represented in an efficient manner both for storage and for common operations like scaling and addition with an iterate. See for example FrankWolfe.ScaledHotVector and FrankWolfe.RankOneMatrix.","category":"page"},{"location":"advanced/#Active-set","page":"Advanced features","title":"Active set","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"The active set represents an iterate as a convex combination of atoms (also referred to as extreme points or vertices). It maintains a vector of atoms, the corresponding weights, and the current iterate.","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Note: the weights in the active set are currently defined as Float64 in the algorithm. This means that even with vertices using a lower precision, the iterate sum_i(lambda_i * v_i) will be upcast to Float64. One reason for keeping this as-is for now is the higher precision required by the computation of iterates from their barycentric decomposition.","category":"page"},{"location":"advanced/#Extra-lazification-with-a-vertex-storage","page":"Advanced features","title":"Extra-lazification with a vertex storage","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"One can pass the following keyword arguments to some active set-based Frank-Wolfe algorithms:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"add_dropped_vertices=true,\nuse_extra_vertex_storage=true,\nextra_vertex_storage=vertex_storage,","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"add_dropped_vertices activates feeding discarded vertices to the storage while use_extra_vertex_storage determines whether vertices from the storage are used in the algorithm. See Extra-lazification for a complete example.","category":"page"},{"location":"advanced/#Specialized-active-set-for-quadratic-functions","page":"Advanced features","title":"Specialized active set for quadratic functions","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"If the objective function is quadratic, a considerable speedup can be obtained by using the structure ActiveSetQuadraticProductCaching. It relies on the storage of various scalar products to efficiently determine the best (and worst for blended_pairwise_conditional_gradient) atom in the active set without the need of computing many scalar products in each iteration. The user should provide the Hessian matrix A as well as the linear part b of the function, such that:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"nabla f(x)=Ax+b","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"If the Hessian matrix A is simply a scaled identity (for a distance function for instance), LinearAlgebra.I or any LinearAlgebra.UniformScaling can be given. Note that these parameters can also be automatically detected, but the precision of this detection (which basically requires solving a linear system) soon becomes insufficient for practical purposes when the dimension increases.","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"See the examples quadratic.jl and quadratic_A.jl for the exact syntax.","category":"page"},{"location":"advanced/#Miscellaneous","page":"Advanced features","title":"Miscellaneous","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Emphasis: All solvers support emphasis (parameter Emphasis) to either exploit vectorized linear algebra or be memory efficient, e.g., for large-scale instances\nVarious caching strategies for the lazy implementations. Unbounded cache sizes (can get slow), bounded cache sizes as well as early returns once any sufficient vertex is found in the cache.\nOptionally all algorithms can be endowed with gradient momentum. This might help convergence especially in the stochastic context.","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Coming soon: when the LMO can compute dual prices, then the Frank-Wolfe algorithms will return dual prices for the (approximately) optimal solutions (see Braun, Pokutta (2021)).","category":"page"},{"location":"advanced/#Rational-arithmetic","page":"Advanced features","title":"Rational arithmetic","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Example: examples/approximateCaratheodory.jl","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"We can solve the approximate Carathéodory problem with rational arithmetic to obtain rational approximations; see Combettes, Pokutta 2019 for some background about approximate Carathéodory and Conditioanl Gradients. We consider the simple instance of approximating the 0 over the probability simplex here:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"min_x in Delta(n) x^2","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"with n = 100.","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Vanilla Frank-Wolfe Algorithm.\nEMPHASIS: blas STEPSIZE: rationalshortstep EPSILON: 1.0e-7 max_iteration: 100 TYPE: Rational{BigInt}\n\n───────────────────────────────────────────────────────────────────────────────────\n Type Iteration Primal Dual Dual Gap Time\n───────────────────────────────────────────────────────────────────────────────────\n I 0 1.000000e+00 -1.000000e+00 2.000000e+00 1.540385e-01\n FW 10 9.090909e-02 -9.090909e-02 1.818182e-01 2.821186e-01\n FW 20 4.761905e-02 -4.761905e-02 9.523810e-02 3.027964e-01\n FW 30 3.225806e-02 -3.225806e-02 6.451613e-02 3.100331e-01\n FW 40 2.439024e-02 -2.439024e-02 4.878049e-02 3.171654e-01\n FW 50 1.960784e-02 -1.960784e-02 3.921569e-02 3.244207e-01\n FW 60 1.639344e-02 -1.639344e-02 3.278689e-02 3.326185e-01\n FW 70 1.408451e-02 -1.408451e-02 2.816901e-02 3.418239e-01\n FW 80 1.234568e-02 -1.234568e-02 2.469136e-02 3.518750e-01\n FW 90 1.098901e-02 -1.098901e-02 2.197802e-02 3.620287e-01\n Last 1.000000e-02 1.000000e-02 0.000000e+00 4.392171e-01\n───────────────────────────────────────────────────────────────────────────────────\n\n 0.600608 seconds (3.83 M allocations: 111.274 MiB, 12.97% gc time)\n\nOutput type of solution: Rational{BigInt}","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"The solution returned is rational as we can see and in fact the exactly optimal solution:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"x = Rational{BigInt}[1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100, 1//100]","category":"page"},{"location":"advanced/#Large-scale-problems","page":"Advanced features","title":"Large-scale problems","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Example: examples/large_scale.jl","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"The package is built to scale well, for those conditional gradients variants that can scale well. For example, Away-Step Frank-Wolfe and Pairwise Conditional Gradients do in most cases not scale well because they need to maintain active sets and maintaining them can be very expensive. Similarly, line search methods might become prohibitive at large sizes. However if we consider scale-friendly variants, e.g., the vanilla Frank-Wolfe algorithm with the agnostic step size rule or short step rule, then these algorithms can scale well to extreme sizes esentially only limited by the amount of memory available. However even for these methods that tend to scale well, allocation of memory itself can be very slow when you need to allocate gigabytes of memory for a single gradient computation.","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"The package is build to support extreme sizes with a special memory efficient emphasis emphasis=FrankWolfe.memory, which minimizes expensive memory allocations and performs as many operations in-place as possible.","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Here is an example of a run with 1e9 variables. Each gradient is around 7.5 GB in size. Here is the output of the run broken down into pieces:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Size of single vector (Float64): 7629.39453125 MB\nTesting f... 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:23\nTesting grad... 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:23\nTesting lmo... 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:29\nTesting dual gap... 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:46\nTesting update... (Emphasis: blas) 100%|███████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:01:35\nTesting update... (Emphasis: memory) 100%|█████████████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:58\n ──────────────────────────────────────────────────────────────────────────\n Time Allocations\n ────────────────────── ───────────────────────\n Tot / % measured: 278s / 31.4% 969GiB / 30.8%\n\n Section ncalls time %tot avg alloc %tot avg\n ──────────────────────────────────────────────────────────────────────────\n update (blas) 10 36.1s 41.3% 3.61s 149GiB 50.0% 14.9GiB\n lmo 10 18.4s 21.1% 1.84s 0.00B 0.00% 0.00B\n grad 10 12.8s 14.6% 1.28s 74.5GiB 25.0% 7.45GiB\n f 10 12.7s 14.5% 1.27s 74.5GiB 25.0% 7.45GiB\n update (memory) 10 5.00s 5.72% 500ms 0.00B 0.00% 0.00B\n dual gap 10 2.40s 2.75% 240ms 0.00B 0.00% 0.00B\n ──────────────────────────────────────────────────────────────────────────","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"The above is the optional benchmarking of the oracles that we provide to understand how fast crucial parts of the algorithms are, mostly notably oracle evaluations, the update of the iterate and the computation of the dual gap. As you can see if you compare update (blas) vs. update (memory), the normal update when we use BLAS requires an additional 14.9GB of memory on top of the gradient etc whereas the update (memory) (the memory emphasis mode) does not consume any extra memory. This is also reflected in the computational times: the BLAS version requires 3.61 seconds on average to update the iterate, while the memory emphasis version requires only 500ms. In fact none of the crucial components in the algorithm consume any memory when run in memory efficient mode. Now let us look at the actual footprint of the whole algorithm:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Vanilla Frank-Wolfe Algorithm.\nEMPHASIS: memory STEPSIZE: agnostic EPSILON: 1.0e-7 MAXITERATION: 1000 TYPE: Float64\nMOMENTUM: nothing GRADIENTTYPE: Nothing\nWARNING: In memory emphasis mode iterates are written back into x0!\n\n─────────────────────────────────────────────────────────────────────────────────────────────────\n Type Iteration Primal Dual Dual Gap Time It/sec\n─────────────────────────────────────────────────────────────────────────────────────────────────\n I 0 1.000000e+00 -1.000000e+00 2.000000e+00 8.783523e+00 0.000000e+00\n FW 100 1.326732e-02 -1.326733e-02 2.653465e-02 4.635923e+02 2.157068e-01\n FW 200 6.650080e-03 -6.650086e-03 1.330017e-02 9.181294e+02 2.178342e-01\n FW 300 4.437059e-03 -4.437064e-03 8.874123e-03 1.372615e+03 2.185609e-01\n FW 400 3.329174e-03 -3.329180e-03 6.658354e-03 1.827260e+03 2.189070e-01\n FW 500 2.664003e-03 -2.664008e-03 5.328011e-03 2.281865e+03 2.191190e-01\n FW 600 2.220371e-03 -2.220376e-03 4.440747e-03 2.736387e+03 2.192672e-01\n FW 700 1.903401e-03 -1.903406e-03 3.806807e-03 3.190951e+03 2.193703e-01\n FW 800 1.665624e-03 -1.665629e-03 3.331253e-03 3.645425e+03 2.194532e-01\n FW 900 1.480657e-03 -1.480662e-03 2.961319e-03 4.099931e+03 2.195159e-01\n FW 1000 1.332665e-03 -1.332670e-03 2.665335e-03 4.554703e+03 2.195533e-01\n Last 1000 1.331334e-03 -1.331339e-03 2.662673e-03 4.559822e+03 2.195261e-01\n─────────────────────────────────────────────────────────────────────────────────────────────────\n\n4560.661203 seconds (7.41 M allocations: 112.121 GiB, 0.01% gc time)","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"As you can see the algorithm ran for about 4600 secs (single-thread run) allocating 112.121 GiB of memory throughout. So how does this average out to the per-iteration cost in terms of memory: 112.121 / 7.45 / 1000 = 0.0151 so about 15.1MiB per iteration which is much less than the size of the gradient and in fact only stems from the reporting here.","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"NB. This example highlights also one of the great features of first-order methods and conditional gradients in particular: we have dimension-independent convergence rates. In fact, we contract the primal gap as 2LD^2 / (t+2) (for the simple agnostic rule) and, e.g., if the feasible region is the probability simplex with D = sqrt(2) and the function has bounded Lipschitzness, e.g., the function || x - xp ||^2 has L = 2, then the convergence rate is completely independent of the input size. The only thing that limits scaling is how much memory you have available and whether you can stomach the (linear) per-iteration cost.","category":"page"},{"location":"advanced/#Iterate-and-atom-expected-interface","page":"Advanced features","title":"Iterate and atom expected interface","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Frank-Wolfe can work on iterate beyond plain vectors, for example with any array-like object. Broadly speaking, the iterate type is assumed to behave as the member of a Hilbert space and optionally be mutable. Assuming the iterate type is IT, some methods must be implemented, with their usual semantics:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Base.similar(::IT)\nBase.similar(::IT, ::Type{T})\nBase.collect(::IT)\nBase.size(::IT)\nBase.eltype(::IT)\nBase.copyto!(dest::IT, src::IT)\n\nBase.:+(x1::IT, x2::IT)\nBase.:*(scalar::Real, x::IT)\nBase.:-(x1::IT, x2::IT)\nLinearAlgebra.dot(x1::IT, x2::IT)\nLinearAlgebra.norm(::IT)","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"For methods using an FrankWolfe.ActiveSet, the atoms or individual extreme points of the feasible region are not necessarily of the same type as the iterate. They are assumed to be immutable, must implement LinearAlgebra.dot with a gradient object. See for example FrankWolfe.RankOneMatrix or FrankWolfe.ScaledHotVector.","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"The iterate type IT must be a broadcastable mutable object or implement FrankWolfe.compute_active_set_iterate!:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"FrankWolfe.compute_active_set_iterate!(active_set::FrankWolfe.ActiveSet{AT, R, IT}) where {AT, R}","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"which recomputes the iterate from the current convex decomposition and the following methods FrankWolfe.active_set_update_scale! and FrankWolfe.active_set_update_iterate_pairwise!:","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"FrankWolfe.active_set_update_scale!(x::IT, lambda, atom)\nFrankWolfe.active_set_update_iterate_pairwise!(x::IT, lambda, fw_atom, away_atom)","category":"page"},{"location":"advanced/#Symmetry-reduction","page":"Advanced features","title":"Symmetry reduction","text":"","category":"section"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Example: examples/reynolds.jl","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Suppose that there is a group G acting on the underlying vector space and such that for all xinmathcalC and gin G","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"f(gcdot x)=f(x)quadtextandquad gcdot xinmathcalC","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"Then, the computations can be performed in the subspace invariant under G. This subspace is the image of the Reynolds operator defined by","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"mathcalR(x)=frac1Gsum_gin Ggcdot x","category":"page"},{"location":"advanced/","page":"Advanced features","title":"Advanced features","text":"In practice, the type SubspaceLMO allows the user to provide the Reynolds operator mathcalR as well as its adjoint mathcalR^ast. The gradient is symmetrised with mathcalR^ast, then passed to the non-symmetric LMO, and the resulting output is symmetrised with mathcalR. In many cases, the gradient is already symmetric so that reynolds_adjoint(gradient, lmo) = gradient is a fast and valid choice.","category":"page"},{"location":"reference/1_algorithms/#Algorithms","page":"Algorithms","title":"Algorithms","text":"","category":"section"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"This section contains all main algorithms of the package. These are the ones typical users will call.","category":"page"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"The typical signature for these algorithms is:","category":"page"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"my_algorithm(f, grad!, lmo, x0)","category":"page"},{"location":"reference/1_algorithms/#Standard-algorithms","page":"Algorithms","title":"Standard algorithms","text":"","category":"section"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"Modules = [FrankWolfe]\nPages = [\"fw_algorithms.jl\"]","category":"page"},{"location":"reference/1_algorithms/#FrankWolfe.frank_wolfe-NTuple{4, Any}","page":"Algorithms","title":"FrankWolfe.frank_wolfe","text":"frank_wolfe(f, grad!, lmo, x0; ...)\n\nSimplest form of the Frank-Wolfe algorithm. Returns a tuple (x, v, primal, dual_gap, traj_data) with:\n\nx final iterate\nv last vertex from the LMO\nprimal primal value f(x)\ndual_gap final Frank-Wolfe gap\ntraj_data vector of trajectory information.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.lazified_conditional_gradient-NTuple{4, Any}","page":"Algorithms","title":"FrankWolfe.lazified_conditional_gradient","text":"lazified_conditional_gradient(f, grad!, lmo_base, x0; ...)\n\nSimilar to FrankWolfe.frank_wolfe but lazyfying the LMO: each call is stored in a cache, which is looked up first for a good-enough direction. The cache used is a FrankWolfe.MultiCacheLMO or a FrankWolfe.VectorCacheLMO depending on whether the provided cache_size option is finite.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.stochastic_frank_wolfe-Tuple{FrankWolfe.StochasticObjective, Any, Any}","page":"Algorithms","title":"FrankWolfe.stochastic_frank_wolfe","text":"stochastic_frank_wolfe(f::StochasticObjective, lmo, x0; ...)\n\nStochastic version of Frank-Wolfe, evaluates the objective and gradient stochastically, implemented through the FrankWolfe.StochasticObjective interface.\n\nKeyword arguments include batch_size to pass a fixed batch_size or a batch_iterator implementing batch_size = FrankWolfe.batchsize_iterate(batch_iterator) for algorithms like Variance-reduced and projection-free stochastic optimization, E Hazan, H Luo, 2016.\n\nSimilarly, a constant momentum can be passed or replaced by a momentum_iterator implementing momentum = FrankWolfe.momentum_iterate(momentum_iterator).\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"FrankWolfe.block_coordinate_frank_wolfe","category":"page"},{"location":"reference/1_algorithms/#FrankWolfe.block_coordinate_frank_wolfe","page":"Algorithms","title":"FrankWolfe.block_coordinate_frank_wolfe","text":"block_coordinate_frank_wolfe(f, grad!, lmo::ProductLMO{N}, x0; ...) where {N}\n\nBlock-coordinate version of the Frank-Wolfe algorithm. Minimizes objective f over the product of feasible domains specified by the lmo. The optional argument the update_order is of type FrankWolfe.BlockCoordinateUpdateOrder and controls the order in which the blocks are updated. The argument update_step is a single instance or tuple of FrankWolfe.UpdateStep and defines which FW-algorithms to use to update the iterates in the different blocks.\n\nThe method returns a tuple (x, v, primal, dual_gap, traj_data) with:\n\nx cartesian product of final iterates\nv cartesian product of last vertices of the LMOs\nprimal primal value f(x)\ndual_gap final Frank-Wolfe gap\ntraj_data vector of trajectory information.\n\nSee S. Lacoste-Julien, M. Jaggi, M. Schmidt, and P. Pletscher 2013 and A. Beck, E. Pauwels and S. Sabach 2015 for more details about Block-Coordinate Frank-Wolfe.\n\n\n\n\n\n","category":"function"},{"location":"reference/1_algorithms/#Active-set-based-methods","page":"Algorithms","title":"Active-set based methods","text":"","category":"section"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"The following algorithms maintain the representation of the iterates as a convex combination of vertices.","category":"page"},{"location":"reference/1_algorithms/#Away-step","page":"Algorithms","title":"Away-step","text":"","category":"section"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"Modules = [FrankWolfe]\nPages = [\"afw.jl\"]","category":"page"},{"location":"reference/1_algorithms/#FrankWolfe.away_frank_wolfe-NTuple{4, Any}","page":"Algorithms","title":"FrankWolfe.away_frank_wolfe","text":"away_frank_wolfe(f, grad!, lmo, x0; ...)\n\nFrank-Wolfe with away steps. The algorithm maintains the current iterate as a convex combination of vertices in the FrankWolfe.ActiveSet data structure. See M. Besançon, A. Carderera and S. Pokutta 2021 for illustrations of away steps.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#Pairwise-Frank-Wolfe","page":"Algorithms","title":"Pairwise Frank-Wolfe","text":"","category":"section"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"Modules = [FrankWolfe]\nPages = [\"pairwise.jl\"]","category":"page"},{"location":"reference/1_algorithms/#FrankWolfe.blended_pairwise_conditional_gradient-NTuple{4, Any}","page":"Algorithms","title":"FrankWolfe.blended_pairwise_conditional_gradient","text":"blended_pairwise_conditional_gradient(f, grad!, lmo, x0; kwargs...)\n\nImplements the BPCG algorithm from Tsuji, Tanaka, Pokutta (2021). The method uses an active set of current vertices. Unlike away-step, it transfers weight from an away vertex to another vertex of the active set.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.blended_pairwise_conditional_gradient-Union{Tuple{R}, Tuple{AT}, Tuple{Any, Any, Any, FrankWolfe.AbstractActiveSet{AT, R, IT} where IT}} where {AT, R}","page":"Algorithms","title":"FrankWolfe.blended_pairwise_conditional_gradient","text":"blended_pairwise_conditional_gradient(f, grad!, lmo, active_set::AbstractActiveSet; kwargs...)\n\nWarm-starts BPCG with a pre-defined active_set.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.pairwise_frank_wolfe-NTuple{4, Any}","page":"Algorithms","title":"FrankWolfe.pairwise_frank_wolfe","text":"pairwise_frank_wolfe(f, grad!, lmo, x0; ...)\n\nFrank-Wolfe with pairwise steps. The algorithm maintains the current iterate as a convex combination of vertices in the FrankWolfe.ActiveSet data structure. See M. Besançon, A. Carderera and S. Pokutta 2021 for illustrations of away steps. Unlike away-step, it transfers weight from an away vertex to another vertex.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#Blended-Conditional-Gradient","page":"Algorithms","title":"Blended Conditional Gradient","text":"","category":"section"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"Modules = [FrankWolfe]\nPages = [\"blended_cg.jl\"]","category":"page"},{"location":"reference/1_algorithms/#FrankWolfe.accelerated_simplex_gradient_descent_over_probability_simplex-Tuple{Any, Any, Any, Any, Any, Any, FrankWolfe.AbstractActiveSet}","page":"Algorithms","title":"FrankWolfe.accelerated_simplex_gradient_descent_over_probability_simplex","text":"accelerated_simplex_gradient_descent_over_probability_simplex\n\nMinimizes an objective function over the unit probability simplex until the Strong-Wolfe gap is below tolerance using Nesterov's accelerated gradient descent.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.blended_conditional_gradient-NTuple{4, Any}","page":"Algorithms","title":"FrankWolfe.blended_conditional_gradient","text":"blended_conditional_gradient(f, grad!, lmo, x0)\n\nEntry point for the Blended Conditional Gradient algorithm. See Braun, Gábor, et al. \"Blended conditonal gradients\" ICML 2019. The method works on an active set like FrankWolfe.away_frank_wolfe, performing gradient descent over the convex hull of active vertices, removing vertices when their weight drops to 0 and adding new vertices by calling the linear oracle in a lazy fashion.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.build_reduced_problem-Tuple{AbstractVector{var\"#s445\"} where var\"#s445\"<:FrankWolfe.ScaledHotVector, Any, Any, Any, Any}","page":"Algorithms","title":"FrankWolfe.build_reduced_problem","text":"build_reduced_problem(atoms::AbstractVector{<:AbstractVector}, hessian, weights, gradient, tolerance)\n\nGiven an active set formed by vectors , a (constant) Hessian and a gradient constructs a quadratic problem over the unit probability simplex that is equivalent to minimizing the original function over the convex hull of the active set. If λ are the barycentric coordinates of dimension equal to the cardinality of the active set, the objective function is:\n\nf(λ) = reduced_linear^T λ + 0.5 * λ^T reduced_hessian λ\n\nIn the case where we find that the current iterate has a strong-Wolfe gap over the convex hull of the active set that is below the tolerance we return nothing (as there is nothing to do).\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.lp_separation_oracle-Tuple{FrankWolfe.LinearMinimizationOracle, FrankWolfe.AbstractActiveSet, Any, Any, Any}","page":"Algorithms","title":"FrankWolfe.lp_separation_oracle","text":"Returns either a tuple (y, val) with y an atom from the active set satisfying the progress criterion and val the corresponding gap dot(y, direction) or the same tuple with y from the LMO.\n\ninplace_loop controls whether the iterate type allows in-place writes. kwargs are passed on to the LMO oracle.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.minimize_over_convex_hull!-Union{Tuple{R}, Tuple{AT}, Tuple{Any, Any, Any, FrankWolfe.AbstractActiveSet{AT, R, IT} where IT, Any, Any, Any, Any}} where {AT, R}","page":"Algorithms","title":"FrankWolfe.minimize_over_convex_hull!","text":"minimize_over_convex_hull!\n\nGiven a function f with gradient grad! and an active set active_set this function will minimize the function over the convex hull of the active set until the strong-wolfe gap over the active set is below tolerance.\n\nIt will either directly minimize over the convex hull using simplex gradient descent, or it will transform the problem to barycentric coordinates and minimize over the unit probability simplex using gradient descent or Nesterov's accelerated gradient descent.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.projection_simplex_sort-Tuple{Any}","page":"Algorithms","title":"FrankWolfe.projection_simplex_sort","text":"projection_simplex_sort(x; s=1.0)\n\nPerform a projection onto the probability simplex of radius s using a sorting algorithm.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.simplex_gradient_descent_over_convex_hull-Union{Tuple{R}, Tuple{AT}, Tuple{Any, Any, Any, FrankWolfe.AbstractActiveSet{AT, R, IT} where IT, Any, Any, Any, Any}, Tuple{Any, Any, Any, FrankWolfe.AbstractActiveSet{AT, R, IT} where IT, Any, Any, Any, Any, FrankWolfe.MemoryEmphasis}} where {AT, R}","page":"Algorithms","title":"FrankWolfe.simplex_gradient_descent_over_convex_hull","text":"simplex_gradient_descent_over_convex_hull(f, grad!, gradient, active_set, tolerance, t, time_start, non_simplex_iter)\n\nMinimizes an objective function over the convex hull of the active set until the Strong-Wolfe gap is below tolerance using simplex gradient descent.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.simplex_gradient_descent_over_probability_simplex-Tuple{Any, Any, Any, Any, Any, Any, Any, FrankWolfe.AbstractActiveSet}","page":"Algorithms","title":"FrankWolfe.simplex_gradient_descent_over_probability_simplex","text":"simplex_gradient_descent_over_probability_simplex\n\nMinimizes an objective function over the unit probability simplex until the Strong-Wolfe gap is below tolerance using gradient descent.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.strong_frankwolfe_gap-Tuple{Any}","page":"Algorithms","title":"FrankWolfe.strong_frankwolfe_gap","text":"Checks the strong Frank-Wolfe gap for the reduced problem.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.strong_frankwolfe_gap_probability_simplex-Tuple{Any, Any}","page":"Algorithms","title":"FrankWolfe.strong_frankwolfe_gap_probability_simplex","text":"strong_frankwolfe_gap_probability_simplex\n\nCompute the Strong-Wolfe gap over the unit probability simplex given a gradient.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#Blended-Pairwise-Conditional-Gradient","page":"Algorithms","title":"Blended Pairwise Conditional Gradient","text":"","category":"section"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"Modules = [FrankWolfe]\nPages = [\"blended_pairwise.jl\"]","category":"page"},{"location":"reference/1_algorithms/#Alternating-Methods","page":"Algorithms","title":"Alternating Methods","text":"","category":"section"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"Problems over intersections of convex sets, i.e.","category":"page"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"min_x in bigcap_i=1^n P_i f(x)","category":"page"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"pose a challenge as one has to combine the information of two or more LMOs.","category":"page"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"FrankWolfe.alternating_linear_minimization converts the problem into a series of subproblems over single sets. To find a point within the intersection, one minimizes both the distance to the iterates of the other subproblems and the original objective function.","category":"page"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"FrankWolfe.alternating_projections solves feasibility problems over intersections of feasible regions.","category":"page"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"Modules = [FrankWolfe]\nPages = [\"alternating_methods.jl\"]","category":"page"},{"location":"reference/1_algorithms/#FrankWolfe.alternating_linear_minimization-Union{Tuple{LS}, Tuple{N}, Tuple{Any, Any, Any, Tuple{Vararg{FrankWolfe.LinearMinimizationOracle, N}}, Tuple{Vararg{Any, N}}}} where {N, LS<:Union{Tuple{Vararg{FrankWolfe.LineSearchMethod, N}}, FrankWolfe.LineSearchMethod}}","page":"Algorithms","title":"FrankWolfe.alternating_linear_minimization","text":"alternating_linear_minimization(bc_algo::BlockCoordinateMethod, f, grad!, lmos::NTuple{N,LinearMinimizationOracle}, x0; ...) where {N}\n\nAlternating Linear Minimization minimizes the objective f over the intersections of the feasible domains specified by lmos. The tuple x0 defines the initial points for each domain. Returns a tuple (x, v, primal, dual_gap, dist2, traj_data) with:\n\nx cartesian product of final iterates\nv cartesian product of last vertices of the LMOs\nprimal primal value f(x)\ndual_gap final Frank-Wolfe gap\ndist2 is 1/2 of the sum of squared, pairwise distances between iterates\ntraj_data vector of trajectory information.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#FrankWolfe.alternating_projections-Union{Tuple{N}, Tuple{Tuple{Vararg{FrankWolfe.LinearMinimizationOracle, N}}, Any}} where N","page":"Algorithms","title":"FrankWolfe.alternating_projections","text":"alternating_projections(lmos::NTuple{N,LinearMinimizationOracle}, x0; ...) where {N}\n\nComputes a point in the intersection of feasible domains specified by lmos. Returns a tuple (x, v, dual_gap, dist2, traj_data) with:\n\nx cartesian product of final iterates\nv cartesian product of last vertices of the LMOs\ndual_gap final Frank-Wolfe gap\ndist2 is 1/2 * sum of squared, pairwise distances between iterates\ntraj_data vector of trajectory information.\n\n\n\n\n\n","category":"method"},{"location":"reference/1_algorithms/#Index","page":"Algorithms","title":"Index","text":"","category":"section"},{"location":"reference/1_algorithms/","page":"Algorithms","title":"Algorithms","text":"Pages = [\"2_algorithms.md\"]","category":"page"},{"location":"reference/0_reference/#API-Reference","page":"API Reference","title":"API Reference","text":"","category":"section"},{"location":"reference/0_reference/","page":"API Reference","title":"API Reference","text":"The pages in this section reference the documentation for specific types and functions.","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"EditURL = \"../../../examples/docs_03_matrix_completion.jl\"","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_03_matrix_completion/#Matrix-Completion","page":"Matrix Completion","title":"Matrix Completion","text":"","category":"section"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"We present another example that is about matrix completion. The idea is, given a partially observed matrix YinmathbbR^mtimes n, to find XinmathbbR^mtimes n to minimize the sum of squared errors from the observed entries while 'completing' the matrix Y, i.e. filling the unobserved entries to match Y as good as possible. A detailed explanation can be found in section 4.2 of the paper. We will try to solve","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"min_X_*le tau sum_(ij)inmathcalI (X_ij-Y_ij)^2","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"where tau0, X_* is the nuclear norm, and mathcalI denotes the indices of the observed entries. We will use FrankWolfe.NuclearNormLMO and compare our Frank-Wolfe implementation with a Projected Gradient Descent (PGD) algorithm which, after each gradient descent step, projects the iterates back onto the nuclear norm ball. We use a movielens dataset for comparison.","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"using FrankWolfe\nusing ZipFile, DataFrames, CSV\n\nusing Random\nusing Plots\n\nusing Profile\n\nimport Arpack\nusing SparseArrays, LinearAlgebra\n\nusing LaTeXStrings\n\ntemp_zipfile = download(\"http://files.grouplens.org/datasets/movielens/ml-latest-small.zip\")\n\nzarchive = ZipFile.Reader(temp_zipfile)\n\nmovies_file = zarchive.files[findfirst(f -> occursin(\"movies\", f.name), zarchive.files)]\nmovies_frame = CSV.read(movies_file, DataFrame)\n\nratings_file = zarchive.files[findfirst(f -> occursin(\"ratings\", f.name), zarchive.files)]\nratings_frame = CSV.read(ratings_file, DataFrame)\n\nusers = unique(ratings_frame[:, :userId])\nmovies = unique(ratings_frame[:, :movieId])\n\n@assert users == eachindex(users)\nmovies_revert = zeros(Int, maximum(movies))\nfor (idx, m) in enumerate(movies)\n movies_revert[m] = idx\nend\nmovies_indices = [movies_revert[idx] for idx in ratings_frame[:, :movieId]]\n\nconst rating_matrix = sparse(\n ratings_frame[:, :userId],\n movies_indices,\n ratings_frame[:, :rating],\n length(users),\n length(movies),\n)\n\nmissing_rate = 0.05\n\nRandom.seed!(42)\n\nconst missing_ratings = Tuple{Int,Int}[]\nconst present_ratings = Tuple{Int,Int}[]\nlet\n (I, J, V) = SparseArrays.findnz(rating_matrix)\n for idx in eachindex(I)\n if V[idx] > 0\n if rand() <= missing_rate\n push!(missing_ratings, (I[idx], J[idx]))\n else\n push!(present_ratings, (I[idx], J[idx]))\n end\n end\n end\nend\n\nfunction f(X)\n r = 0.0\n for (i, j) in present_ratings\n r += 0.5 * (X[i, j] - rating_matrix[i, j])^2\n end\n return r\nend\n\nfunction grad!(storage, X)\n storage .= 0\n for (i, j) in present_ratings\n storage[i, j] = X[i, j] - rating_matrix[i, j]\n end\n return nothing\nend\n\nfunction test_loss(X)\n r = 0.0\n for (i, j) in missing_ratings\n r += 0.5 * (X[i, j] - rating_matrix[i, j])^2\n end\n return r\nend\n\nfunction project_nuclear_norm_ball(X; radius=1.0)\n U, sing_val, Vt = svd(X)\n if (sum(sing_val) <= radius)\n return X, -norm_estimation * U[:, 1] * Vt[:, 1]'\n end\n sing_val = FrankWolfe.projection_simplex_sort(sing_val, s=radius)\n return U * Diagonal(sing_val) * Vt', -norm_estimation * U[:, 1] * Vt[:, 1]'\nend\n\nnorm_estimation = 10 * Arpack.svds(rating_matrix, nsv=1, ritzvec=false)[1].S[1]\n\nconst lmo = FrankWolfe.NuclearNormLMO(norm_estimation)\nconst x0 = FrankWolfe.compute_extreme_point(lmo, ones(size(rating_matrix)))\nconst k = 10\n\ngradient = spzeros(size(x0)...)\ngradient_aux = spzeros(size(x0)...)\n\nfunction build_callback(trajectory_arr)\n return function callback(state, args...)\n return push!(trajectory_arr, (FrankWolfe.callback_state(state)..., test_loss(state.x)))\n end\nend","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"The smoothness constant is estimated:","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"num_pairs = 100\nL_estimate = -Inf\nfor i in 1:num_pairs\n global L_estimate\n u1 = rand(size(x0, 1))\n u1 ./= sum(u1)\n u1 .*= norm_estimation\n v1 = rand(size(x0, 2))\n v1 ./= sum(v1)\n x = FrankWolfe.RankOneMatrix(u1, v1)\n u2 = rand(size(x0, 1))\n u2 ./= sum(u2)\n u2 .*= norm_estimation\n v2 = rand(size(x0, 2))\n v2 ./= sum(v2)\n y = FrankWolfe.RankOneMatrix(u2, v2)\n grad!(gradient, x)\n grad!(gradient_aux, y)\n new_L = norm(gradient - gradient_aux) / norm(x - y)\n if new_L > L_estimate\n L_estimate = new_L\n end\nend","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"We can now perform projected gradient descent:","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"xgd = Matrix(x0)\nfunction_values = Float64[]\ntiming_values = Float64[]\nfunction_test_values = Float64[]\n\nls = FrankWolfe.Backtracking()\nls_storage = similar(xgd)\ntime_start = time_ns()\nfor _ in 1:k\n f_val = f(xgd)\n push!(function_values, f_val)\n push!(function_test_values, test_loss(xgd))\n push!(timing_values, (time_ns() - time_start) / 1e9)\n @info f_val\n grad!(gradient, xgd)\n xgd_new, vertex = project_nuclear_norm_ball(xgd - gradient / L_estimate, radius=norm_estimation)\n gamma = FrankWolfe.perform_line_search(\n ls,\n 1,\n f,\n grad!,\n gradient,\n xgd,\n xgd - xgd_new,\n 1.0,\n ls_storage,\n FrankWolfe.InplaceEmphasis(),\n )\n @. xgd -= gamma * (xgd - xgd_new)\nend\n\ntrajectory_arr_fw = Vector{Tuple{Int64,Float64,Float64,Float64,Float64,Float64}}()\ncallback = build_callback(trajectory_arr_fw)\nxfin, _, _, _, traj_data = FrankWolfe.frank_wolfe(\n f,\n grad!,\n lmo,\n x0;\n epsilon=1e-9,\n max_iteration=10 * k,\n print_iter=k / 10,\n verbose=false,\n line_search=FrankWolfe.Adaptive(),\n memory_mode=FrankWolfe.InplaceEmphasis(),\n gradient=gradient,\n callback=callback,\n)\n\ntrajectory_arr_lazy = Vector{Tuple{Int64,Float64,Float64,Float64,Float64,Float64}}()\ncallback = build_callback(trajectory_arr_lazy)\nxlazy, _, _, _, _ = FrankWolfe.lazified_conditional_gradient(\n f,\n grad!,\n lmo,\n x0;\n epsilon=1e-9,\n max_iteration=10 * k,\n print_iter=k / 10,\n verbose=false,\n line_search=FrankWolfe.Adaptive(),\n memory_mode=FrankWolfe.InplaceEmphasis(),\n gradient=gradient,\n callback=callback,\n)\n\n\ntrajectory_arr_lazy_ref = Vector{Tuple{Int64,Float64,Float64,Float64,Float64,Float64}}()\ncallback = build_callback(trajectory_arr_lazy_ref)\nxlazy, _, _, _, _ = FrankWolfe.lazified_conditional_gradient(\n f,\n grad!,\n lmo,\n x0;\n epsilon=1e-9,\n max_iteration=50 * k,\n print_iter=k / 10,\n verbose=false,\n line_search=FrankWolfe.Adaptive(),\n memory_mode=FrankWolfe.InplaceEmphasis(),\n gradient=gradient,\n callback=callback,\n)\n\nfw_test_values = getindex.(trajectory_arr_fw, 6)\nlazy_test_values = getindex.(trajectory_arr_lazy, 6)\n\nresults = Dict(\n \"svals_gd\" => svdvals(xgd),\n \"svals_fw\" => svdvals(xfin),\n \"svals_lcg\" => svdvals(xlazy),\n \"fw_test_values\" => fw_test_values,\n \"lazy_test_values\" => lazy_test_values,\n \"trajectory_arr_fw\" => trajectory_arr_fw,\n \"trajectory_arr_lazy\" => trajectory_arr_lazy,\n \"function_values_gd\" => function_values,\n \"function_values_test_gd\" => function_test_values,\n \"timing_values_gd\" => timing_values,\n \"trajectory_arr_lazy_ref\" => trajectory_arr_lazy_ref,\n)\n\nref_optimum = results[\"trajectory_arr_lazy_ref\"][end][2]\n\niteration_list = [\n [x[1] + 1 for x in results[\"trajectory_arr_fw\"]],\n [x[1] + 1 for x in results[\"trajectory_arr_lazy\"]],\n collect(1:1:length(results[\"function_values_gd\"])),\n]\ntime_list = [\n [x[5] for x in results[\"trajectory_arr_fw\"]],\n [x[5] for x in results[\"trajectory_arr_lazy\"]],\n results[\"timing_values_gd\"],\n]\nprimal_gap_list = [\n [x[2] - ref_optimum for x in results[\"trajectory_arr_fw\"]],\n [x[2] - ref_optimum for x in results[\"trajectory_arr_lazy\"]],\n [x - ref_optimum for x in results[\"function_values_gd\"]],\n]\ntest_list =\n [results[\"fw_test_values\"], results[\"lazy_test_values\"], results[\"function_values_test_gd\"]]\n\nlabel = [L\"\\textrm{FW}\", L\"\\textrm{L-CG}\", L\"\\textrm{GD}\"]\n\nplot_results(\n [primal_gap_list, primal_gap_list, test_list, test_list],\n [iteration_list, time_list, iteration_list, time_list],\n label,\n [L\"\\textrm{Iteration}\", L\"\\textrm{Time}\", L\"\\textrm{Iteration}\", L\"\\textrm{Time}\"],\n [\n L\"\\textrm{Primal Gap}\",\n L\"\\textrm{Primal Gap}\",\n L\"\\textrm{Test Error}\",\n L\"\\textrm{Test Error}\",\n ],\n xscalelog=[:log, :identity, :log, :identity],\n legend_position=[:bottomleft, nothing, nothing, nothing],\n)","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"","category":"page"},{"location":"examples/docs_03_matrix_completion/","page":"Matrix Completion","title":"Matrix Completion","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"EditURL = \"../../../examples/docs_12_quadratic_symmetric.jl\"","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/#Accelerations-for-quadratic-functions-and-symmetric-problems","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"","category":"section"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"This example illustrates how to exploit symmetry to reduce the dimension of the problem via SubspaceLMO. Moreover, active set based algorithms can be accelerated by using the specialized structure ActiveSetQuadraticProductCaching.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"The specific problem we consider here comes from quantum information and some context can be found here. Formally, we want to find the distance between a tensor of size m^N and the N-partite local polytope which is defined by its vertices","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"d^veca^(1)ldots veca^(N)_x_1ldots x_Ncoloneqqprod_n=1^Na^(n)_x_n","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"labeled by veca^(n)=a^(n)_1ldots a^(n)_m for nin1N, where a^(n)_x=pm1. In the bipartite case (N=2), this polytope is affinely equivalent to the cut polytope.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/#Import-and-setup","page":"Accelerations for quadratic functions and symmetric problems","title":"Import and setup","text":"","category":"section"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"We first import the necessary packages.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"import Combinatorics\nimport FrankWolfe\nimport LinearAlgebra\nimport Tullio","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"Then we can define our custom LMO, together with the method compute_extreme_point, which simply enumerates the vertices d^veca^(1) defined above. This structure is specialized for the case N=5 and contains pre-allocated fields used to accelerate the enumeration. Note that the output type (full tensor) is quite naive, but this is enough to illustrate the syntax in this toy example.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"struct BellCorrelationsLMO{T} <: FrankWolfe.LinearMinimizationOracle\n m::Int # size of the tensor\n tmp1::Array{T, 1}\n tmp2::Array{T, 2}\n tmp3::Array{T, 3}\n tmp4::Array{T, 4}\nend\n\nfunction FrankWolfe.compute_extreme_point(lmo::BellCorrelationsLMO{T}, A::Array{T, 5}; kwargs...) where {T <: Number}\n ax = [ones(T, lmo.m) for n in 1:5]\n sc1 = zero(T)\n sc2 = one(T)\n axm = [zeros(T, lmo.m) for n in 1:5]\n scm = typemax(T)\n L = 2^lmo.m\n aux = zeros(Int, lmo.m)\n for λa5 in 0:(L÷2)-1\n digits!(aux, λa5, base=2)\n ax[5] .= 2aux .- 1\n Tullio.@tullio lmo.tmp4[x1, x2, x3, x4] = A[x1, x2, x3, x4, x5] * ax[5][x5]\n for λa4 in 0:L-1\n digits!(aux, λa4, base=2)\n ax[4] .= 2aux .- 1\n Tullio.@tullio lmo.tmp3[x1, x2, x3] = lmo.tmp4[x1, x2, x3, x4] * ax[4][x4]\n for λa3 in 0:L-1\n digits!(aux, λa3, base=2)\n ax[3] .= 2aux .- 1\n Tullio.@tullio lmo.tmp2[x1, x2] = lmo.tmp3[x1, x2, x3] * ax[3][x3]\n for λa2 in 0:L-1\n digits!(aux, λa2, base=2)\n ax[2] .= 2aux .- 1\n LinearAlgebra.mul!(lmo.tmp1, lmo.tmp2, ax[2])\n for x1 in 1:lmo.m\n ax[1][x1] = lmo.tmp1[x1] > zero(T) ? -one(T) : one(T)\n end\n sc = LinearAlgebra.dot(ax[1], lmo.tmp1)\n if sc < scm\n scm = sc\n for n in 1:5\n axm[n] .= ax[n]\n end\n end\n end\n end\n end\n end\n return [axm[1][x1]*axm[2][x2]*axm[3][x3]*axm[4][x4]*axm[5][x5] for x1 in 1:lmo.m, x2 in 1:lmo.m, x3 in 1:lmo.m, x4 in 1:lmo.m, x5 in 1:lmo.m]\nend","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"Then we define our specific instance, coming from a GHZ state measured with measurements forming a regular polygon on the equator of the Bloch sphere. See this article for definitions and references.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"function correlation_tensor_GHZ_polygon(::Type{T}, N::Int, m::Int) where {T <: Number}\n res = zeros(T, m*ones(Int, N)...)\n tab_cos = [cos(x*T(pi)/m) for x in 0:N*m]\n tab_cos[abs.(tab_cos) .< Base.rtoldefault(T)] .= zero(T)\n for ci in CartesianIndices(res)\n res[ci] = tab_cos[sum(ci.I)-N+1]\n end\n return res\nend\n\nT = Float64\nverbose = true\nmax_iteration = 10^4\nm = 5\np = 0.23correlation_tensor_GHZ_polygon(T, 5, m)\nx0 = zeros(T, size(p))\nprintln() #hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"The objective function is simply frac12x-p_2^2, which we decompose in different terms for speed.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"normp2 = LinearAlgebra.dot(p, p) / 2\nf = let p = p, normp2 = normp2\n x -> LinearAlgebra.dot(x, x) / 2 - LinearAlgebra.dot(p, x) + normp2\nend\ngrad! = let p = p\n (storage, x) -> begin\n @inbounds for i in eachindex(x)\n storage[i] = x[i] - p[i]\n end\n end\nend\nprintln() #hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/#Naive-run","page":"Accelerations for quadratic functions and symmetric problems","title":"Naive run","text":"","category":"section"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"If we run the blended pairwise conditional gradient algorithm without modifications, convergence is not reached in 10000 iterations.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"lmo_naive = BellCorrelationsLMO{T}(m, zeros(T, m), zeros(T, m, m), zeros(T, m, m, m), zeros(T, m, m, m, m))\nFrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_naive, FrankWolfe.ActiveSet([(one(T), x0)]); verbose=false, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration=10) #hide\nas_naive = FrankWolfe.ActiveSet([(one(T), x0)])\n@time FrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_naive, as_naive; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)\nprintln() #hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/#Faster-active-set-for-quadratic-functions","page":"Accelerations for quadratic functions and symmetric problems","title":"Faster active set for quadratic functions","text":"","category":"section"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"A first acceleration can be obtained by using the active set specialized for the quadratic objective function, whose gradient is here x-p, explaining the hessian and linear part provided as arguments. The speedup is obtained by pre-computing some scalar products to quickly obtained, in each iteration, the best and worst atoms currently in the active set.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"FrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_naive, FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0)], LinearAlgebra.I, -p); verbose=false, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration=10) #hide\nasq_naive = FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0)], LinearAlgebra.I, -p)\n@time FrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_naive, asq_naive; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)\nprintln() #hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"In this small example, the acceleration is quite minimal, but as soon as one of the following conditions is met, significant speedups (factor ten at least) can be expected:","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"quite expensive scalar product between atoms, for instance, due to a high dimension (say, more than 10000),\nhigh number of atoms in the active set (say, more than 1000),\nhigh number of iterations (say, more than 100000), spending most of the time redistributing the weights in the active set.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/#Dimension-reduction-via-symmetrization","page":"Accelerations for quadratic functions and symmetric problems","title":"Dimension reduction via symmetrization","text":"","category":"section"},{"location":"examples/docs_12_quadratic_symmetric/#Permutation-of-the-tensor-axes","page":"Accelerations for quadratic functions and symmetric problems","title":"Permutation of the tensor axes","text":"","category":"section"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"It is easy to see that our specific instance remains invariant under permutation of the dimensions of the tensor. This means that all computations can be performed in the symmetric subspace, which leads to an important speedup, owing to the reduced dimension (hence reduced size of the final active set and reduced number of iterations).","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"The way to operate this in the FrankWolfe package is to use a symmetrized LMO, which basically does the following:","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"symmetrize the gradient, which is not necessary here as the gradient remains symmetric throughout the algorithm,\ncall the standard LMO,\nsymmetrize its output, which amounts to averaging over its orbit with respect to the group considered (here the symmetric group permuting the dimensions of the tensor).","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"function reynolds_permutedims(atom::Array{T, N}, lmo::BellCorrelationsLMO{T}) where {T <: Number, N}\n res = zeros(T, size(atom))\n for per in Combinatorics.permutations(1:N)\n res .+= permutedims(atom, per)\n end\n res ./= factorial(N)\n return res\nend\nprintln() #hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"Note that the second argument lmo is not used here but could in principle be exploited to obtain a very small speedup by precomputing and storing Combinatorics.permutations(1:N) in a dedicated field of our custom LMO.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"lmo_permutedims = FrankWolfe.SubspaceLMO(lmo_naive, reynolds_permutedims)\nFrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_permutedims, FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0)], LinearAlgebra.I, -p); verbose=false, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration=10) #hide\nasq_permutedims = FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0)], LinearAlgebra.I, -p)\n@time FrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_permutedims, asq_permutedims; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)\nprintln() #hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"Now, convergence is reached within 10000 iterations, and the size of the final active set is considerably smaller than before, thanks to the reduced dimension.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/#Uniqueness-pattern","page":"Accelerations for quadratic functions and symmetric problems","title":"Uniqueness pattern","text":"","category":"section"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"In this specific case, there is a bigger symmetry group that we can exploit. Its action roughly allows us to work in the subspace respecting the structure of the objective point p, that is, to average over tensor entries that have the same value in p. Although quite general, this kind of symmetry is not always applicable, and great care has to be taken when using it, in particular, to ensure that there exists a suitable group action whose Reynolds operator corresponds to this averaging procedure. In our current case, the theoretical study enabling this further symmetrization can be found here.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"function build_reynolds_unique(p::Array{T, N}) where {T <: Number, N}\n ptol = round.(p; digits=8)\n ptol[ptol .== zero(T)] .= zero(T) # transform -0.0 into 0.0 as isequal(0.0, -0.0) is false\n uniquetol = unique(ptol[:])\n indices = [ptol .== u for u in uniquetol]\n return function(A::Array{T, N}, lmo)\n res = zeros(T, size(A))\n for ind in indices\n @view(res[ind]) .= sum(A[ind]) / sum(ind) # average over ind\n end\n return res\n end\nend\n\nlmo_unique = FrankWolfe.SubspaceLMO(lmo_naive, build_reynolds_unique(p))\nFrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_unique, FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0)], LinearAlgebra.I, -p); verbose=false, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration=10) #hide\nasq_unique = FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0)], LinearAlgebra.I, -p)\n@time FrankWolfe.blended_pairwise_conditional_gradient(f, grad!, lmo_unique, asq_unique; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)\nprintln() #hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/#Reduction-of-the-memory-footprint-of-the-iterate","page":"Accelerations for quadratic functions and symmetric problems","title":"Reduction of the memory footprint of the iterate","text":"","category":"section"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"In the previous run, the dimension reduction is mathematically exploited to accelerate the algorithm, but it is not used to effectively work in a subspace of reduced dimension. Indeed, the iterate, although symmetric, was still a full tensor. As a last example of the speedup obtainable through symmetry reduction, we show how to map the computations into a space whose physical dimension is also reduced during the algorithm. This makes all in-place operations marginally faster, which can lead, in bigger instances, to significant accelerations, especially for active set based algorithms in the regime where many lazy iterations are performed. We refer to the example symmetric.jl for a small benchmark with symmetric matrices.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"function build_deflate_inflate(p::Array{T, N}) where {T <: Number, N}\n ptol = round.(p; digits=8)\n ptol[ptol .== zero(T)] .= zero(T) # transform -0.0 into 0.0 as isequal(0.0, -0.0) is false\n uniquetol = unique(ptol[:])\n dim = length(uniquetol) # reduced dimension\n indices = [ptol .== u for u in uniquetol]\n mul = [sum(ind) for ind in indices] # multiplicities, used to have matching scalar products\n sqmul = sqrt.(mul) # precomputed for speed\n return function(A::Array{T, N}, lmo)\n vec = zeros(T, dim)\n for (i, ind) in enumerate(indices)\n vec[i] = sum(A[ind]) / sqmul[i]\n end\n return FrankWolfe.SubspaceVector(A, vec)\n end, function(x::FrankWolfe.SubspaceVector, lmo)\n for (i, ind) in enumerate(indices)\n @view(x.data[ind]) .= x.vec[i] / sqmul[i]\n end\n return x.data\n end\nend\n\ndeflate, inflate = build_deflate_inflate(p)\np_deflate = deflate(p, nothing)\nx0_deflate = deflate(x0, nothing)\nf_deflate = let p_deflate = p_deflate, normp2 = normp2\n x -> LinearAlgebra.dot(x, x) / 2 - LinearAlgebra.dot(p_deflate, x) + normp2\nend\ngrad_deflate! = let p_deflate = p_deflate\n (storage, x) -> begin\n @inbounds for i in eachindex(x)\n storage[i] = x[i] - p_deflate[i]\n end\n end\nend\nprintln() #hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"Note that the objective function and its gradient have to be explicitly rewritten. In this simple example, their shape remains unchanged, but in general this may need some reformulation, which falls to the user.","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"lmo_deflate = FrankWolfe.SubspaceLMO(lmo_naive, deflate, inflate)\nFrankWolfe.blended_pairwise_conditional_gradient(f_deflate, grad_deflate!, lmo_deflate, FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0_deflate)], LinearAlgebra.I, -p_deflate); verbose=false, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration=10) #hide\nasq_deflate = FrankWolfe.ActiveSetQuadraticProductCaching([(one(T), x0_deflate)], LinearAlgebra.I, -p_deflate)\n@time FrankWolfe.blended_pairwise_conditional_gradient(f_deflate, grad_deflate!, lmo_deflate, asq_deflate; verbose, lazy=true, line_search=FrankWolfe.Shortstep(one(T)), max_iteration)\nprintln() #hide","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"","category":"page"},{"location":"examples/docs_12_quadratic_symmetric/","page":"Accelerations for quadratic functions and symmetric problems","title":"Accelerations for quadratic functions and symmetric problems","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"EditURL = \"../../../examples/docs_11_block_coordinate_fw.jl\"","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/#Block-Coordinate-Frank-Wolfe-and-Block-Vectors","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"","category":"section"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"In this example, we demonstrate the usage of the FrankWolfe.block_coordinate_frank_wolfe and FrankWolfe.BlockVector. We consider the problem of minimizing the squared Euclidean distance between two sets. We compare different update orders and different update steps.","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/#Import-and-setup","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Import and setup","text":"","category":"section"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"We first import the necessary packages and include the code for plotting the results.","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"using FrankWolfe\nusing LinearAlgebra\n\ninclude(\"plot_utils.jl\")","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"Next, we define the objective function and its gradient. The iterates x are instances of the FrankWolfe.BlockVector type. The different blocks of the vector can be accessed via the blocks field.","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"f(x) = dot(x.blocks[1] - x.blocks[2], x.blocks[1] - x.blocks[2])\n\nfunction grad!(storage, x)\n @. storage.blocks = [x.blocks[1] - x.blocks[2], x.blocks[2] - x.blocks[1]]\nend","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"In our example we consider the probability simplex and an L-infinity norm ball as the feasible sets.","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"n = 100\nlmo1 = FrankWolfe.ScaledBoundLInfNormBall(-ones(n), zeros(n))\nlmo2 = FrankWolfe.ProbabilitySimplexOracle(1.0)\nprod_lmo = FrankWolfe.ProductLMO((lmo1, lmo2))","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"We initialize the starting point x0 as a FrankWolfe.BlockVector with two blocks. The two other arguments are the block sizes and the overall number of entries.","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"x0 = FrankWolfe.BlockVector([-ones(n), [i == 1 ? 1 : 0 for i in 1:n]], [(n,), (n,)], 2 * n);\nnothing #hide","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/#Running-block-coordinate-Frank-Wolfe-with-different-update-orders","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Running block-coordinate Frank-Wolfe with different update-orders","text":"","category":"section"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"In a first step, we compare different update orders. There are three different update orders implemented, FrankWolfe.FullUpdate, CyclicUpdate and Stochasticupdate. For creating a custome FrankWolfe.BlockCoordinateUpdateOrder, one needs to implement the function select_update_indices.","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"struct CustomOrder <: FrankWolfe.BlockCoordinateUpdateOrder end\n\nfunction FrankWolfe.select_update_indices(::CustomOrder, state::FrankWolfe.CallbackState, dual_gaps)\n return [rand() < 1 / n ? 1 : 2 for _ in 1:length(state.lmo.lmos)]\nend","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"We run the block-coordinate Frank-Wolfe method with the different update orders and store the trajectories.","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"trajectories = []\n\nfor order in [\n FrankWolfe.FullUpdate(),\n FrankWolfe.CyclicUpdate(),\n FrankWolfe.StochasticUpdate(),\n CustomOrder(),\n]\n\n _, _, _, _, traj_data = FrankWolfe.block_coordinate_frank_wolfe(\n f,\n grad!,\n prod_lmo,\n x0;\n verbose=true,\n trajectory=true,\n update_order=order,\n )\n push!(trajectories, traj_data)\nend","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/#Plotting-the-results","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Plotting the results","text":"","category":"section"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"labels = [\"Full update\", \"Cyclic order\", \"Stochstic order\", \"Custom order\"]\nplot_trajectories(trajectories, labels, xscalelog=true)","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/#Running-BCFW-with-different-update-methods","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Running BCFW with different update methods","text":"","category":"section"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"As a second step, we compare different update steps. We consider the FrankWolfe.BPCGStep and the FrankWolfe.FrankWolfeStep. One can either pass a tuple of FrankWolfe.UpdateStep to define for each block the update procedure or pass a single update step so that each block uses the same procedure.","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"trajectories = []\n\nfor us in [(FrankWolfe.BPCGStep(), FrankWolfe.FrankWolfeStep()), (FrankWolfe.FrankWolfeStep(), FrankWolfe.BPCGStep()), FrankWolfe.BPCGStep(), FrankWolfe.FrankWolfeStep()]\n\n _, _, _, _, traj_data = FrankWolfe.block_coordinate_frank_wolfe(\n f,\n grad!,\n prod_lmo,\n x0;\n verbose=true,\n trajectory=true,\n update_step=us,\n )\n push!(trajectories, traj_data)\nend","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/#Plotting-the-results-2","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Plotting the results","text":"","category":"section"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"labels = [\"BPCG FW\", \"FW BPCG\", \"BPCG\", \"FW\"]\nplot_trajectories(trajectories, labels, xscalelog=true)","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"","category":"page"},{"location":"examples/docs_11_block_coordinate_fw/","page":"Block-Coordinate Frank-Wolfe and Block-Vectors","title":"Block-Coordinate Frank-Wolfe and Block-Vectors","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"EditURL = \"../../../examples/docs_10_alternating_methods.jl\"","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"import FrankWolfe; include(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\")) # hide","category":"page"},{"location":"examples/docs_10_alternating_methods/#Alternating-methods","page":"Alternating methods","title":"Alternating methods","text":"","category":"section"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"In this example we will compare FrankWolfe.alternating_linear_minimization and FrankWolfe.alternating_projections for a very simple feasibility problem.","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"We consider the probability simplex","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"P = x in mathbbR^n colon sum_i=1^n x_i = 1 x_i geq 0 i=1dotsn ","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"and a scaled, shifted ell^infty norm ball","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"Q = -10^n ","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"The goal is to find a point that lies both in P and Q. We do this by reformulating the problem first. Instead of a finding a point in the intersection P cap Q, we search for a pair of points, (x_P x_Q) in the cartesian product P times Q, which attains minimal distance between P and Q,","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"x_P - x_Q_2 = min_(xy) in P times Q x - y _2 ","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"using FrankWolfe\ninclude(\"../examples/plot_utils.jl\")","category":"page"},{"location":"examples/docs_10_alternating_methods/#Setting-up-objective,-gradient-and-linear-minimization-oracles","page":"Alternating methods","title":"Setting up objective, gradient and linear minimization oracles","text":"","category":"section"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"Alternating Linear Minimization (ALM) allows for an additional objective such that one can optimize over an intersection of sets instead of finding only feasible points. Since this example only considers the feasibility, we set the objective function as well as the gradient to zero.","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"n = 20\n\nf(x) = 0\n\nfunction grad!(storage, x)\n @. storage = zero(x)\nend\n\n\nlmo1 = FrankWolfe.ProbabilitySimplexOracle(1.0)\nlmo2 = FrankWolfe.ScaledBoundLInfNormBall(-ones(n), zeros(n))\nlmos = (lmo1, lmo2)\n\nx0 = rand(n)\n\ntarget_tolerance = 1e-6\n\ntrajectories = [];\nnothing #hide","category":"page"},{"location":"examples/docs_10_alternating_methods/#Running-Alternating-Linear-Minimization","page":"Alternating methods","title":"Running Alternating Linear Minimization","text":"","category":"section"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"The method FrankWolfe.alternating_linear_minimization is not a FrankWolfe method itself. It is a wrapper translating a problem over the intersection of multiple sets to a problem over the product space. ALM can be called with any FW method. The default choice though is FrankWolfe.block_coordinate_frank_wolfe as it allows to update the blocks separately. There are three different update orders implemented, FullUpdate, CyclicUpdate and Stochasticupdate. Accordingly both blocks are updated either simulatenously, sequentially or in random order.","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"for order in [FrankWolfe.FullUpdate(), FrankWolfe.CyclicUpdate(), FrankWolfe.StochasticUpdate()]\n\n _, _, _, _, _, alm_trajectory = FrankWolfe.alternating_linear_minimization(\n FrankWolfe.block_coordinate_frank_wolfe,\n f,\n grad!,\n lmos,\n x0,\n update_order=order,\n verbose=true,\n trajectory=true,\n epsilon=target_tolerance,\n )\n push!(trajectories, alm_trajectory)\nend","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"As an alternative to Block-Coordiante Frank-Wolfe (BCFW), one can also run alternating linear minimization with standard Frank-Wolfe algorithm. These methods perform then the full (simulatenous) update at each iteration. In this example we also use FrankWolfe.away_frank_wolfe.","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"_, _, _, _, _, afw_trajectory = FrankWolfe.alternating_linear_minimization(\n FrankWolfe.away_frank_wolfe,\n f,\n grad!,\n lmos,\n x0,\n verbose=true,\n trajectory=true,\n epsilon=target_tolerance,\n)\npush!(trajectories, afw_trajectory);\nnothing #hide","category":"page"},{"location":"examples/docs_10_alternating_methods/#Running-Alternating-Projections","page":"Alternating methods","title":"Running Alternating Projections","text":"","category":"section"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"Unlike ALM, Alternating Projections (AP) is only suitable for feasibility problems. One omits the objective and gradient as parameters.","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"_, _, _, _, ap_trajectory = FrankWolfe.alternating_projections(\n lmos,\n x0,\n trajectory=true,\n verbose=true,\n print_iter=100,\n epsilon=target_tolerance,\n)\npush!(trajectories, ap_trajectory);\nnothing #hide","category":"page"},{"location":"examples/docs_10_alternating_methods/#Plotting-the-resulting-trajectories","page":"Alternating methods","title":"Plotting the resulting trajectories","text":"","category":"section"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"labels = [\"BCFW - Full\", \"BCFW - Cyclic\", \"BCFW - Stochastic\", \"AFW\", \"AP\"]\n\nplot_trajectories(trajectories, labels, xscalelog=true)","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"","category":"page"},{"location":"examples/docs_10_alternating_methods/","page":"Alternating methods","title":"Alternating methods","text":"This page was generated using Literate.jl.","category":"page"},{"location":"","page":"Home","title":"Home","text":"EditURL = \"https://github.com/ZIB-IOL/FrankWolfe.jl/blob/master/README.md\"","category":"page"},{"location":"#FrankWolfe.jl","page":"Home","title":"FrankWolfe.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"(Image: Build Status) (Image: Dev) (Image: Stable) (Image: Coverage) (Image: DOI)","category":"page"},{"location":"","page":"Home","title":"Home","text":"This package is a toolbox for Frank-Wolfe and conditional gradients algorithms.","category":"page"},{"location":"#Overview","page":"Home","title":"Overview","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Frank-Wolfe algorithms were designed to solve optimization problems of the form min_x C f(x), where f is a differentiable convex function and C is a convex and compact set. They are especially useful when we know how to optimize a linear function over C in an efficient way.","category":"page"},{"location":"","page":"Home","title":"Home","text":"A paper presenting the package with mathematical explanations and numerous examples can be found here:","category":"page"},{"location":"","page":"Home","title":"Home","text":"FrankWolfe.jl: A high-performance and flexible toolbox for Frank-Wolfe algorithms and Conditional Gradients.","category":"page"},{"location":"#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"The most recent release is available via the julia package manager, e.g., with","category":"page"},{"location":"","page":"Home","title":"Home","text":"using Pkg\nPkg.add(\"FrankWolfe\")","category":"page"},{"location":"","page":"Home","title":"Home","text":"or the master branch:","category":"page"},{"location":"","page":"Home","title":"Home","text":"Pkg.add(url=\"https://github.com/ZIB-IOL/FrankWolfe.jl\", rev=\"master\")","category":"page"},{"location":"#Getting-started","page":"Home","title":"Getting started","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Let's say we want to minimize the Euclidian norm over the probability simplex Δ. Using FrankWolfe.jl, this is what the code looks like (in dimension 3):","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> using FrankWolfe\n\njulia> f(p) = sum(abs2, p) # objective function\n\njulia> grad!(storage, p) = storage .= 2p # in-place gradient computation\n\n# # function d ⟼ argmin ⟨p,d⟩ st. p ∈ Δ\njulia> lmo = FrankWolfe.ProbabilitySimplexOracle(1.)\n\njulia> p0 = [1., 0., 0.]\n\njulia> p_opt, _ = frank_wolfe(f, grad!, lmo, p0; verbose=true);\n\nVanilla Frank-Wolfe Algorithm.\nMEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: Adaptive EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64\nMOMENTUM: nothing GRADIENTTYPE: Nothing\n[ Info: In memory_mode memory iterates are written back into x0!\n\n-------------------------------------------------------------------------------------------------\n Type Iteration Primal Dual Dual Gap Time It/sec\n-------------------------------------------------------------------------------------------------\n I 1 1.000000e+00 -1.000000e+00 2.000000e+00 0.000000e+00 Inf\n Last 24 3.333333e-01 3.333332e-01 9.488992e-08 1.533181e+00 1.565373e+01\n-------------------------------------------------------------------------------------------------\n\njulia> p_opt\n3-element Vector{Float64}:\n 0.33333334349923327\n 0.33333332783841896\n 0.3333333286623478","category":"page"},{"location":"","page":"Home","title":"Home","text":"Note that active-set based methods like Away Frank-Wolfe and Blended Pairwise Conditional Gradient also include a post processing step. In post-processing all values are recomputed and in particular the dual gap is computed at the current FW vertex, which might be slightly larger than the best dual gap observed as the gap is not monotonic. This is expected behavior.","category":"page"},{"location":"#Documentation-and-examples","page":"Home","title":"Documentation and examples","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"To explore the content of the package, go to the documentation.","category":"page"},{"location":"","page":"Home","title":"Home","text":"Beyond those presented in the documentation, many more use cases are implemented in the examples folder. To run them, you will need to activate the test environment, which can be done simply with TestEnv.jl (we recommend you install it in your base Julia).","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> using TestEnv\n\njulia> TestEnv.activate()\n\"/tmp/jl_Ux8wKE/Project.toml\"\n\n# necessary for plotting\njulia> include(\"examples/plot_utils.jl\")\njulia> include(\"examples/linear_regression.jl\")\n...","category":"page"},{"location":"","page":"Home","title":"Home","text":"If you need the plotting utilities in your own code, make sure Plots.jl is included in your current project and run:","category":"page"},{"location":"","page":"Home","title":"Home","text":"using Plots\nusing FrankWolfe\n\ninclude(joinpath(dirname(pathof(FrankWolfe)), \"../examples/plot_utils.jl\"))","category":"page"},{"location":"reference/3_backend/#Utilities-and-data-structures","page":"Utilities and data structures","title":"Utilities and data structures","text":"","category":"section"},{"location":"reference/3_backend/#Active-set","page":"Utilities and data structures","title":"Active set","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"Modules = [FrankWolfe]\nPages = [\"active_set.jl\", \"active_set_quadratic.jl\", \"active_set_quadratic_direct_solve.jl\", \"active_set_sparsifier.jl\"]","category":"page"},{"location":"reference/3_backend/#FrankWolfe.AbstractActiveSet","page":"Utilities and data structures","title":"FrankWolfe.AbstractActiveSet","text":"AbstractActiveSet{AT, R, IT}\n\nAbstract type for an active set of atoms of type AT with weights of type R and iterate of type IT. An active set is typically expected to have a field weights, a field atoms, and a field x. Otherwise, all active set methods from src/active_set.jl can be overwritten.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.ActiveSet","page":"Utilities and data structures","title":"FrankWolfe.ActiveSet","text":"ActiveSet{AT, R, IT}\n\nRepresents an active set of extreme vertices collected in a FW algorithm, along with their coefficients (λ_i, a_i). R is the type of the λ_i, AT is the type of the atoms a_i. The iterate x = ∑λ_i a_i is stored in x with type IT.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#Base.copy-Union{Tuple{FrankWolfe.AbstractActiveSet{AT, R, IT}}, Tuple{IT}, Tuple{R}, Tuple{AT}} where {AT, R, IT}","page":"Utilities and data structures","title":"Base.copy","text":"Copies an active set, the weight and atom vectors and the iterate. Individual atoms are not copied.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.active_set_argmin-Tuple{FrankWolfe.AbstractActiveSet, Any}","page":"Utilities and data structures","title":"FrankWolfe.active_set_argmin","text":"active_set_argmin(active_set::AbstractActiveSet, direction)\n\nComputes the linear minimizer in the direction on the active set. Returns (λ_i, a_i, i)\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.active_set_argminmax-Tuple{FrankWolfe.AbstractActiveSet, Any}","page":"Utilities and data structures","title":"FrankWolfe.active_set_argminmax","text":"active_set_argminmax(active_set::AbstractActiveSet, direction)\n\nComputes the linear minimizer in the direction on the active set. Returns (λ_min, a_min, i_min, val_min, λ_max, a_max, i_max, val_max, val_max-val_min ≥ Φ)\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.active_set_initialize!-Union{Tuple{R}, Tuple{AT}, Tuple{FrankWolfe.AbstractActiveSet{AT, R, IT} where IT, Any}} where {AT, R}","page":"Utilities and data structures","title":"FrankWolfe.active_set_initialize!","text":"active_set_initialize!(as, v)\n\nResets the active set structure to a single vertex v with unit weight.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.active_set_update!-Union{Tuple{R}, Tuple{AT}, Tuple{FrankWolfe.AbstractActiveSet{AT, R, IT} where IT, Any, Any}, Tuple{FrankWolfe.AbstractActiveSet{AT, R, IT} where IT, Any, Any, Any}, Tuple{FrankWolfe.AbstractActiveSet{AT, R, IT} where IT, Any, Any, Any, Any}} where {AT, R}","page":"Utilities and data structures","title":"FrankWolfe.active_set_update!","text":"active_set_update!(active_set::AbstractActiveSet, lambda, atom)\n\nAdds the atom to the active set with weight lambda or adds lambda to existing atom.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.active_set_update_iterate_pairwise!-Union{Tuple{A}, Tuple{IT}, Tuple{IT, Real, A, A}} where {IT, A}","page":"Utilities and data structures","title":"FrankWolfe.active_set_update_iterate_pairwise!","text":"active_set_update_iterate_pairwise!(active_set, x, lambda, fw_atom, away_atom)\n\nOperates x ← x + λ a_fw - λ a_aw.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.active_set_update_scale!-Union{Tuple{IT}, Tuple{IT, Any, Any}} where IT","page":"Utilities and data structures","title":"FrankWolfe.active_set_update_scale!","text":"active_set_update_scale!(x, lambda, atom)\n\nOperates x ← (1-λ) x + λ a.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.compute_active_set_iterate!-Tuple{Any}","page":"Utilities and data structures","title":"FrankWolfe.compute_active_set_iterate!","text":"compute_active_set_iterate!(active_set::AbstractActiveSet) -> x\n\nRecomputes from scratch the iterate x from the current weights and vertices of the active set. Returns the iterate x.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.get_active_set_iterate-Tuple{Any}","page":"Utilities and data structures","title":"FrankWolfe.get_active_set_iterate","text":"get_active_set_iterate(active_set)\n\nReturn the current iterate corresponding. Does not recompute it.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.ActiveSetQuadraticProductCaching","page":"Utilities and data structures","title":"FrankWolfe.ActiveSetQuadraticProductCaching","text":"ActiveSetQuadraticProductCaching{AT, R, IT}\n\nRepresents an active set of extreme vertices collected in a FW algorithm, along with their coefficients (λ_i, a_i). R is the type of the λ_i, AT is the type of the atoms a_i. The iterate x = ∑λ_i a_i is stored in x with type IT. The objective function is assumed to be of the form f(x)=½⟨x,Ax⟩+⟨b,x⟩+c so that the gradient is simply ∇f(x)=Ax+b.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.ActiveSetQuadraticLinearSolve","page":"Utilities and data structures","title":"FrankWolfe.ActiveSetQuadraticLinearSolve","text":"ActiveSetQuadraticLinearSolve{AT, R, IT}\n\nRepresents an active set of extreme vertices collected in a FW algorithm, along with their coefficients (λ_i, a_i). R is the type of the λ_i, AT is the type of the atoms a_i. The iterate x = ∑λ_i a_i is stored in x with type IT. The objective function is assumed to be of the form f(x)=½⟨x,Ax⟩+⟨b,x⟩+c so that the gradient is ∇f(x)=Ax+b.\n\nThis active set stores an inner active_set that keeps track of the current set of vertices and convex decomposition. It therefore delegates all update, deletion, and addition operations to this inner active set. The weight, atoms, and x fields should only be accessed to read and are effectively the same objects as those in the inner active set. The flag wolfe_step determines whether to use a Wolfe step from the min-norm point algorithm or the normal direct solve. The Wolfe step solves the auxiliary subproblem over the affine hull of the current active set (instead of the convex hull).\n\nThe structure also contains a scheduler struct which is called with the should_solve_lp function. To define a new frequency at which the LP should be solved, one can define another scheduler struct and implement the corresponding method.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.ActiveSetQuadraticLinearSolve-Union{Tuple{H}, Tuple{R}, Tuple{AT}, Tuple{Array{Tuple{R, AT}, 1}, H, Any, Any}} where {AT, R, H}","page":"Utilities and data structures","title":"FrankWolfe.ActiveSetQuadraticLinearSolve","text":"ActiveSetQuadraticLinearSolve(tuple_values::Vector{Tuple{R,AT}}, A, b, lp_optimizer)\n\nCreates an ActiveSetQuadraticLinearSolve from the given Hessian A, linear term b and lp_optimizer by creating an inner ActiveSetQuadraticProductCaching active set.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.ActiveSetQuadraticLinearSolve-Union{Tuple{R}, Tuple{AT}, Tuple{Array{Tuple{R, AT}, 1}, Function, Any}} where {AT, R}","page":"Utilities and data structures","title":"FrankWolfe.ActiveSetQuadraticLinearSolve","text":"ActiveSetQuadraticLinearSolve(tuple_values::Vector{Tuple{R,AT}}, grad!::Function, lp_optimizer)\n\nCreates an ActiveSetQuadraticLinearSolve by computing the Hessian and linear term from grad!.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.solve_quadratic_activeset_lp!-Union{Tuple{FrankWolfe.ActiveSetQuadraticLinearSolve{AT, R, IT, H, BT, OT, AS, SF} where {BT, OT<:MathOptInterface.AbstractOptimizer, AS<:FrankWolfe.AbstractActiveSet, SF}}, Tuple{H}, Tuple{IT}, Tuple{R}, Tuple{AT}} where {AT, R, IT, H}","page":"Utilities and data structures","title":"FrankWolfe.solve_quadratic_activeset_lp!","text":"solve_quadratic_activeset_lp!(as::ActiveSetQuadraticLinearSolve{AT, R, IT, H}))\n\nSolves the auxiliary LP over the current active set. The method is specialized by type H of the Hessian matrix A.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#Functions-and-gradients","page":"Utilities and data structures","title":"Functions and gradients","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"Modules = [FrankWolfe]\nPages = [\"function_gradient.jl\"]","category":"page"},{"location":"reference/3_backend/#FrankWolfe.ObjectiveFunction","page":"Utilities and data structures","title":"FrankWolfe.ObjectiveFunction","text":"ObjectiveFunction\n\nRepresents an objective function optimized by algorithms. Subtypes of ObjectiveFunction must implement at least\n\ncompute_value(::ObjectiveFunction, x) for primal value evaluation\ncompute_gradient(::ObjectiveFunction, x) for gradient evaluation.\n\nand optionally compute_value_gradient(::ObjectiveFunction, x) returning the (primal, gradient) pair. compute_gradient may always use the same storage and return a reference to it.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.SimpleFunctionObjective","page":"Utilities and data structures","title":"FrankWolfe.SimpleFunctionObjective","text":"SimpleFunctionObjective{F,G,S}\n\nAn objective function built from separate primal objective f(x) and in-place gradient function grad!(storage, x). It keeps an internal storage of type s used to evaluate the gradient in-place.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.StochasticObjective","page":"Utilities and data structures","title":"FrankWolfe.StochasticObjective","text":"StochasticObjective{F, G, XT, S}(f::F, grad!::G, xs::XT, storage::S)\n\nRepresents a composite function evaluated with stochastic gradient. f(θ, x) evaluates the loss for a single data point x and parameter θ. grad!(storage, θ, x) adds to storage the partial gradient with respect to data point x at parameter θ. xs must be an indexable iterable (Vector{Vector{Float64}} for instance). Functions using a StochasticObjective have optional keyword arguments rng, batch_size and full_evaluation controlling whether the function should be evaluated over all data points.\n\nNote: grad! must not reset the storage to 0 before adding to it.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.compute_gradient","page":"Utilities and data structures","title":"FrankWolfe.compute_gradient","text":"compute_gradient(f::ObjectiveFunction, x; [kwargs...])\n\nComputes the gradient of f at x. May return a reference to an internal storage.\n\n\n\n\n\n","category":"function"},{"location":"reference/3_backend/#FrankWolfe.compute_value","page":"Utilities and data structures","title":"FrankWolfe.compute_value","text":"compute_value(f::ObjectiveFunction, x; [kwargs...])\n\nComputes the objective f at x.\n\n\n\n\n\n","category":"function"},{"location":"reference/3_backend/#FrankWolfe.compute_value_gradient-Tuple{FrankWolfe.ObjectiveFunction, Any}","page":"Utilities and data structures","title":"FrankWolfe.compute_value_gradient","text":"compute_value_gradient(f::ObjectiveFunction, x; [kwargs...])\n\nComputes in one call the pair (value, gradient) evaluated at x. By default, calls compute_value and compute_gradient with keywords kwargs passed down to both.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#Callbacks","page":"Utilities and data structures","title":"Callbacks","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"FrankWolfe.CallbackState","category":"page"},{"location":"reference/3_backend/#FrankWolfe.CallbackState","page":"Utilities and data structures","title":"FrankWolfe.CallbackState","text":"Main structure created before and passed to the callback in first position.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#Custom-vertex-storage","page":"Utilities and data structures","title":"Custom vertex storage","text":"","category":"section"},{"location":"reference/3_backend/#Custom-extreme-point-types","page":"Utilities and data structures","title":"Custom extreme point types","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"For some feasible sets, the extreme points of the feasible set returned by the LMO possess a specific structure that can be represented in an efficient manner both for storage and for common operations like scaling and addition with an iterate. They are presented below:","category":"page"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"FrankWolfe.ScaledHotVector\nFrankWolfe.RankOneMatrix","category":"page"},{"location":"reference/3_backend/#FrankWolfe.ScaledHotVector","page":"Utilities and data structures","title":"FrankWolfe.ScaledHotVector","text":"ScaledHotVector{T}\n\nRepresents a vector of at most one value different from 0.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.RankOneMatrix","page":"Utilities and data structures","title":"FrankWolfe.RankOneMatrix","text":"RankOneMatrix{T, UT, VT}\n\nRepresents a rank-one matrix R = u * vt'. Composes like a charm.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"Modules = [FrankWolfe]\nPages = [\"types.jl\"]","category":"page"},{"location":"reference/3_backend/#FrankWolfe.SubspaceVector","page":"Utilities and data structures","title":"FrankWolfe.SubspaceVector","text":"SubspaceVector{HasMultiplicities, T}\n\nCompanion structure of SubspaceLMO containing three fields:\n\ndata is the full structure to be deflated,\nvec is a vector in the reduced subspace in which computations are performed,\nmul is only used to compute scalar products when HasMultiplicities = true,\n\nwhich should be avoided (when possible) for performance reasons.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#Utils","page":"Utilities and data structures","title":"Utils","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"Modules = [FrankWolfe]\nPages = [\"utils.jl\"]","category":"page"},{"location":"reference/3_backend/#FrankWolfe.ConstantBatchIterator","page":"Utilities and data structures","title":"FrankWolfe.ConstantBatchIterator","text":"ConstantBatchIterator(batch_size)\n\nBatch iterator always returning a constant batch size.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.ConstantMomentumIterator","page":"Utilities and data structures","title":"FrankWolfe.ConstantMomentumIterator","text":"ConstantMomentumIterator{T}\n\nIterator for momentum with a fixed damping value, always return the value and a dummy state.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.DeletedVertexStorage","page":"Utilities and data structures","title":"FrankWolfe.DeletedVertexStorage","text":"Vertex storage to store dropped vertices or find a suitable direction in lazy settings. The algorithm will look for at most return_kth suitable atoms before returning the best. See Extra-lazification with a vertex storage for usage.\n\nA vertex storage can be any type that implements two operations:\n\nBase.push!(storage, atom) to add an atom to the storage.\n\nNote that it is the storage type responsibility to ensure uniqueness of the atoms present.\n\nstorage_find_argmin_vertex(storage, direction, lazy_threshold) -> (found, vertex)\n\nreturning whether a vertex with sufficient progress was found and the vertex. It is up to the storage to remove vertices (or not) when they have been picked up.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.ExpMomentumIterator","page":"Utilities and data structures","title":"FrankWolfe.ExpMomentumIterator","text":"ExpMomentumIterator{T}\n\nIterator for the momentum used in the variant of Stochastic Frank-Wolfe. Momentum coefficients are the values of the iterator: ρ_t = 1 - num / (offset + t)^exp\n\nThe state corresponds to the iteration count.\n\nSource: Stochastic Conditional Gradient Methods: From Convex Minimization to Submodular Maximization Aryan Mokhtari, Hamed Hassani, Amin Karbasi, JMLR 2020.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.IncrementBatchIterator","page":"Utilities and data structures","title":"FrankWolfe.IncrementBatchIterator","text":"IncrementBatchIterator(starting_batch_size, max_batch_size, [increment = 1])\n\nBatch size starting at startingbatchsize and incrementing by increment at every iteration.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.NegatingArray","page":"Utilities and data structures","title":"FrankWolfe.NegatingArray","text":"Given an array array, NegatingArray represents -1 * array lazily.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe._unsafe_equal-Tuple{Array, Array}","page":"Utilities and data structures","title":"FrankWolfe._unsafe_equal","text":"_unsafe_equal(a, b)\n\nLike isequal on arrays but without the checks. Assumes a and b have the same axes.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.batchsize_iterate","page":"Utilities and data structures","title":"FrankWolfe.batchsize_iterate","text":"batchsize_iterate(iter::BatchSizeIterator) -> b\n\nMethod to implement for a batch size iterator of type BatchSizeIterator. Calling batchsize_iterate returns the next batch size and typically update the internal state of iter.\n\n\n\n\n\n","category":"function"},{"location":"reference/3_backend/#FrankWolfe.momentum_iterate","page":"Utilities and data structures","title":"FrankWolfe.momentum_iterate","text":"momentum_iterate(iter::MomentumIterator) -> ρ\n\nMethod to implement for a type MomentumIterator. Returns the next momentum value ρ and updates the iterator internal state.\n\n\n\n\n\n","category":"function"},{"location":"reference/3_backend/#FrankWolfe.muladd_memory_mode-Tuple{FrankWolfe.MemoryEmphasis, Any, Any, Any}","page":"Utilities and data structures","title":"FrankWolfe.muladd_memory_mode","text":"muladd_memory_mode(memory_mode::MemoryEmphasis, d, x, v)\n\nPerforms d = x - v in-place or not depending on MemoryEmphasis\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.muladd_memory_mode-Tuple{FrankWolfe.MemoryEmphasis, Any, Any, Real, Any}","page":"Utilities and data structures","title":"FrankWolfe.muladd_memory_mode","text":"(memory_mode::MemoryEmphasis, storage, x, gamma::Real, d)\n\nPerforms storage = x - gamma * d in-place or not depending on MemoryEmphasis\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.muladd_memory_mode-Tuple{FrankWolfe.MemoryEmphasis, Any, Real, Any}","page":"Utilities and data structures","title":"FrankWolfe.muladd_memory_mode","text":"(memory_mode::MemoryEmphasis, x, gamma::Real, d)\n\nPerforms x = x - gamma * d in-place or not depending on MemoryEmphasis\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.pre_computed_set_argminmax-Tuple{Any, Any}","page":"Utilities and data structures","title":"FrankWolfe.pre_computed_set_argminmax","text":"Computes the linear minimizer in the direction on the precomputedset. Precomputedset stores the vertices computed as extreme points v in each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.storage_find_argmin_vertex-Tuple{FrankWolfe.DeletedVertexStorage, Any, Any}","page":"Utilities and data structures","title":"FrankWolfe.storage_find_argmin_vertex","text":"Give the vertex v in the storage that minimizes s = direction ⋅ v and whether s achieves s ≤ lazy_threshold.\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#FrankWolfe.trajectory_callback-Tuple{Any}","page":"Utilities and data structures","title":"FrankWolfe.trajectory_callback","text":"trajectory_callback(storage)\n\nCallback pushing the state at each iteration to the passed storage. The state data is only the 5 first fields, usually: (t,primal,dual,dual_gap,time)\n\n\n\n\n\n","category":"method"},{"location":"reference/3_backend/#Oracle-counting-trackers","page":"Utilities and data structures","title":"Oracle counting trackers","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"The following structures are wrapping given oracles to behave similarly but additionally track the number of calls.","category":"page"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"FrankWolfe.TrackingObjective\nFrankWolfe.TrackingGradient\nFrankWolfe.TrackingLMO","category":"page"},{"location":"reference/3_backend/#FrankWolfe.TrackingObjective","page":"Utilities and data structures","title":"FrankWolfe.TrackingObjective","text":"A function acting like the normal objective f but tracking the number of calls.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.TrackingGradient","page":"Utilities and data structures","title":"FrankWolfe.TrackingGradient","text":"A function acting like the normal grad! but tracking the number of calls.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.TrackingLMO","page":"Utilities and data structures","title":"FrankWolfe.TrackingLMO","text":"TrackingLMO{LMO}(lmo)\n\nAn LMO wrapping another one and tracking the number of calls.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"Also see the example Tracking, counters and custom callbacks for Frank Wolfe.","category":"page"},{"location":"reference/3_backend/#Update-order-for-block-coordinate-methods","page":"Utilities and data structures","title":"Update order for block-coordinate methods","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"Block-coordinate methods can be run with different update orders. All update orders are subtypes of FrankWolfe.BlockCoordinateUpdateOrder. They have to implement the method FrankWolfe.select_update_indices which selects which blocks to update in what order.","category":"page"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"FrankWolfe.BlockCoordinateUpdateOrder\nFrankWolfe.select_update_indices\nFrankWolfe.FullUpdate\nFrankWolfe.CyclicUpdate\nFrankWolfe.StochasticUpdate\nFrankWolfe.LazyUpdate","category":"page"},{"location":"reference/3_backend/#FrankWolfe.BlockCoordinateUpdateOrder","page":"Utilities and data structures","title":"FrankWolfe.BlockCoordinateUpdateOrder","text":"Update order for a block-coordinate method. A BlockCoordinateUpdateOrder must implement\n\nselect_update_indices(::BlockCoordinateUpdateOrder, s::CallbackState, dual_gaps)\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.select_update_indices","page":"Utilities and data structures","title":"FrankWolfe.select_update_indices","text":"select_update_indices(::BlockCoordinateUpdateOrder, s::CallbackState, dual_gaps)\n\nReturns a list of lists of the block indices. Each sublist represents one round of updates in an iteration. The indices in a list show which blocks should be updated parallely in one round. For example, a full update is given by [1:l] and a blockwise update by [[i] for i=1:l], where l is the number of blocks.\n\n\n\n\n\n","category":"function"},{"location":"reference/3_backend/#FrankWolfe.FullUpdate","page":"Utilities and data structures","title":"FrankWolfe.FullUpdate","text":"The full update initiates a parallel update of all blocks in one single round.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.CyclicUpdate","page":"Utilities and data structures","title":"FrankWolfe.CyclicUpdate","text":"The cyclic update initiates a sequence of update rounds. In each round only one block is updated. The order of the blocks is determined by the given order of the LMOs.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.StochasticUpdate","page":"Utilities and data structures","title":"FrankWolfe.StochasticUpdate","text":"The stochastic update initiates a sequence of update rounds. In each round only one block is updated. The order of the blocks is a random.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.LazyUpdate","page":"Utilities and data structures","title":"FrankWolfe.LazyUpdate","text":"The Lazy update order is discussed in \"Flexible block-iterative analysis for the Frank-Wolfe algorithm,\" by Braun, Pokutta, & Woodstock (2024). 'lazyblock' is an index of a computationally expensive block to update; 'refreshrate' describes the frequency at which we perform a full activation; and 'blocksize' describes the number of \"faster\" blocks (i.e., those excluding 'lazyblock') activated (chosen uniformly at random) during each of the \"faster\" iterations; for more detail, see the article. If 'block_size' is unspecified, this defaults to\n\n\n\nNote: This methodology is currently only proven to work with 'FrankWolfe.Shortstep' linesearches and a (not-yet implemented) adaptive method; see the article for details.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#Update-step-for-block-coordinate-Frank-Wolfe","page":"Utilities and data structures","title":"Update step for block-coordinate Frank-Wolfe","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"Block-coordinate Frank-Wolfe (BCFW) can run different FW algorithms on different blocks. All update steps are subtypes of FrankWolfe.UpdateStep and implement FrankWolfe.update_iterate which defines one iteration of the corresponding method.","category":"page"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"FrankWolfe.UpdateStep\nFrankWolfe.update_iterate\nFrankWolfe.FrankWolfeStep\nFrankWolfe.BPCGStep","category":"page"},{"location":"reference/3_backend/#FrankWolfe.UpdateStep","page":"Utilities and data structures","title":"FrankWolfe.UpdateStep","text":"Update step for block-coordinate Frank-Wolfe. These are implementations of different FW-algorithms to be used in a blockwise manner. Each update step must implement\n\nupdate_iterate(\n step::UpdateStep,\n x,\n lmo,\n f,\n gradient,\n grad!,\n dual_gap,\n t,\n line_search,\n linesearch_workspace,\n memory_mode,\n epsilon,\n)\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.update_iterate","page":"Utilities and data structures","title":"FrankWolfe.update_iterate","text":"update_iterate(\n step::UpdateStep,\n x,\n lmo,\n f,\n gradient,\n grad!,\n dual_gap,\n t,\n line_search,\n linesearch_workspace,\n memory_mode,\n epsilon,\n)\n\nExecutes one iteration of the defined FrankWolfe.UpdateStep and updates the iterate x implicitly. The function returns a tuple (dual_gap, v, d, gamma, step_type):\n\ndual_gap is the updated FrankWolfe gap\nv is the used vertex\nd is the update direction\ngamma is the applied step-size\nstep_type is the applied step-type\n\n\n\n\n\n","category":"function"},{"location":"reference/3_backend/#FrankWolfe.FrankWolfeStep","page":"Utilities and data structures","title":"FrankWolfe.FrankWolfeStep","text":"Implementation of the vanilla Frank-Wolfe algorithm as an update step for block-coordinate Frank-Wolfe.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#FrankWolfe.BPCGStep","page":"Utilities and data structures","title":"FrankWolfe.BPCGStep","text":"Implementation of the blended pairwise conditional gradient (BPCG) method as an update step for block-coordinate Frank-Wolfe.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#Block-vector","page":"Utilities and data structures","title":"Block vector","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"FrankWolfe.BlockVector","category":"page"},{"location":"reference/3_backend/#FrankWolfe.BlockVector","page":"Utilities and data structures","title":"FrankWolfe.BlockVector","text":"BlockVector{T, MT <: AbstractArray{T}, ST <: Tuple} <: AbstractVector{T}\n\nRepresents a vector consisting of blocks. T is the element type of the vector, MT is the type of the underlying data array, and ST is the type of the tuple representing the sizes of each block. Each block can be accessed with the blocks field, and the sizes of the blocks are stored in the block_sizes field.\n\n\n\n\n\n","category":"type"},{"location":"reference/3_backend/#Index","page":"Utilities and data structures","title":"Index","text":"","category":"section"},{"location":"reference/3_backend/","page":"Utilities and data structures","title":"Utilities and data structures","text":"Pages = [\"3_backend.md\"]","category":"page"}] +} diff --git a/previews/PR539/siteinfo.js b/previews/PR539/siteinfo.js new file mode 100644 index 000000000..71e54af91 --- /dev/null +++ b/previews/PR539/siteinfo.js @@ -0,0 +1 @@ +var DOCUMENTER_CURRENT_VERSION = "previews/PR539";