diff --git a/previews/PR644/assets/android-chrome-192x192.png b/previews/PR644/assets/android-chrome-192x192.png new file mode 100644 index 0000000000..55076c2764 Binary files /dev/null and b/previews/PR644/assets/android-chrome-192x192.png differ diff --git a/previews/PR644/assets/android-chrome-512x512.png b/previews/PR644/assets/android-chrome-512x512.png new file mode 100644 index 0000000000..cc78ca4e3e Binary files /dev/null and b/previews/PR644/assets/android-chrome-512x512.png differ diff --git a/previews/PR644/assets/apple-touch-icon.png b/previews/PR644/assets/apple-touch-icon.png new file mode 100644 index 0000000000..a088562691 Binary files /dev/null and b/previews/PR644/assets/apple-touch-icon.png differ diff --git a/previews/PR644/assets/documenter.js b/previews/PR644/assets/documenter.js new file mode 100644 index 0000000000..6adfbbbf4b --- /dev/null +++ b/previews/PR644/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/PR644/assets/favicon-16x16.png b/previews/PR644/assets/favicon-16x16.png new file mode 100644 index 0000000000..dc9e119f1b Binary files /dev/null and b/previews/PR644/assets/favicon-16x16.png differ diff --git a/previews/PR644/assets/favicon-32x32.png b/previews/PR644/assets/favicon-32x32.png new file mode 100644 index 0000000000..5cd7966aab Binary files /dev/null and b/previews/PR644/assets/favicon-32x32.png differ diff --git a/previews/PR644/assets/favicon.ico b/previews/PR644/assets/favicon.ico new file mode 100644 index 0000000000..19440dacc5 Binary files /dev/null and b/previews/PR644/assets/favicon.ico differ diff --git a/previews/PR644/assets/images/SPDSignal.png b/previews/PR644/assets/images/SPDSignal.png new file mode 100644 index 0000000000..b3304c989f Binary files /dev/null and b/previews/PR644/assets/images/SPDSignal.png differ diff --git a/previews/PR644/assets/images/projection_illustration.png b/previews/PR644/assets/images/projection_illustration.png new file mode 100644 index 0000000000..9ddd73601a Binary files /dev/null and b/previews/PR644/assets/images/projection_illustration.png differ diff --git a/previews/PR644/assets/images/projection_illustration_600.png b/previews/PR644/assets/images/projection_illustration_600.png new file mode 100644 index 0000000000..80d4612cf4 Binary files /dev/null and b/previews/PR644/assets/images/projection_illustration_600.png differ diff --git a/previews/PR644/assets/images/retraction_illustration.png b/previews/PR644/assets/images/retraction_illustration.png new file mode 100644 index 0000000000..a3d42d874d Binary files /dev/null and b/previews/PR644/assets/images/retraction_illustration.png differ diff --git a/previews/PR644/assets/images/retraction_illustration_600.png b/previews/PR644/assets/images/retraction_illustration_600.png new file mode 100644 index 0000000000..e379593a46 Binary files /dev/null and b/previews/PR644/assets/images/retraction_illustration_600.png differ diff --git a/previews/PR644/assets/logo-dark.png b/previews/PR644/assets/logo-dark.png new file mode 100644 index 0000000000..c24e69d753 Binary files /dev/null and b/previews/PR644/assets/logo-dark.png differ diff --git a/previews/PR644/assets/logo-dark_bg.png b/previews/PR644/assets/logo-dark_bg.png new file mode 100644 index 0000000000..d8d52c593b Binary files /dev/null and b/previews/PR644/assets/logo-dark_bg.png differ diff --git a/previews/PR644/assets/logo-text-readme-dark.png b/previews/PR644/assets/logo-text-readme-dark.png new file mode 100644 index 0000000000..e9d27c76c7 Binary files /dev/null and b/previews/PR644/assets/logo-text-readme-dark.png differ diff --git a/previews/PR644/assets/logo-text-readme.png b/previews/PR644/assets/logo-text-readme.png new file mode 100644 index 0000000000..4a83e9e8d8 Binary files /dev/null and b/previews/PR644/assets/logo-text-readme.png differ diff --git a/previews/PR644/assets/logo.png b/previews/PR644/assets/logo.png new file mode 100644 index 0000000000..fd89e1b523 Binary files /dev/null and b/previews/PR644/assets/logo.png differ diff --git a/previews/PR644/assets/logo_bg.png b/previews/PR644/assets/logo_bg.png new file mode 100644 index 0000000000..b47c580777 Binary files /dev/null and b/previews/PR644/assets/logo_bg.png differ diff --git a/previews/PR644/assets/mstile-150x150.png b/previews/PR644/assets/mstile-150x150.png new file mode 100644 index 0000000000..26b5dc9e91 Binary files /dev/null and b/previews/PR644/assets/mstile-150x150.png differ diff --git a/previews/PR644/assets/search.js b/previews/PR644/assets/search.js new file mode 100644 index 0000000000..c133f74101 --- /dev/null +++ b/previews/PR644/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/PR644/assets/site.webmanifest b/previews/PR644/assets/site.webmanifest new file mode 100644 index 0000000000..b20abb7cbb --- /dev/null +++ b/previews/PR644/assets/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/previews/PR644/assets/themes/documenter-dark.css b/previews/PR644/assets/themes/documenter-dark.css new file mode 100644 index 0000000000..c94a294dcf --- /dev/null +++ b/previews/PR644/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/PR644/assets/themes/documenter-light.css b/previews/PR644/assets/themes/documenter-light.css new file mode 100644 index 0000000000..9b9a14b043 --- /dev/null +++ b/previews/PR644/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/PR644/assets/themeswap.js b/previews/PR644/assets/themeswap.js new file mode 100644 index 0000000000..c58e993e3e --- /dev/null +++ b/previews/PR644/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/PR644/assets/warner.js b/previews/PR644/assets/warner.js new file mode 100644 index 0000000000..5531c8851b --- /dev/null +++ b/previews/PR644/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/PR644/features/atlases.html b/previews/PR644/features/atlases.html new file mode 100644 index 0000000000..8a35a5c868 --- /dev/null +++ b/previews/PR644/features/atlases.html @@ -0,0 +1,47 @@ + +Atlases and charts · Manifolds.jl

    Atlases and charts

    Atlases on an $n$-dimensional manifold $\mathcal M$ are collections of charts $\mathcal A = \{(U_i, φ_i) \colon i \in I\}$, where $I$ is a (finite or infinte) index family, such that $U_i \subseteq \mathcal M$ is an open set and each chart $φ_i: U_i \to \mathbb{R}^n$ is a homeomorphism. This means, that $φ_i$ is bijective – sometimes also called one-to-one and onto - and continuous, and its inverse $φ_i^{-1}$ is continuous as well. The inverse $φ_i^{-1}$ is called (local) parametrization. The resulting parameters $a=φ(p)$ of $p$ (with respect to the chart $φ$) are in the literature also called “(local) coordinates”. To distinguish the parameter $a$ from get_coordinates in a basis, we use the terminology parameter in this package.

    For an atlas $\mathcal A$ we further require that

    \[\displaystyle\bigcup_{i\in I} U_i = \mathcal M.\]

    We say that $φ_i$ is a chart about $p$, if $p\in U_i$. An atlas provides a connection between a manifold and the Euclidean space $\mathbb{R}^n$, since locally, a chart about $p$ can be used to identify its neighborhood (as long as you stay in $U_i$) with a subset of a Euclidean space. Most manifolds we consider are smooth, i.e. any change of charts $φ_i \circ φ_j^{-1}: \mathbb{R}^n\to\mathbb{R}^n$, where $i,j\in I$, is a smooth function. These changes of charts are also called transition maps.

    Most operations on manifolds in Manifolds.jl avoid operating in a chart through appropriate embeddings and formulas derived for particular manifolds, though atlases provide the most general way of working with manifolds. Compared to these approaches, using an atlas is often more technical and time-consuming. They are extensively used in metric-related functions on MetricManifolds.

    Atlases are represented by objects of subtypes of AbstractAtlas. There are no type restrictions for indices of charts in atlases.

    Operations using atlases and charts are available through the following functions:

    • get_chart_index can be used to select an appropriate chart for the neighborhood of a given point $p$. This function should work deterministically, i.e. for a fixed $p$ always return the same chart.
    • get_parameters converts a point to its parameters with respect to the chart in a chart.
    • get_point converts parameters (local coordinates) in a chart to the point that corresponds to them.
    • induced_basis returns a basis of a given vector space at a point induced by a chart $φ$.
    • transition_map converts coordinates of a point between two charts, e.g. computes $φ_i\circ φ_j^{-1}: \mathbb{R}^n\to\mathbb{R}^n$, $i,j\in I$.

    While an atlas could store charts as explicit functions, it is favourable, that the [get_parameters] actually implements a chart $φ$, get_point its inverse, the prametrization $φ^{-1}$.

    Manifolds.AbstractAtlasType
    AbstractAtlas{𝔽}

    An abstract class for atlases whith charts that have values in the vector space 𝔽ⁿ for some value of n. 𝔽 is a number system determined by an AbstractNumbers object.

    source
    Manifolds.InducedBasisType
    InducedBasis(vs::VectorSpaceType, A::AbstractAtlas, i)

    The basis induced by chart with index i from an AbstractAtlas A of vector space of type vs.

    For the vs a TangentSpace this works as follows:

    Let $n$ denote the dimension of the manifold $\mathcal M$.

    Let the parameter $a=φ_i(p) ∈ \mathbb R^n$ and $j∈\{1,…,n\}$. We can look at the $j$th parameter curve $b_j(t) = a + te_j$, where $e_j$ denotes the $j$th unit vector. Using the parametrisation we obtain a curve $c_j(t) = φ_i^{-1}(b_j(t))$ which fulfills $c(0) = p$.

    Now taking the derivative(s) with respect to $t$ (and evaluate at $t=0$), we obtain a tangent vector for each $j$ corresponding to an equivalence class of curves (having the same derivative) as

    \[X_j = [c_j] = \frac{\mathrm{d}}{\mathrm{d}t} c_i(t) \Bigl|_{t=0}\]

    and the set $\{X_1,\ldots,X_n\}$ is the chart-induced basis of $T_p\mathcal M$.

    See also

    VectorSpaceType, AbstractBasis

    source
    Manifolds.RetractionAtlasType
    RetractionAtlas{
    +    𝔽,
    +    TRetr<:AbstractRetractionMethod,
    +    TInvRetr<:AbstractInverseRetractionMethod,
    +    TBasis<:AbstractBasis,
    +} <: AbstractAtlas{𝔽}

    An atlas indexed by points on a manifold, $\mathcal M = I$ and parameters (local coordinates) are given in $T_p\mathcal M$. This means that a chart $φ_p = \mathrm{cord}\circ\mathrm{retr}_p^{-1}$ is only locally defined (around $p$), where $\mathrm{cord}$ is the decomposition of the tangent vector into coordinates with respect to the given basis of the tangent space, cf. get_coordinates. The parametrization is given by $φ_p^{-1}=\mathrm{retr}_p\circ\mathrm{vec}$, where $\mathrm{vec}$ turns the basis coordinates into a tangent vector, cf. get_vector.

    In short: The coordinates with respect to a basis are used together with a retraction as a parametrization.

    See also

    AbstractAtlas, AbstractInverseRetractionMethod, AbstractRetractionMethod, AbstractBasis

    source
    LinearAlgebra.normMethod
    norm(M::AbstractManifold, A::AbstractAtlas, i, a, Xc)

    Calculate norm on manifold M at point with parameters a in chart i of an AbstractAtlas A of vector with coefficients Xc in induced basis.

    source
    Manifolds.affine_connection!Method
    affine_connection!(M::AbstractManifold, Zc, A::AbstractAtlas, i, a, Xc, Yc)

    Calculate affine connection on manifold M at point with parameters a in chart i of an an AbstractAtlas A of vectors with coefficients Zc and Yc in induced basis and save the result in Zc.

    source
    Manifolds.affine_connectionMethod
    affine_connection(M::AbstractManifold, A::AbstractAtlas, i, a, Xc, Yc)

    Calculate affine connection on manifold M at point with parameters a in chart i of AbstractAtlas A of vectors with coefficients Xc and Yc in induced basis.

    source
    Manifolds.check_chart_switchMethod
    check_chart_switch(M::AbstractManifold, A::AbstractAtlas, i, a)

    Determine whether chart should be switched when an operation in chart i from an AbstractAtlas A reaches parameters a in that chart.

    By default false is returned.

    source
    Manifolds.get_chart_indexMethod
    get_chart_index(M::AbstractManifold, A::AbstractAtlas, i, a)

    Select a chart from an AbstractAtlas A for manifold M that is suitable for representing the neighborhood of point with parametrization a in chart i. This selection should be deterministic, although different charts may be selected for arbitrarily close but distinct points.

    See also

    get_default_atlas

    source
    Manifolds.get_chart_indexMethod
    get_chart_index(M::AbstractManifold, A::AbstractAtlas, p)

    Select a chart from an AbstractAtlas A for manifold M that is suitable for representing the neighborhood of point p. This selection should be deterministic, although different charts may be selected for arbitrarily close but distinct points.

    See also

    get_default_atlas

    source
    Manifolds.get_parametersMethod
    get_parameters(M::AbstractManifold, A::AbstractAtlas, i, p)

    Calculate parameters (local coordinates) of point p on manifold M in chart from an AbstractAtlas A at index i. This function is hence an implementation of the chart $φ_i(p), i\in I$. The parameters are in the number system determined by A. If the point $p\notin U_i$ is not in the domain of the chart, this method should throw an error.

    See also

    get_point, get_chart_index

    source
    Manifolds.get_pointMethod
    get_point(M::AbstractManifold, A::AbstractAtlas, i, a)

    Calculate point at parameters (local coordinates) a on manifold M in chart from an AbstractAtlas A at index i. This function is hence an implementation of the inverse $φ_i^{-1}(a), i\in I$ of a chart, also called a parametrization.

    See also

    get_parameters, get_chart_index

    source
    Manifolds.local_metricMethod
    local_metric(M::AbstractManifold, p, B::InducedBasis)

    Compute the local metric tensor for vectors expressed in terms of coordinates in basis B on manifold M. The point p is not checked.

    source
    Manifolds.transition_mapMethod
    transition_map(M::AbstractManifold, A_from::AbstractAtlas, i_from, A_to::AbstractAtlas, i_to, a)
    +transition_map(M::AbstractManifold, A::AbstractAtlas, i_from, i_to, a)

    Given coordinates a in chart (A_from, i_from) of a point on manifold M, returns coordinates of that point in chart (A_to, i_to). If A_from and A_to are equal, A_to can be omitted.

    Mathematically this function is the transition map or change of charts, but it might even be between two atlases $A_{\text{from}} = \{(U_i,φ_i)\}_{i\in I}$ and $A_{\text{to}} = \{(V_j,\psi_j)\}_{j\in J}$, and hence $I, J$ are their index sets. We have $i_{\text{from}}\in I$, $i_{\text{to}}\in J$.

    This method then computes

    \[\bigl(\psi_{i_{\text{to}}}\circ φ_{i_{\text{from}}}^{-1}\bigr)(a)\]

    Note that, similarly to get_parameters, this method should fail the same way if $V_{i_{\text{to}}}\cap U_{i_{\text{from}}}=\emptyset$.

    See also

    AbstractAtlas, get_parameters, get_point

    source
    Manifolds.transition_map_diffMethod
    transition_map_diff(M::AbstractManifold, A::AbstractAtlas, i_from, a, c, i_to)

    Compute differential of transition map from chart i_from to chart i_to from an AbstractAtlas A on manifold M at point with parameters a on tangent vector with coordinates c in the induced basis.

    source
    ManifoldsBase.innerMethod
    inner(M::AbstractManifold, A::AbstractAtlas, i, a, Xc, Yc)

    Calculate inner product on manifold M at point with parameters a in chart i of an atlas A of vectors with coefficients Xc and Yc in induced basis.

    source

    Cotangent space and musical isomorphisms

    Related to atlases, there is also support for the cotangent space and coefficients of cotangent vectors in bases of the cotangent space.

    Functions sharp and flat implement musical isomorphisms for arbitrary vector bundles.

    Manifolds.flatMethod
    flat(M::AbstractManifold, p, X)

    Compute the flat isomorphism (one of the musical isomorphisms) of tangent vector X from the vector space of type M at point p from the underlying AbstractManifold.

    The function can be used for example to transform vectors from the tangent bundle to vectors from the cotangent bundle $♭ : T\mathcal M → T^{*}\mathcal M$

    source
    Manifolds.sharpMethod
    sharp(M::AbstractManifold, p, ξ)

    Compute the sharp isomorphism (one of the musical isomorphisms) of vector ξ from the vector space M at point p from the underlying AbstractManifold.

    The function can be used for example to transform vectors from the cotangent bundle to vectors from the tangent bundle $♯ : T^{*}\mathcal M → T\mathcal M$

    source

    Computations in charts

    Manifolds.IntegratorTerminatorNearChartBoundaryType
    IntegratorTerminatorNearChartBoundary{TKwargs}

    An object for determining the point at which integration of a differential equation in a chart on a manifold should be terminated for the purpose of switching a chart.

    The value stored in check_chart_switch_kwargs will be passed as keyword arguments to check_chart_switch. By default an empty tuple is stored.

    source
    Manifolds.solve_chart_exp_odeFunction
    solve_chart_exp_ode(
    +    M::AbstractManifold,
    +    a,
    +    Xc,
    +    A::AbstractAtlas,
    +    i0;
    +    solver=AutoVern9(Rodas5()),
    +    final_time=1.0,
    +    check_chart_switch_kwargs=NamedTuple(),
    +    kwargs...,
    +)

    Solve geodesic ODE on a manifold M from point of coordinates a in chart i0 from an AbstractAtlas A in direction of coordinates Xc in the induced basis.

    source
    Manifolds.solve_chart_log_bvpFunction
    solve_chart_log_bvp(
    +    M::AbstractManifold,
    +    a1,
    +    a2,
    +    A::AbstractAtlas,
    +    i;
    +    solver=GeneralMIRK4(),
    +    dt=0.05,
    +    kwargs...,
    +)

    Solve the BVP corresponding to geodesic calculation on AbstractManifold M, between points with parameters a1 and a2 in a chart i of an AbstractAtlas A using solver solver. Geodesic γ is sampled at time interval dt, with γ(0) = a1 and γ(1) = a2.

    source
    Manifolds.solve_chart_parallel_transport_odeFunction
    solve_chart_parallel_transport_ode(
    +    M::AbstractManifold,
    +    a,
    +    Xc,
    +    A::AbstractAtlas,
    +    i0,
    +    Yc;
    +    solver=AutoVern9(Rodas5()),
    +    check_chart_switch_kwargs=NamedTuple(),
    +    final_time=1.0,
    +    kwargs...,
    +)

    Parallel transport vector with coordinates Yc along geodesic on a manifold M from point of coordinates a in a chart i0 from an AbstractAtlas A in direction of coordinates Xc in the induced basis.

    source
    diff --git a/previews/PR644/features/differentiation.html b/previews/PR644/features/differentiation.html new file mode 100644 index 0000000000..1b4c254f33 --- /dev/null +++ b/previews/PR644/features/differentiation.html @@ -0,0 +1,2 @@ + +Differentiation · Manifolds.jl
    diff --git a/previews/PR644/features/distributions.html b/previews/PR644/features/distributions.html new file mode 100644 index 0000000000..e774dec6f2 --- /dev/null +++ b/previews/PR644/features/distributions.html @@ -0,0 +1,2 @@ + +Distributions · Manifolds.jl

    Distributions

    The following functions and types provide support for manifold-valued and tangent space-valued distributions:

    Manifolds.FVectorDistributionType
    FVectorDistribution{TSpace<:VectorBundleFibers, T}

    An abstract distribution for vector bundle fiber-valued distributions (values from a fiber of a vector bundle at point x from the given manifold). For example used for tangent vector-valued distributions.

    source
    Manifolds.FVectorSupportType
    FVectorSupport(space::AbstractManifold, VectorBundleFibers)

    Value support for vector bundle fiber-valued distributions (values from a fiber of a vector bundle at a point from the given manifold). For example used for tangent vector-valued distributions.

    source
    Manifolds.FVectorvariateType
    FVectorvariate

    Structure that subtypes VariateForm, indicating that a single sample is a vector from a fiber of a vector bundle.

    source
    Manifolds.MPointvariateType
    MPointvariate

    Structure that subtypes VariateForm, indicating that a single sample is a point on a manifold.

    source
    Manifolds.ProjectedFVectorDistributionType
    ProjectedFVectorDistribution(type::VectorBundleFibers, p, d, project!)

    Generates a random vector from ambient space of manifold type.manifold at point p and projects it to vector space of type type using function project!, see project for documentation. Generated arrays are of type TResult.

    source
    Manifolds.ProjectedPointDistributionType
    ProjectedPointDistribution(M::AbstractManifold, d, proj!, p)

    Generates a random point in ambient space of M and projects it to M using function proj!. Generated arrays are of type TResult, which can be specified by providing the p argument.

    source
    Manifolds.projected_distributionFunction
    projected_distribution(M::AbstractManifold, d, [p=rand(d)])

    Wrap the standard distribution d into a manifold-valued distribution. Generated points will be of similar type to p. By default, the type is not changed.

    source
    diff --git a/previews/PR644/features/statistics.html b/previews/PR644/features/statistics.html new file mode 100644 index 0000000000..071e549483 --- /dev/null +++ b/previews/PR644/features/statistics.html @@ -0,0 +1,132 @@ + +Statistics · Manifolds.jl

    Statistics

    Manifolds.GeodesicInterpolationType
    GeodesicInterpolation <: AbstractEstimationMethod

    Repeated weighted geodesic interpolation method for estimating the Riemannian center of mass.

    The algorithm proceeds with the following simple online update:

    \[\begin{aligned} +μ_1 &= x_1\\ +t_k &= \frac{w_k}{\sum_{i=1}^k w_i}\\ +μ_{k} &= γ_{μ_{k-1}}(x_k; t_k), +\end{aligned}\]

    where $x_k$ are points, $w_k$ are weights, $μ_k$ is the $k$th estimate of the mean, and $γ_x(y; t)$ is the point at time $t$ along the shortest_geodesic between points $x,y ∈ \mathcal M$. The algorithm terminates when all $x_k$ have been considered. In the Euclidean case, this exactly computes the weighted mean.

    The algorithm has been shown to converge asymptotically with the sample size for the following manifolds equipped with their default metrics when all sampled points are in an open geodesic ball about the mean with corresponding radius (see GeodesicInterpolationWithinRadius):

    For online variance computation, the algorithm additionally uses an analogous recursion to the weighted Welford algorithm [West1979].

    source
    Manifolds.default_estimation_methodMethod
    default_estimation_method(M::AbstractManifold, f)

    Specify a default AbstractEstimationMethod for an AbstractManifold for a function f, e.g. the median or the mean.

    Note that his function is decorated, so it can inherit from the embedding, for example for the IsEmbeddedSubmanifold trait.

    source
    Statistics.covMethod
    Statistics.cov(
    +    M::AbstractManifold,
    +    x::AbstractVector;
    +    basis::AbstractBasis=DefaultOrthonormalBasis(),
    +    tangent_space_covariance_estimator::CovarianceEstimator=SimpleCovariance(;
    +        corrected=true,
    +    ),
    +    mean_estimation_method::AbstractEstimationMethod=GradientDescentEstimation(),
    +    inverse_retraction_method::AbstractInverseRetractionMethod=default_inverse_retraction_method(
    +        M, eltype(x),
    +    ),
    +)

    Estimate the covariance matrix of a set of points x on manifold M. Since the covariance matrix on a manifold is a rank 2 tensor, the function returns its coefficients in basis induced by the given tangent space basis. See Section 5 of [Pennec2006] for details.

    The mean is calculated using the specified mean_estimation_method using [mean](@ref Statistics.mean(::AbstractManifold, ::AbstractVector, ::AbstractEstimationMethod), and tangent vectors at this mean are calculated using the provided inverse_retraction_method. Finally, the covariance matrix in the tangent plane is estimated using the Euclidean space estimator tangent_space_covariance_estimator. The type CovarianceEstimator is defined in StatsBase.jl and examples of covariance estimation methods can be found in CovarianceEstimation.jl.

    source
    Statistics.mean!Method
    mean!(M::AbstractManifold, y, x::AbstractVector[, w::AbstractWeights]; kwargs...)
    +mean!(
    +    M::AbstractManifold,
    +    y,
    +    x::AbstractVector,
    +    [w::AbstractWeights,]
    +    method::AbstractEstimationMethod;
    +    kwargs...,
    +)

    Compute the mean in-place in y.

    source
    Statistics.meanMethod
    mean(
    +    M::AbstractManifold,
    +    x::AbstractVector,
    +    [w::AbstractWeights,]
    +    method::ExtrinsicEstimation;
    +    kwargs...,
    +)

    Estimate the Riemannian center of mass of x using ExtrinsicEstimation, i.e. by computing the mean in the embedding and projecting the result back. You can specify an extrinsic_method to specify which mean estimation method to use in the embedding, which defaults to GeodesicInterpolation.

    See mean for a description of the remaining kwargs.

    source
    Statistics.meanMethod
    mean(
    +    M::AbstractManifold,
    +    x::AbstractVector,
    +    [w::AbstractWeights,]
    +    method::GeodesicInterpolation;
    +    shuffle_rng=nothing,
    +    retraction::AbstractRetractionMethod = default_retraction_method(M, eltype(x)),
    +    inverse_retraction::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, eltype(x)),
    +    kwargs...,
    +)

    Estimate the Riemannian center of mass of x in an online fashion using repeated weighted geodesic interpolation. See GeodesicInterpolation for details.

    If shuffle_rng is provided, it is used to shuffle the order in which the points are considered for computing the mean.

    Optionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction.

    source
    Statistics.meanMethod
    mean(M::AbstractManifold, x::AbstractVector[, w::AbstractWeights]; kwargs...)

    Compute the (optionally weighted) Riemannian center of mass also known as Karcher mean of the vector x of points on the AbstractManifold M, defined as the point that satisfies the minimizer

    \[\argmin_{y ∈ \mathcal M} \frac{1}{2 \sum_{i=1}^n w_i} \sum_{i=1}^n w_i\mathrm{d}_{\mathcal M}^2(y,x_i),\]

    where $\mathrm{d}_{\mathcal M}$ denotes the Riemannian distance.

    In the general case, the GradientDescentEstimation is used to compute the mean. mean( M::AbstractManifold, x::AbstractVector, [w::AbstractWeights,] method::AbstractEstimationMethod=defaultestimationmethod(M); kwargs..., )

    Compute the mean using the specified method.

    mean(
    +    M::AbstractManifold,
    +    x::AbstractVector,
    +    [w::AbstractWeights,]
    +    method::GradientDescentEstimation;
    +    p0=x[1],
    +    stop_iter=100,
    +    retraction::AbstractRetractionMethod = default_retraction_method(M),
    +    inverse_retraction::AbstractInverseRetractionMethod = default_retraction_method(M, eltype(x)),
    +    kwargs...,
    +)

    Compute the mean using the gradient descent scheme GradientDescentEstimation.

    Optionally, provide p0, the starting point (by default set to the first data point). stop_iter denotes the maximal number of iterations to perform and the kwargs... are passed to isapprox to stop, when the minimal change between two iterates is small. For more stopping criteria check the Manopt.jl package and use a solver therefrom.

    Optionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction.

    The Theory stems from[Karcher1977] and is also described in[PennecArsigny2013] as the exponential barycenter. The algorithm is further described in[Afsari2013].

    source
    Statistics.median!Method
    median!(M::AbstractManifold, y, x::AbstractVector[, w::AbstractWeights]; kwargs...)
    +median!(
    +    M::AbstractManifold,
    +    y,
    +    x::AbstractVector,
    +    [w::AbstractWeights,]
    +    method::AbstractEstimationMethod;
    +    kwargs...,
    +)

    computes the median in-place in y.

    source
    Statistics.medianMethod
    median(
    +    M::AbstractManifold,
    +    x::AbstractVector,
    +    [w::AbstractWeights,]
    +    method::CyclicProximalPointEstimation;
    +    p0=x[1],
    +    stop_iter=1000000,
    +    retraction::AbstractRetractionMethod = default_retraction_method(M, eltype(x),),
    +    inverse_retraction::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, eltype(x),),
    +    kwargs...,
    +)

    Compute the median using CyclicProximalPointEstimation.

    Optionally, provide p0, the starting point (by default set to the first data point). stop_iter denotes the maximal number of iterations to perform and the kwargs... are passed to isapprox to stop, when the minimal change between two iterates is small. For more stopping criteria check the Manopt.jl package and use a solver therefrom.

    Optionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction.

    The algorithm is further described in [Bačák2014].

    source
    Statistics.medianMethod
    median(
    +    M::AbstractManifold,
    +    x::AbstractVector,
    +    [w::AbstractWeights,]
    +    method::ExtrinsicEstimation;
    +    extrinsic_method = CyclicProximalPointEstimation(),
    +    kwargs...,
    +)

    Estimate the median of x using ExtrinsicEstimation, i.e. by computing the median in the embedding and projecting the result back. You can specify an extrinsic_method to specify which median estimation method to use in the embedding, which defaults to CyclicProximalPointEstimation.

    See median for a description of kwargs.

    source
    Statistics.medianMethod
    median(
    +    M::AbstractManifold,
    +    x::AbstractVector,
    +    [w::AbstractWeights,]
    +    method::WeiszfeldEstimation;
    +    α = 1.0,
    +    p0=x[1],
    +    stop_iter=2000,
    +    retraction::AbstractRetractionMethod = default_retraction_method(M, eltype(x)),
    +    inverse_retraction::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, eltype(x)),
    +    kwargs...,
    +)

    Compute the median using WeiszfeldEstimation.

    Optionally, provide p0, the starting point (by default set to the first data point). stop_iter denotes the maximal number of iterations to perform and the kwargs... are passed to isapprox to stop, when the minimal change between two iterates is small. For more stopping criteria check the Manopt.jl package and use a solver therefrom.

    The parameter $α\in (0,2]$ is a step size.

    The algorithm is further described in [FletcherVenkatasubramanianJoshi2008], especially the update rule in Eq. (6), i.e. Let $q_{k}$ denote the current iterate, $n$ the number of points $x_1,\ldots,x_n$, and

    \[I_k = \bigl\{ i \in \{1,\ldots,n\} \big| x_i \neq q_k \bigr\}\]

    all indices of points that are not equal to the current iterate. Then the update reads $q_{k+1} = \exp_{q_k}(αX)$, where

    \[X = \frac{1}{s}\sum_{i\in I_k} \frac{w_i}{d_{\mathcal M}(q_k,x_i)}\log_{q_k}x_i +\quad +\text{ with } +\quad +s = \sum_{i\in I_k} \frac{w_i}{d_{\mathcal M}(q_k,x_i)},\]

    and where $\mathrm{d}_{\mathcal M}$ denotes the Riemannian distance.

    Optionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction, which by default use the exponential and logarithmic map, respectively.

    source
    Statistics.medianMethod
    median(M::AbstractManifold, x::AbstractVector[, w::AbstractWeights]; kwargs...)
    +median(
    +    M::AbstractManifold,
    +    x::AbstractVector,
    +    [w::AbstractWeights,]
    +    method::AbstractEstimationMethod;
    +    kwargs...,
    +)

    Compute the (optionally weighted) Riemannian median of the vector x of points on the AbstractManifold M, defined as the point that satisfies the minimizer

    \[\argmin_{y ∈ \mathcal M} \frac{1}{\sum_{i=1}^n w_i} \sum_{i=1}^n w_i\mathrm{d}_{\mathcal M}(y,x_i),\]

    where $\mathrm{d}_{\mathcal M}$ denotes the Riemannian distance. This function is nonsmooth (i.e nondifferentiable).

    In the general case, the CyclicProximalPointEstimation is used to compute the median. However, this default may be overloaded for specific manifolds.

    Compute the median using the specified method.

    source
    Statistics.stdMethod
    std(M, x, m=mean(M, x); corrected=true, kwargs...)
    +std(M, x, w::AbstractWeights, m=mean(M, x, w); corrected=false, kwargs...)

    compute the optionally weighted standard deviation of a Vector x of n data points on the AbstractManifold M, i.e.

    \[\sqrt{\frac{1}{c} \sum_{i=1}^n w_i d_{\mathcal M}^2 (x_i,m)},\]

    where c is a correction term, see Statistics.std. The mean of x can be specified as m, and the corrected variance can be activated by setting corrected=true.

    source
    Statistics.varMethod
    var(M, x, m=mean(M, x); corrected=true)
    +var(M, x, w::AbstractWeights, m=mean(M, x, w); corrected=false)

    compute the (optionally weighted) variance of a Vector x of n data points on the AbstractManifold M, i.e.

    \[\frac{1}{c} \sum_{i=1}^n w_i d_{\mathcal M}^2 (x_i,m),\]

    where c is a correction term, see Statistics.var. The mean of x can be specified as m, and the corrected variance can be activated by setting corrected=true. All further kwargs... are passed to the computation of the mean (if that is not provided).

    source
    StatsBase.kurtosisMethod
    kurtosis(M::AbstractManifold, x::AbstractVector, k::Int[, w::AbstractWeights], m=mean(M, x[, w]))

    Compute the excess kurtosis of points in x on manifold M. Optionally provide weights w and/or a precomputed mean m.

    source
    StatsBase.mean_and_stdMethod
    mean_and_std(M::AbstractManifold, x::AbstractVector[, w::AbstractWeights]; kwargs...) -> (mean, std)

    Compute the mean and the standard deviation std simultaneously.

    mean_and_std(
    +    M::AbstractManifold,
    +    x::AbstractVector
    +    [w::AbstractWeights,]
    +    method::AbstractEstimationMethod;
    +    kwargs...,
    +) -> (mean, var)

    Use the method for simultaneously computing the mean and standard deviation. To use a mean-specific method, call mean and then std.

    source
    StatsBase.mean_and_varMethod
    mean_and_var(
    +    M::AbstractManifold,
    +    x::AbstractVector
    +    [w::AbstractWeights,]
    +    method::GeodesicInterpolationWithinRadius;
    +    kwargs...,
    +) -> (mean, var)

    Use repeated weighted geodesic interpolation to estimate the mean. Simultaneously, use a Welford-like recursion to estimate the variance.

    See GeodesicInterpolationWithinRadius and mean_and_var for more information.

    source
    StatsBase.mean_and_varMethod
    mean_and_var(
    +    M::AbstractManifold,
    +    x::AbstractVector
    +    [w::AbstractWeights,]
    +    method::GeodesicInterpolation;
    +    shuffle_rng::Union{AbstractRNG,Nothing} = nothing,
    +    retraction::AbstractRetractionMethod = default_retraction_method(M, eltype(x)),
    +    inverse_retraction::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, eltype(x)),
    +    kwargs...,
    +) -> (mean, var)

    Use the repeated weighted geodesic interpolation to estimate the mean. Simultaneously, use a Welford-like recursion to estimate the variance.

    If shuffle_rng is provided, it is used to shuffle the order in which the points are considered. Optionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction.

    See GeodesicInterpolation for details on the geodesic interpolation method.

    Note

    The Welford algorithm for the variance is experimental and is not guaranteed to give accurate results except on Euclidean.

    source
    StatsBase.mean_and_varMethod
    mean_and_var(M::AbstractManifold, x::AbstractVector[, w::AbstractWeights]; kwargs...) -> (mean, var)

    Compute the mean and the variance simultaneously. See those functions for a description of the arguments.

    mean_and_var(
    +    M::AbstractManifold,
    +    x::AbstractVector
    +    [w::AbstractWeights,]
    +    method::AbstractEstimationMethod;
    +    kwargs...,
    +) -> (mean, var)

    Use the method for simultaneously computing the mean and variance. To use a mean-specific method, call mean and then var.

    source
    StatsBase.momentFunction
    moment(M::AbstractManifold, x::AbstractVector, k::Int[, w::AbstractWeights], m=mean(M, x[, w]))

    Compute the kth central moment of points in x on manifold M. Optionally provide weights w and/or a precomputed mean.

    source
    StatsBase.skewnessMethod
    skewness(M::AbstractManifold, x::AbstractVector, k::Int[, w::AbstractWeights], m=mean(M, x[, w]))

    Compute the standardized skewness of points in x on manifold M. Optionally provide weights w and/or a precomputed mean m.

    source

    Literature

    • Ho2013

      Ho J.; Cheng G.; Salehian H.; Vemuri B. C.; Recursive Karcher expectation estimators and geometric law of large numbers. Proceedings of the 16th International Conference on Artificial Intelligence and Statistics (2013), pp. 325–332. pdf.

    • Salehian2015

      Salehian H.; Chakraborty R.; Ofori E.; Vaillancourt D.; An efficient recursive estimator of the Fréchet mean on a hypersphere with applications to Medical Image Analysis. Mathematical Foundations of Computational Anatomy (2015). pdf.

    • Chakraborty2015

      Chakraborty R.; Vemuri B. C.; Recursive Fréchet Mean Computation on the Grassmannian and Its Applications to Computer Vision. Proceedings of the IEEE International Conference on Computer Vision (ICCV) (2015), pp. 4229-4237. doi: 10.1109/ICCV.2015.481, link.

    • Cheng2016

      Cheng G.; Ho J.; Salehian H.; Vemuri B. C.; Recursive Computation of the Fréchet Mean on Non-positively Curved Riemannian Manifolds with Applications. Riemannian Computing in Computer Vision. Springer, Cham (2016), pp. 21-43. doi: 10.1007/978-3-319-22957-7_2, pdf.

    • Chakraborty2019

      Chakraborty R.; Vemuri B. C.; Statistics on the (compact) Stiefel manifold: Theory and Applications. The Annals of Statistics (2019), 47(1), pp. 415-438. doi: 10.1214/18-AOS1692, arxiv: 1708.00045.

    • West1979

      West D. H. D.; Updating Mean and Variance Estimates: An Improved Method. Communications of the ACM (1979), 22(9), pp. 532–535. doi: 10.1145/359146.359153.

    • Pennec2006

      X. Pennec, “Intrinsic Statistics on Riemannian Manifolds: Basic Tools for Geometric Measurements,” J Math Imaging Vis, vol. 25, no. 1, p. 127, Jul. 2006, doi: 10.1007/s10851-006-6228-4.

    • Afsari2013

      Afsari, B; Tron, R.; Vidal, R.: On the Convergence of Gradient Descent for Finding the Riemannian Center of Mass, SIAM Journal on Control and Optimization (2013), 51(3), pp. 2230–2260, doi: 10.1137/12086282X, arxiv: 1201.0925

    • PennecArsigny2013

      Pennec X., Arsigny V.: Exponential Barycenters of the Canonical Cartan Connection and Invariant Means on Lie Groups. In: Nielsen F., Bhatia R. (eds) Matrix Information Geometry, (2013), pp. 123-166. doi: 10.1007/978-3-642-30232-9_7, hal: https://hal.inria.fr/hal-00699361/document

    • Karcher1977

      Karcher, H.: Riemannian center of mass and mollifier smoothing. Communications on Pure Applied Mathematics (1977), 30, pp. 509–541. doi 10.1002/cpa.3160300502

    • Bačák2014

      Bačák, M: Computing Medians and Means in Hadamard Spaces. SIAM Journal on Optimization (2014), 24(3), pp. 1542–1566, doi: 10.1137/140953393, arxiv: 1210.2145

    • FletcherVenkatasubramanianJoshi2008

      Fletcher, T., Venkatasubramanian, S., Joshi, S: Robust statistics on Riemannian manifolds via the geometric median 2008 IEEE Conference on Computer Vision and Pattern Recognition, doi: 10.1109/CVPR.2008.4587747,

    diff --git a/previews/PR644/features/testing.html b/previews/PR644/features/testing.html new file mode 100644 index 0000000000..8193864b9d --- /dev/null +++ b/previews/PR644/features/testing.html @@ -0,0 +1,31 @@ + +Testing · Manifolds.jl

    Testing

    Documentation for testing utilities for Manifolds.jl. The function test_manifold can be used to verify that your manifold correctly implements the Manifolds.jl interface. Similarly test_group and test_action can be used to verify implementation of groups and group actions.

    Manifolds.test_actionFunction
    test_action(
    +    A::AbstractGroupAction,
    +    a_pts::AbstractVector,
    +    m_pts::AbstractVector,
    +    X_pts = [];
    +    atol = 1e-10,
    +    atol_ident_compose = 0,
    +    test_optimal_alignment = false,
    +    test_mutating_group=true,
    +    test_mutating_action=true,
    +    test_diff = false,
    +    test_switch_direction = true,
    +)

    Tests general properties of the action A, given at least three different points that lie on it (contained in a_pts) and three different point that lie on the manifold it acts upon (contained in m_pts).

    Arguments

    • atol_ident_compose = 0: absolute tolerance for the test that composition with identity doesn't change the group element.
    source
    Manifolds.test_groupFunction
    test_group(
    +    G,
    +    g_pts::AbstractVector,
    +    X_pts::AbstractVector = [],
    +    Xe_pts::AbstractVector = [];
    +    atol = 1e-10,
    +    test_mutating = true,
    +    test_exp_lie_log = true,
    +    test_diff = false,
    +    test_invariance = false,
    +    test_lie_bracket=false,
    +    test_adjoint_action=false,
    +    diff_convs = [(), (LeftForwardAction(),), (RightBackwardAction(),)],
    +)

    Tests general properties of the group G, given at least three different points elements of it (contained in g_pts). Optionally, specify test_diff to test differentials of translation, using X_pts, which must contain at least one tangent vector at g_pts[1], and the direction conventions specified in diff_convs. Xe_pts should contain tangent vectors at identity for testing Lie algebra operations. If the group is equipped with an invariant metric, test_invariance indicates that the invariance should be checked for the provided points.

    source
    Manifolds.test_manifoldFunction
    test_manifold(
    +    M::AbstractManifold,
    +    pts::AbstractVector;
    +    args,
    +)

    Test general properties of manifold M, given at least three different points that lie on it (contained in pts).

    Arguments

    • basis_has_specialized_diagonalizing_get = false: if true, assumes that DiagonalizingOrthonormalBasis given in basis_types has get_coordinates and get_vector that work without caching.
    • basis_types_to_from = (): basis types that will be tested based on get_coordinates and get_vector.
    • basis_types_vecs = () : basis types that will be tested based on get_vectors
    • default_inverse_retraction_method = ManifoldsBase.LogarithmicInverseRetraction(): default method for inverse retractions (log.
    • default_retraction_method = ManifoldsBase.ExponentialRetraction(): default method for retractions (exp).
    • exp_log_atol_multiplier = 0: change absolute tolerance of exp/log tests (0 use default, i.e. deactivate atol and use rtol).
    • exp_log_rtol_multiplier = 1: change the relative tolerance of exp/log tests (1 use default). This is deactivated if the exp_log_atol_multiplier is nonzero.
    • expected_dimension_type = Integer: expected type of value returned by manifold_dimension.
    • inverse_retraction_methods = []: inverse retraction methods that will be tested.
    • is_mutating = true: whether mutating variants of functions should be tested.
    • is_point_atol_multiplier = 0: determines atol of is_point checks.
    • is_tangent_atol_multiplier = 0: determines atol of is_vector checks.
    • mid_point12 = test_exp_log ? shortest_geodesic(M, pts[1], pts[2], 0.5) : nothing: if not nothing, then check that mid_point(M, pts[1], pts[2]) is approximately equal to mid_point12. This is by default set to nothing if text_exp_log is set to false.
    • point_distributions = [] : point distributions to test.
    • rand_tvector_atol_multiplier = 0 : chage absolute tolerance in testing random vectors (0 use default, i.e. deactivate atol and use rtol) random tangent vectors are tangent vectors.
    • retraction_atol_multiplier = 0: change absolute tolerance of (inverse) retraction tests (0 use default, i.e. deactivate atol and use rtol).
    • retraction_rtol_multiplier = 1: change the relative tolerance of (inverse) retraction tests (1 use default). This is deactivated if the exp_log_atol_multiplier is nonzero.
    • retraction_methods = []: retraction methods that will be tested.
    • test_atlases = []: Vector or tuple of atlases that should be tested.
    • test_exp_log = true: if true, check that exp is the inverse of log.
    • test_injectivity_radius = true: whether implementation of injectivity_radius should be tested.
    • test_inplace = false : if true check if inplace variants work if they are activated, e.g. check that exp!(M, p, p, X) work if test_exp_log = true. This in general requires is_mutating to be true.
    • test_is_tangent: if true check that the default_inverse_retraction_method actually returns valid tangent vectors.
    • test_musical_isomorphisms = false : test musical isomorphisms.
    • test_mutating_rand = false : test the mutating random function for points on manifolds.
    • test_project_point = false: test projections onto the manifold.
    • test_project_tangent = false : test projections on tangent spaces.
    • test_representation_size = true : test repersentation size of points/tvectprs.
    • test_tangent_vector_broadcasting = true : test boradcasting operators on TangentSpace.
    • test_vector_spaces = true : test Vector bundle of this manifold.
    • test_default_vector_transport = false : test the default vector transport (usually parallel transport).
    • test_vee_hat = false: test vee and hat functions.
    • tvector_distributions = [] : tangent vector distributions to test.
    • vector_transport_methods = []: vector transport methods that should be tested.
    • vector_transport_inverse_retractions = [default_inverse_retraction_method for _ in 1:length(vector_transport_methods)]` inverse retractions to use with the vector transport method (especially the differentiated ones)
    • vector_transport_to = [ true for _ in 1:length(vector_transport_methods)]: whether to check the to variant of vector transport
    • vector_transport_direction = [ true for _ in 1:length(vector_transport_methods)]: whether to check the direction variant of vector transport
    source
    Manifolds.find_epsFunction
    find_eps(x...)

    Find an appropriate tolerance for given points or tangent vectors, or their types.

    source
    Manifolds.test_parallel_transportFunction
    test_parallel_transport(M,P; along=false, to=true, diretion=true)

    Generic tests for parallel transport on Mgiven at least two pointsin P.

    The single functions to transport along (a curve), to (a point) or (towards a) direction are sub-tests that can be activated by the keywords arguemnts

    !!! Note Since the interface to specify curves is not yet provided, the along keyword does not have an effect yet

    source
    diff --git a/previews/PR644/features/utilities.html b/previews/PR644/features/utilities.html new file mode 100644 index 0000000000..75fd92dc44 --- /dev/null +++ b/previews/PR644/features/utilities.html @@ -0,0 +1,8 @@ + +Utilities · Manifolds.jl

    Ease of notation

    The following terms introduce a nicer notation for some operations, for example using the ∈ operator, $p ∈ \mathcal M$, to determine whether $p$ is a point on the AbstractManifold $\mathcal M$.

    Base.inFunction
    Base.in(p, M::AbstractManifold; kwargs...)
    +p ∈ M

    Check, whether a point p is a valid point (i.e. in) a AbstractManifold M. This method employs is_point deactivating the error throwing option.

    source
    Base.in(p, TpM::TangentSpaceAtPoint; kwargs...)
    +X ∈ TangentSpaceAtPoint(M,p)

    Check whether X is a tangent vector from (in) the tangent space $T_p\mathcal M$, i.e. the TangentSpaceAtPoint at p on the AbstractManifold M. This method uses is_vector deactivating the error throw option.

    source

    Fallback for the exponential map: Solving the corresponding ODE

    When additionally loading NLSolve.jl the following fallback for the exponential map is available.

    Public documentation

    The following functions are of interest for extending and using the ProductManifold.

    Manifolds.submanifold_componentFunction
    submanifold_component(M::AbstractManifold, p, i::Integer)
    +submanifold_component(M::AbstractManifold, p, ::Val(i)) where {i}
    +submanifold_component(p, i::Integer)
    +submanifold_component(p, ::Val(i)) where {i}

    Project the product array p on M to its ith component. A new array is returned.

    source
    Manifolds.submanifold_componentsFunction
    submanifold_components(M::AbstractManifold, p)
    +submanifold_components(p)

    Get the projected components of p on the submanifolds of M. The components are returned in a Tuple.

    source
    Manifolds.ProductReprType
    ProductRepr(parts)

    A more general but slower representation of points and tangent vectors on a product manifold.

    Example:

    A product point on a product manifold Sphere(2) × Euclidean(2) might be created as

    ProductRepr([1.0, 0.0, 0.0], [2.0, 3.0])

    where [1.0, 0.0, 0.0] is the part corresponding to the sphere factor and [2.0, 3.0] is the part corresponding to the euclidean manifold.

    Warning

    ProductRepr is deprecated and will be removed in a future release. Please use ArrayPartition instead.

    source

    Specific exception types

    For some manifolds it is useful to keep an extra index, at which point on the manifold, the error occurred as well as to collect all errors that occurred on a manifold. This page contains the manifold-specific error messages this package introduces.

    diff --git a/previews/PR644/index.html b/previews/PR644/index.html new file mode 100644 index 0000000000..b1f8c3829a --- /dev/null +++ b/previews/PR644/index.html @@ -0,0 +1,22 @@ + +Home · Manifolds.jl

    Manifolds

    Manifolds.ManifoldsModule

    Manifolds.jl provides a library of manifolds aiming for an easy-to-use and fast implementation.

    source

    The implemented manifolds are accompanied by their mathematical formulae.

    The manifolds are implemented using the interface for manifolds given in ManifoldsBase.jl. You can use that interface to implement your own software on manifolds, such that all manifolds based on that interface can be used within your code.

    For more information, see the About section.

    Getting started

    To install the package just type

    using Pkg; Pkg.add("Manifolds")

    Then you can directly start, for example to stop half way from the north pole on the Sphere to a point on the the equator, you can generate the shortest_geodesic. It internally employs log and exp.

    using Manifolds
    +M = Sphere(2)
    +γ = shortest_geodesic(M, [0., 0., 1.], [0., 1., 0.])
    +γ(0.5)
    3-element Vector{Float64}:
    + 0.0
    + 0.7071067811865475
    + 0.7071067811865476

    Citation

    If you use Manifolds.jl in your work, please cite the following

    @online{2106.08777,
    +    Author = {Seth D. Axen and Mateusz Baran and Ronny Bergmann and Krzysztof Rzecki},
    +    Title = {Manifolds.jl: An Extensible Julia Framework for Data Analysis on Manifolds},
    +    Year = {2021},
    +    Eprint = {2106.08777},
    +    Eprinttype = {arXiv},
    +}

    To refer to a certain version we recommend to also cite for example

    @software{manifoldsjl-zenodo-mostrecent,
    +  Author = {Seth D. Axen and Mateusz Baran and Ronny Bergmann},
    +  Title = {Manifolds.jl},
    +  Doi = {10.5281/ZENODO.4292129},
    +  Url = {https://zenodo.org/record/4292129},
    +  Publisher = {Zenodo},
    +  Year = {2021},
    +  Copyright = {MIT License}
    +}

    for the most recent version or a corresponding version specific DOI, see the list of all versions. Note that both citations are in BibLaTeX format.

    diff --git a/previews/PR644/manifolds/centeredmatrices.html b/previews/PR644/manifolds/centeredmatrices.html new file mode 100644 index 0000000000..0d3f1ef3d1 --- /dev/null +++ b/previews/PR644/manifolds/centeredmatrices.html @@ -0,0 +1,10 @@ + +Centered matrices · Manifolds.jl

    Centered matrices

    Manifolds.CenteredMatricesType
    CenteredMatrices{m,n,𝔽} <: AbstractDecoratorManifold{𝔽}

    The manifold of $m × n$ real-valued or complex-valued matrices whose columns sum to zero, i.e.

    \[\bigl\{ p ∈ 𝔽^{m × n}\ \big|\ [1 … 1] * p = [0 … 0] \bigr\},\]

    where $𝔽 ∈ \{ℝ,ℂ\}$.

    Constructor

    CenteredMatrices(m, n[, field=ℝ])

    Generate the manifold of m-by-n (field-valued) matrices whose columns sum to zero.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::CenteredMatrices{m,n,𝔽}, p; kwargs...)

    Check whether the matrix is a valid point on the CenteredMatrices M, i.e. is an m-by-n matrix whose columns sum to zero.

    The tolerance for the column sums of p can be set using kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::CenteredMatrices{m,n,𝔽}, p, X; kwargs... )

    Check whether X is a tangent vector to manifold point p on the CenteredMatrices M, i.e. that X is a matrix of size (m, n) whose columns sum to zero and its values are from the correct AbstractNumbers. The tolerance for the column sums of p and X can be set using kwargs....

    source
    ManifoldsBase.projectMethod
    project(M::CenteredMatrices, p, X)

    Project the matrix X onto the tangent space at p on the CenteredMatrices M, i.e.

    \[\operatorname{proj}_p(X) = X - \begin{bmatrix} +1\\ +⋮\\ +1 +\end{bmatrix} * [c_1 \dots c_n],\]

    where $c_i = \frac{1}{m}\sum_{j=1}^m x_{j,i}$ for $i = 1, \dots, n$.

    source
    ManifoldsBase.projectMethod
    project(M::CenteredMatrices, p)

    Projects p from the embedding onto the CenteredMatrices M, i.e.

    \[\operatorname{proj}_{\mathcal M}(p) = p - \begin{bmatrix} +1\\ +⋮\\ +1 +\end{bmatrix} * [c_1 \dots c_n],\]

    where $c_i = \frac{1}{m}\sum_{j=1}^m p_{j,i}$ for $i = 1, \dots, n$.

    source
    diff --git a/previews/PR644/manifolds/choleskyspace.html b/previews/PR644/manifolds/choleskyspace.html new file mode 100644 index 0000000000..07edeee4ff --- /dev/null +++ b/previews/PR644/manifolds/choleskyspace.html @@ -0,0 +1,6 @@ + +Cholesky space · Manifolds.jl

    Cholesky space

    The Cholesky space is a Riemannian manifold on the lower triangular matrices. Its metric is based on the cholesky decomposition. The CholeskySpace is used to define the LogCholeskyMetric on the manifold of SymmetricPositiveDefinite matrices.

    Manifolds.CholeskySpaceType
    CholeskySpace{N} <: AbstractManifold{ℝ}

    The manifold of lower triangular matrices with positive diagonal and a metric based on the cholesky decomposition. The formulae for this manifold are for example summarized in Table 1 of [Lin2019].

    Constructor

    CholeskySpace(n)

    Generate the manifold of $n× n$ lower triangular matrices with positive diagonal.

    source
    Base.expMethod
    exp(M::CholeskySpace, p, X)

    Compute the exponential map on the CholeskySpace M emanating from the lower triangular matrix with positive diagonal p towards the lower triangular matrix X The formula reads

    \[\exp_p X = ⌊ p ⌋ + ⌊ X ⌋ + \operatorname{diag}(p) +\operatorname{diag}(p)\exp\bigl( \operatorname{diag}(X)\operatorname{diag}(p)^{-1}\bigr),\]

    where $⌊\cdot⌋$ denotes the strictly lower triangular matrix, and $\operatorname{diag}$ extracts the diagonal matrix.

    source
    Base.logMethod
    log(M::CholeskySpace, X, p, q)

    Compute the logarithmic map on the CholeskySpace M for the geodesic emanating from the lower triangular matrix with positive diagonal p towards q. The formula reads

    \[\log_p q = ⌊ p ⌋ - ⌊ q ⌋ + \operatorname{diag}(p)\log\bigl(\operatorname{diag}(q)\operatorname{diag}(p)^{-1}\bigr),\]

    where $⌊\cdot⌋$ denotes the strictly lower triangular matrix, and $\operatorname{diag}$ extracts the diagonal matrix.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::CholeskySpace, p; kwargs...)

    Check whether the matrix p lies on the CholeskySpace M, i.e. it's size fits the manifold, it is a lower triangular matrix and has positive entries on the diagonal. The tolerance for the tests can be set using the kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::CholeskySpace, p, X; kwargs... )

    Check whether v is a tangent vector to p on the CholeskySpace M, i.e. after check_point(M,p), X has to have the same dimension as p and a symmetric matrix. The tolerance for the tests can be set using the kwargs....

    source
    ManifoldsBase.distanceMethod
    distance(M::CholeskySpace, p, q)

    Compute the Riemannian distance on the CholeskySpace M between two matrices p, q that are lower triangular with positive diagonal. The formula reads

    \[d_{\mathcal M}(p,q) = \sqrt{\sum_{i>j} (p_{ij}-q_{ij})^2 + +\sum_{j=1}^m (\log p_{jj} - \log q_{jj})^2 +}\]

    source
    ManifoldsBase.innerMethod
    inner(M::CholeskySpace, p, X, Y)

    Compute the inner product on the CholeskySpace M at the lower triangular matric with positive diagonal p and the two tangent vectors X,Y, i.e they are both lower triangular matrices with arbitrary diagonal. The formula reads

    \[g_p(X,Y) = \sum_{i>j} X_{ij}Y_{ij} + \sum_{j=1}^m X_{ii}Y_{ii}p_{ii}^{-2}\]

    source
    ManifoldsBase.parallel_transport_toMethod
    parallel_transport_to(M::CholeskySpace, p, X, q)

    Parallely transport the tangent vector X at p along the geodesic to q on the CholeskySpace manifold M. The formula reads

    \[\mathcal P_{q←p}(X) = ⌊ X ⌋ ++ \operatorname{diag}(q)\operatorname{diag}(p)^{-1}\operatorname{diag}(X),\]

    where $⌊\cdot⌋$ denotes the strictly lower triangular matrix, and $\operatorname{diag}$ extracts the diagonal matrix.

    source

    Literature

    • Lin2019

      Lin, Zenhua: Riemannian Geometry of Symmetric Positive Definite Matrices via Cholesky Decomposition, arXiv: 1908.09326.

    diff --git a/previews/PR644/manifolds/circle.html b/previews/PR644/manifolds/circle.html new file mode 100644 index 0000000000..4c520876f5 --- /dev/null +++ b/previews/PR644/manifolds/circle.html @@ -0,0 +1,3 @@ + +Circle · Manifolds.jl

    Circle

    Manifolds.CircleType
    Circle{𝔽} <: AbstractManifold{𝔽}

    The circle $𝕊^1$ is a manifold here represented by real-valued points in $[-π,π)$ or complex-valued points $z ∈ ℂ$ of absolute value $\lvert z\rvert = 1$.

    Constructor

    Circle(𝔽=ℝ)

    Generate the -valued Circle represented by angles, which alternatively can be set to use the AbstractNumbers 𝔽=ℂ to obtain the circle represented by -valued circle of unit numbers.

    source
    Base.expMethod
    exp(M::Circle, p, X)

    Compute the exponential map on the Circle.

    \[\exp_p X = (p+X)_{2π},\]

    where $(\cdot)_{2π}$ is the (symmetric) remainder with respect to division by $2π$, i.e. in $[-π,π)$.

    For the complex-valued case, the same formula as for the Sphere $𝕊^1$ is applied to values in the complex plane.

    source
    Base.logMethod
    log(M::Circle, p, q)

    Compute the logarithmic map on the Circle M.

    \[\log_p q = (q-p)_{2π},\]

    where $(\cdot)_{2π}$ is the (symmetric) remainder with respect to division by $2π$, i.e. in $[-π,π)$.

    For the complex-valued case, the same formula as for the Sphere $𝕊^1$ is applied to values in the complex plane.

    source
    Base.randMethod
    Random.rand(M::Circle{ℝ}; vector_at = nothing, σ::Real=1.0)

    If vector_at is nothing, return a random point on the Circle $\mathbb S^1$ by picking a random element from $[-\pi,\pi)$ uniformly.

    If vector_at is not nothing, return a random tangent vector from the tangent space of the point vector_at on the Circle by using a normal distribution with mean 0 and standard deviation σ.

    source
    Manifolds.sym_remMethod
    sym_rem(x,[T=π])

    Compute symmetric remainder of x with respect to the interall 2*T, i.e. (x+T)%2T, where the default for T is $π$

    source
    ManifoldsBase.check_pointMethod
    check_point(M::Circle, p)

    Check whether p is a point on the Circle M. For the real-valued case, p is an angle and hence it checks that $p ∈ [-π,π)$. for the complex-valued case, it is a unit number, $p ∈ ℂ$ with $\lvert p \rvert = 1$.

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::Circle, p, X; kwargs...)

    Check whether X is a tangent vector in the tangent space of p on the Circle M. For the real-valued case represented by angles, all X are valid, since the tangent space is the whole real line. For the complex-valued case X has to lie on the line parallel to the tangent line at p in the complex plane, i.e. their inner product has to be zero.

    source
    ManifoldsBase.distanceMethod
    distance(M::Circle, p, q)

    Compute the distance on the Circle M, which is the absolute value of the symmetric remainder of p and q for the real-valued case and the angle between both complex numbers in the Gaussian plane for the complex-valued case.

    source
    ManifoldsBase.innerMethod
    inner(M::Circle, p, X, Y)

    Compute the inner product of the two tangent vectors X,Y from the tangent plane at p on the Circle M using the restriction of the metric from the embedding, i.e.

    \[g_p(X,Y) = X*Y\]

    for the real case and

    \[g_p(X,Y) = Y^\mathrm{T}X\]

    for the complex case interpreting complex numbers in the Gaussian plane.

    source
    ManifoldsBase.parallel_transport_toMethod
     parallel_transport_to(M::Circle, p, X, q)

    Compute the parallel transport of X from the tangent space at p to the tangent space at q on the Circle M. For the real-valued case this results in the identity. For the complex-valud case, the formula is the same as for the Sphere(1) in the complex plane.

    \[\mathcal P_{q←p} X = X - \frac{⟨\log_p q,X⟩_p}{d^2_{ℂ}(p,q)} +\bigl(\log_p q + \log_q p \bigr),\]

    where log denotes the logarithmic map on M.

    source
    ManifoldsBase.projectMethod
    project(M::Circle, p, X)

    Project a value X onto the tangent space of the point p on the Circle M.

    For the real-valued case this is just the identity. For the complex valued case X is projected onto the line in the complex plane that is parallel to the tangent to p on the unit circle and contains 0.

    source
    ManifoldsBase.projectMethod
    project(M::Circle, p)

    Project a point p onto the Circle M. For the real-valued case this is the remainder with respect to modulus $2π$. For the complex-valued case the result is the projection of p onto the unit circle in the complex plane.

    source
    Statistics.meanMethod
    mean(M::Circle{ℂ}, x::AbstractVector[, w::AbstractWeights])

    Compute the Riemannian mean of x of points on the Circle $𝕊^1$, reprsented by complex numbers, i.e. embedded in the complex plane. Comuting the sum

    \[s = \sum_{i=1}^n x_i\]

    the mean is the angle of the complex number $s$, so represented in the complex plane as $\frac{s}{\lvert s \rvert}$, whenever $s \neq 0$.

    If the sum $s=0$, the mean is not unique. For example for opposite points or equally spaced angles.

    source
    Statistics.meanMethod
    mean(M::Circle{ℝ}, x::AbstractVector[, w::AbstractWeights])

    Compute the Riemannian mean of x of points on the Circle $𝕊^1$, reprsented by real numbers, i.e. the angular mean

    \[\operatorname{atan}\Bigl( \sum_{i=1}^n w_i\sin(x_i), \sum_{i=1}^n w_i\sin(x_i) \Bigr).\]

    source
    diff --git a/previews/PR644/manifolds/connection.html b/previews/PR644/manifolds/connection.html new file mode 100644 index 0000000000..58f47c186f --- /dev/null +++ b/previews/PR644/manifolds/connection.html @@ -0,0 +1,26 @@ + +Connection manifold · Manifolds.jl

    Connection manifold

    A connection manifold always consists of a topological manifold together with a connection $\Gamma$.

    However, often there is an implicitly assumed (default) connection, like the LeviCivitaConnection connection on a Riemannian manifold. It is not necessary to use this decorator if you implement just one (or the first) connection. If you later introduce a second, the old (first) connection can be used without an explicitly stated connection.

    This manifold decorator serves two purposes:

    1. to implement different connections (e.g. in closed form) for one AbstractManifold
    2. to provide a way to compute geodesics on manifolds, where this AbstractAffineConnection does not yield a closed formula.

    An example of usage can be found in Cartan-Schouten connections, see AbstractCartanSchoutenConnection.

    Types

    Manifolds.IsConnectionManifoldType
    IsConnectionManifold <: AbstractTrait

    Specify that a certain decorated Manifold is a connection manifold in the sence that it provides explicit connection properties, extending/changing the default connection properties of a manifold.

    source

    Functions

    Base.expMethod
    exp(::TraitList{IsConnectionManifold}, M::AbstractDecoratorManifold, p, X)

    Compute the exponential map on a manifold that IsConnectionManifold M equipped with corresponding affine connection.

    If M is a MetricManifold with a IsDefaultMetric trait, this method falls back to exp(M, p, X).

    Otherwise it numerically integrates the underlying ODE, see solve_exp_ode. Currently, the numerical integration is only accurate when using a single coordinate chart that covers the entire manifold. This excludes coordinates in an embedded space.

    source
    Manifolds.christoffel_symbols_firstMethod
    christoffel_symbols_first(
    +    M::AbstractManifold,
    +    p,
    +    B::AbstractBasis;
    +    backend::AbstractDiffBackend = default_differential_backend(),
    +)

    Compute the Christoffel symbols of the first kind in local coordinates of basis B. The Christoffel symbols are (in Einstein summation convention)

    \[Γ_{ijk} = \frac{1}{2} \Bigl[g_{kj,i} + g_{ik,j} - g_{ij,k}\Bigr],\]

    where $g_{ij,k}=\frac{∂}{∂ p^k} g_{ij}$ is the coordinate derivative of the local representation of the metric tensor. The dimensions of the resulting multi-dimensional array are ordered $(i,j,k)$.

    source
    Manifolds.christoffel_symbols_secondMethod
    christoffel_symbols_second(
    +    M::AbstractManifold,
    +    p,
    +    B::AbstractBasis;
    +    backend::AbstractDiffBackend = default_differential_backend(),
    +)

    Compute the Christoffel symbols of the second kind in local coordinates of basis B. For affine connection manifold the Christoffel symbols need to be explicitly implemented while, for a MetricManifold they are computed as (in Einstein summation convention)

    \[Γ^{l}_{ij} = g^{kl} Γ_{ijk},\]

    where $Γ_{ijk}$ are the Christoffel symbols of the first kind (see christoffel_symbols_first), and $g^{kl}$ is the inverse of the local representation of the metric tensor. The dimensions of the resulting multi-dimensional array are ordered $(l,i,j)$.

    source
    Manifolds.christoffel_symbols_second_jacobianMethod
    christoffel_symbols_second_jacobian(
    +    M::AbstractManifold,
    +    p,
    +    B::AbstractBasis;
    +    backend::AbstractDiffBackend = default_differential_backend(),
    +)

    Get partial derivatives of the Christoffel symbols of the second kind for manifold M at p with respect to the coordinates of B, i.e.

    \[\frac{∂}{∂ p^l} Γ^{k}_{ij} = Γ^{k}_{ij,l}.\]

    The dimensions of the resulting multi-dimensional array are ordered $(i,j,k,l)$.

    source
    Manifolds.gaussian_curvatureMethod
    gaussian_curvature(M::AbstractManifold, p, B::AbstractBasis; backend::AbstractDiffBackend = default_differential_backend())

    Compute the Gaussian curvature of the manifold M at the point p using basis B. This is equal to half of the scalar Ricci curvature, see ricci_curvature.

    source
    Manifolds.solve_exp_odeMethod
    solve_exp_ode(
    +    M::AbstractConnectionManifold,
    +    p,
    +    X,
    +    t::Number,
    +    B::AbstractBasis;
    +    backend::AbstractDiffBackend = default_differential_backend(),
    +    solver = AutoVern9(Rodas5()),
    +    kwargs...,
    +)

    Approximate the exponential map on the manifold by evaluating the ODE descripting the geodesic at 1, assuming the default connection of the given manifold by solving the ordinary differential equation

    \[\frac{d^2}{dt^2} p^k + Γ^k_{ij} \frac{d}{dt} p_i \frac{d}{dt} p_j = 0,\]

    where $Γ^k_{ij}$ are the Christoffel symbols of the second kind, and the Einstein summation convention is assumed. The argument solver follows the OrdinaryDiffEq conventions. kwargs... specify keyword arguments that will be passed to OrdinaryDiffEq.solve.

    Currently, the numerical integration is only accurate when using a single coordinate chart that covers the entire manifold. This excludes coordinates in an embedded space.

    Note

    This function only works when OrdinaryDiffEq.jl is loaded with

    using OrdinaryDiffEq
    source
    ManifoldsBase.riemann_tensorMethod
    riemann_tensor(M::AbstractManifold, p, B::AbstractBasis; backend::AbstractDiffBackend=default_differential_backend())

    Compute the Riemann tensor $R^l_{ijk}$, also known as the Riemann curvature tensor, at the point p in local coordinates defined by B. The dimensions of the resulting multi-dimensional array are ordered $(l,i,j,k)$.

    The function uses the coordinate expression involving the second Christoffel symbol, see https://en.wikipedia.org/wiki/Riemann_curvature_tensor#Coordinate_expression for details.

    See also

    christoffel_symbols_second, christoffel_symbols_second_jacobian

    source

    Charts and bases of vector spaces

    All connection-related functions take a basis of a vector space as one of the arguments. This is needed because generally there is no way to define these functions without referencing a basis. In some cases there is no need to be explicit about this basis, and then for example a DefaultOrthonormalBasis object can be used. In cases where being explicit about these bases is needed, for example when using multiple charts, a basis can be specified, for example using induced_basis.

    diff --git a/previews/PR644/manifolds/elliptope.html b/previews/PR644/manifolds/elliptope.html new file mode 100644 index 0000000000..f97a41fc21 --- /dev/null +++ b/previews/PR644/manifolds/elliptope.html @@ -0,0 +1,10 @@ + +Elliptope · Manifolds.jl

    Elliptope

    Manifolds.ElliptopeType
    Elliptope{N,K} <: AbstractDecoratorManifold{ℝ}

    The Elliptope manifold, also known as the set of correlation matrices, consists of all symmetric positive semidefinite matrices of rank $k$ with unit diagonal, i.e.,

    \[\begin{aligned} +\mathcal E(n,k) = +\bigl\{p ∈ ℝ^{n × n}\ \big|\ &a^\mathrm{T}pa \geq 0 \text{ for all } a ∈ ℝ^{n},\\ +&p_{ii} = 1 \text{ for all } i=1,\ldots,n,\\ +&\text{and } p = qq^{\mathrm{T}} \text{ for } q \in ℝ^{n × k} \text{ with } \operatorname{rank}(p) = \operatorname{rank}(q) = k +\bigr\}. +\end{aligned}\]

    And this manifold is working solely on the matrices $q$. Note that this $q$ is not unique, indeed for any orthogonal matrix $A$ we have $(qA)(qA)^{\mathrm{T}} = qq^{\mathrm{T}} = p$, so the manifold implemented here is the quotient manifold. The unit diagonal translates to unit norm columns of $q$.

    The tangent space at $p$, denoted $T_p\mathcal E(n,k)$, is also represented by matrices $Y\in ℝ^{n × k}$ and reads as

    \[T_p\mathcal E(n,k) = \bigl\{ +X ∈ ℝ^{n × n}\,|\,X = qY^{\mathrm{T}} + Yq^{\mathrm{T}} \text{ with } X_{ii} = 0 \text{ for } i=1,\ldots,n +\bigr\}\]

    endowed with the Euclidean metric from the embedding, i.e. from the $ℝ^{n × k}$

    This manifold was for example investigated in[JourneeBachAbsilSepulchre2010].

    Constructor

    Elliptope(n,k)

    generates the manifold $\mathcal E(n,k) \subset ℝ^{n × n}$.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::Elliptope, q; kwargs...)

    checks, whether q is a valid reprsentation of a point $p=qq^{\mathrm{T}}$ on the Elliptope M, i.e. is a matrix of size (N,K), such that $p$ is symmetric positive semidefinite and has unit trace. Since by construction $p$ is symmetric, this is not explicitly checked. Since $p$ is by construction positive semidefinite, this is not checked. The tolerances for positive semidefiniteness and unit trace can be set using the kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::Elliptope, q, Y; kwargs... )

    Check whether $X = qY^{\mathrm{T}} + Yq^{\mathrm{T}}$ is a tangent vector to $p=qq^{\mathrm{T}}$ on the Elliptope M, i.e. Y has to be of same dimension as q and a $X$ has to be a symmetric matrix with zero diagonal.

    The tolerance for the base point check and zero diagonal can be set using the kwargs.... Note that symmetric of $X$ holds by construction an is not explicitly checked.

    source
    ManifoldsBase.projectMethod
    project(M::Elliptope, q, Y)

    Project Y onto the tangent space at q, i.e. row-wise onto the oblique manifold.

    source
    ManifoldsBase.representation_sizeMethod
    representation_size(M::Elliptope)

    Return the size of an array representing an element on the Elliptope manifold M, i.e. $n × k$, the size of such factor of $p=qq^{\mathrm{T}}$ on $\mathcal M = \mathcal E(n,k)$.

    source
    ManifoldsBase.retractMethod
    retract(M::Elliptope, q, Y, ::ProjectionRetraction)

    compute a projection based retraction by projecting $q+Y$ back onto the manifold.

    source

    Literature

    diff --git a/previews/PR644/manifolds/essentialmanifold.html b/previews/PR644/manifolds/essentialmanifold.html new file mode 100644 index 0000000000..9cc5105f5e --- /dev/null +++ b/previews/PR644/manifolds/essentialmanifold.html @@ -0,0 +1,2 @@ + +Essential manifold · Manifolds.jl

    Essential Manifold

    The essential manifold is modeled as an AbstractPowerManifold of the $3\times3$ Rotations and uses NestedPowerRepresentation.

    Manifolds.EssentialManifoldType
    EssentialManifold <: AbstractPowerManifold{ℝ}

    The essential manifold is the space of the essential matrices which is represented as a quotient space of the Rotations manifold product $\mathrm{SO}(3)^2$.

    Let $R_x(θ), R_y(θ), R_x(θ) \in ℝ^{x\times 3}$ denote the rotation around the $z$, $y$, and $x$ axis in $ℝ^3$, respectively, and further the groups

    \[H_z = \bigl\{(R_z(θ),R_z(θ))\ \big|\ θ ∈ [-π,π) \bigr\}\]

    and

    \[H_π = \bigl\{ (I,I), (R_x(π), R_x(π)), (I,R_z(π)), (R_x(π), R_y(π)) \bigr\}\]

    acting elementwise on the left from $\mathrm{SO}(3)^2$ (component wise).

    Then the unsigned Essential manifold $\mathcal{M}_{\text{E}}$ can be identified with the quotient space

    \[\mathcal{M}_{\text{E}} := (\text{SO}(3)×\text{SO}(3))/(H_z × H_π),\]

    and for the signed Essential manifold $\mathcal{M}_{\text{Ǝ}}$, the quotient reads

    \[\mathcal{M}_{\text{Ǝ}} := (\text{SO}(3)×\text{SO}(3))/(H_z).\]

    An essential matrix is defined as

    \[E = (R'_1)^T [T'_2 - T'_1]_{×} R'_2,\]

    where the poses of two cameras $(R_i', T_i'), i=1,2$, are contained in the space of rigid body transformations $SE(3)$ and the operator $[⋅]_{×}\colon ℝ^3 \to \operatorname{SkewSym}(3)$ denotes the matrix representation of the cross product operator. For more details see [TronDaniilidis2017].

    Constructor

    EssentialManifold(is_signed=true)

    Generate the manifold of essential matrices, either the signed (is_signed=true) or unsigned (is_signed=false) variant.

    source

    Functions

    Base.expMethod
    exp(M::EssentialManifold, p, X)

    Compute the exponential map on the EssentialManifold from p into direction X, i.e.

    \[\text{exp}_p(X) =\text{exp}_g( \tilde X), \quad g \in \text(SO)(3)^2,\]

    where $\tilde X$ is the horizontal lift of $X$[TronDaniilidis2017].

    source
    Base.logMethod
    log(M::EssentialManifold, p, q)

    Compute the logarithmic map on the EssentialManifold M, i.e. the tangent vector, whose geodesic starting from p reaches q after time 1. Here, $p=(R_{p_1},R_{p_2})$ and $q=(R_{q_1},R_{q_2})$ are elements of $SO(3)^2$. We use that any essential matrix can, up to scale, be decomposed to

    \[E = R_1^T [e_z]_{×}R_2,\]

    where $(R_1,R_2)∈SO(3)^2$. Two points in $SO(3)^2$ are equivalent iff their corresponding essential matrices are equal (up to a sign flip). To compute the logarithm, we first move q to another representative of its equivalence class. For this, we find $t= t_{\text{opt}}$ for which the function

    \[f(t) = f_1 + f_2, \quad f_i = \frac{1}{2} θ^2_i(t), \quad θ_i(t)=d(R_{p_i},R_z(t)R_{b_i}) \text{ for } i=1,2,\]

    where $d(⋅,⋅)$ is the distance function in $SO(3)$, is minimized. Further, the group $H_z$ acting on the left on $SO(3)^2$ is defined as

    \[H_z = \{(R_z(θ),R_z(θ))\colon θ \in [-π,π) \},\]

    where $R_z(θ)$ is the rotation around the z axis with angle $θ$. Points in $H_z$ are denoted by $S_z$. Then, the logarithm is defined as

    \[\log_p (S_z(t_{\text{opt}})q) = [\text{Log}(R_{p_i}^T R_z(t_{\text{opt}})R_{b_i})]_{i=1,2},\]

    where $\text{Log}$ is the logarithm on $SO(3)$. For more details see [TronDaniilidis2017].

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::EssentialManifold, p, X; kwargs... )

    Check whether X is a tangent vector to manifold point p on the EssentialManifold M, i.e. X has to be a 2-element array of 3-by-3 skew-symmetric matrices.

    source
    ManifoldsBase.distanceMethod
    distance(M::EssentialManifold, p, q)

    Compute the Riemannian distance between the two points p and q on the EssentialManifold. This is done by computing the distance of the equivalence classes $[p]$ and $[q]$ of the points $p=(R_{p_1},R_{p_2}), q=(R_{q_1},R_{q_2}) ∈ SO(3)^2$, respectively. Two points in $SO(3)^2$ are equivalent iff their corresponding essential matrices, given by

    \[E = R_1^T [e_z]_{×}R_2,\]

    are equal (up to a sign flip). Using the logarithmic map, the distance is given by

    \[\text{dist}([p],[q]) = \| \text{log}_{[p]} [q] \| = \| \log_p (S_z(t_{\text{opt}})q) \|,\]

    where $S_z ∈ H_z = \{(R_z(θ),R_z(θ))\colon θ \in [-π,π) \}$ in which $R_z(θ)$ is the rotation around the z axis with angle $θ$ and $t_{\text{opt}}$ is the minimizer of the cost function

    \[f(t) = f_1 + f_2, \quad f_i = \frac{1}{2} θ^2_i(t), \quad θ_i(t)=d(R_{p_i},R_z(t)R_{b_i}) \text{ for } i=1,2,\]

    where $d(⋅,⋅)$ is the distance function in $SO(3)$[TronDaniilidis2017].

    source
    ManifoldsBase.projectMethod
    project(M::EssentialManifold, p, X)

    Project the matrix X onto the tangent space

    \[T_{p} \text{SO}(3)^2 = T_{\text{vp}}\text{SO}(3)^2 ⊕ T_{\text{hp}}\text{SO}(3)^2,\]

    by first computing its projection onto the vertical space $T_{\text{vp}}\text{SO}(3)^2$ using vert_proj. Then the orthogonal projection of X onto the horizontal space $T_{\text{hp}}\text{SO}(3)^2$ is defined as

    \[\Pi_h(X) = X - \frac{\text{vert\_proj}_p(X)}{2} \begin{bmatrix} R_1^T e_z \\ R_2^T e_z \end{bmatrix},\]

    with $R_i = R_0 R'_i, i=1,2,$ where $R'_i$ is part of the pose of camera $i$ $g_i = (R'_i,T'_i) ∈ \text{SE}(3)$ and $R_0 ∈ \text{SO}(3)$ such that $R_0(T'_2-T'_1) = e_z$.

    source

    Internal Functions

    Manifolds.dist_min_angle_pairMethod
    dist_min_angle_pair(p, q)

    This function computes the global minimizer of the function

    \[f(t) = f_1 + f_2, \quad f_i = \frac{1}{2} θ^2_i(t), \quad θ_i(t)=d(R_{p_i},R_z(t)R_{b_i}) \text{ for } i=1,2,\]

    for the given values. This is done by finding the discontinuity points $t_{d_i}, i=1,2$ of its derivative and using Newton's method to minimize the function over the intervals $[t_{d_1},t_{d_2}]$ and $[t_{d_2},t_{d_1}+2π]$ separately. Then, the minimizer for which $f$ is minimal is chosen and given back together with the minimal value. For more details see Algorithm 1 in [TronDaniilidis2017].

    source
    Manifolds.dist_min_angle_pair_df_newtonMethod
    dist_min_angle_pair_df_newton(m1, Φ1, c1, m2, Φ2, c2, t_min, t_low, t_high)

    This function computes the minimizer of the function

    \[f(t) = f_1 + f_2, \quad f_i = \frac{1}{2} θ^2_i(t), \quad θ_i(t)=d(R_{p_i},R_z(t)R_{b_i}) \text{ for } i=1,2,\]

    in the interval $[$t_low, t_high$]$ using Newton's method. For more details see [TronDaniilidis2017].

    source
    Manifolds.dist_min_angle_pair_discontinuity_distanceMethod
    dist_min_angle_pair_discontinuity_distance(q)

    This function computes the point $t_{\text{di}}$ for which the first derivative of

    \[f(t) = f_1 + f_2, \quad f_i = \frac{1}{2} θ^2_i(t), \quad θ_i(t)=d(R_{p_i},R_z(t)R_{b_i}) \text{ for } i=1,2,\]

    does not exist. This is the case for $\sin(θ_i(t_{\text{di}})) = 0$. For more details see Proposition 9 and its proof, as well as Lemma 1 in [TronDaniilidis2017].

    source
    Manifolds.vert_projMethod
    vert_proj(M::EssentialManifold, p, X)

    Project X onto the vertical space $T_{\text{vp}}\text{SO}(3)^2$ with

    \[\text{vert\_proj}_p(X) = e_z^T(R_1 X_1 + R_2 X_2),\]

    where $e_z$ is the third unit vector, $X_i ∈ T_{p}\text{SO}(3)$ for $i=1,2,$ and it holds $R_i = R_0 R'_i, i=1,2,$ where $R'_i$ is part of the pose of camera $i$ $g_i = (R_i,T'_i) ∈ \text{SE}(3)$ and $R_0 ∈ \text{SO}(3)$ such that $R_0(T'_2-T'_1) = e_z$ [TronDaniilidis2017].

    source

    Literature

    diff --git a/previews/PR644/manifolds/euclidean.html b/previews/PR644/manifolds/euclidean.html new file mode 100644 index 0000000000..bc33a079ef --- /dev/null +++ b/previews/PR644/manifolds/euclidean.html @@ -0,0 +1,3 @@ + +Euclidean · Manifolds.jl

    Euclidean space

    The Euclidean space $ℝ^n$ is a simple model space, since it has curvature constantly zero everywhere; hence, nearly all operations simplify. The easiest way to generate an Euclidean space is to use a field, i.e. AbstractNumbers, e.g. to create the $ℝ^n$ or $ℝ^{n\times n}$ you can simply type M = ℝ^n or ℝ^(n,n), respectively.

    Manifolds.EuclideanType
    Euclidean{T<:Tuple,𝔽} <: AbstractManifold{𝔽}

    Euclidean vector space.

    Constructor

    Euclidean(n)

    Generate the $n$-dimensional vector space $ℝ^n$.

    Euclidean(n₁,n₂,...,nᵢ; field=ℝ)
    +𝔽^(n₁,n₂,...,nᵢ) = Euclidean(n₁,n₂,...,nᵢ; field=𝔽)

    Generate the vector space of $k = n_1 \cdot n_2 \cdot … \cdot n_i$ values, i.e. the manifold $𝔽^{n_1, n_2, …, n_i}$, $𝔽\in\{ℝ,ℂ\}$, whose elements are interpreted as $n_1 × n_2 × … × n_i$ arrays. For $i=2$ we obtain a matrix space. The default field=ℝ can also be set to field=ℂ. The dimension of this space is $k \dim_ℝ 𝔽$, where $\dim_ℝ 𝔽$ is the real_dimension of the field $𝔽$.

    Euclidean(; field=ℝ)

    Generate the 1D Euclidean manifold for an -, -valued real- or complex-valued immutable values (in contrast to 1-element arrays from the constructor above).

    source
    Base.expMethod
    exp(M::Euclidean, p, X)

    Compute the exponential map on the Euclidean manifold M from p in direction X, which in this case is just

    \[\exp_p X = p + X.\]

    source
    Base.logMethod
    log(M::Euclidean, p, q)

    Compute the logarithmic map on the Euclidean M from p to q, which in this case is just

    \[\log_p q = q-p.\]

    source
    LinearAlgebra.normMethod
    norm(M::Euclidean, p, X)

    Compute the norm of a tangent vector X at p on the Euclidean M, i.e. since every tangent space can be identified with M itself in this case, just the (Frobenius) norm of X.

    source
    ManifoldsBase.distanceMethod
    distance(M::Euclidean, p, q)

    Compute the Euclidean distance between two points on the Euclidean manifold M, i.e. for vectors it's just the norm of the difference, for matrices and higher order arrays, the matrix and ternsor Frobenius norm, respectively.

    source
    ManifoldsBase.embedMethod
    embed(M::Euclidean, p, X)

    Embed the tangent vector X at point p in M. Equivalent to an identity map.

    source
    ManifoldsBase.innerMethod
    inner(M::Euclidean, p, X, Y)

    Compute the inner product on the Euclidean M, which is just the inner product on the real-valued or complex valued vector space of arrays (or tensors) of size $n_1 × n_2 × … × n_i$, i.e.

    \[g_p(X,Y) = \sum_{k ∈ I} \overline{X}_{k} Y_{k},\]

    where $I$ is the set of vectors $k ∈ ℕ^i$, such that for all

    $i ≤ j ≤ i$ it holds $1 ≤ k_j ≤ n_j$ and $\overline{\cdot}$ denotes the complex conjugate.

    For the special case of $i ≤ 2$, i.e. matrices and vectors, this simplifies to

    \[g_p(X,Y) = X^{\mathrm{H}}Y,\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed.

    source
    ManifoldsBase.projectMethod
    project(M::Euclidean, p, X)

    Project an arbitrary vector X into the tangent space of a point p on the Euclidean M, which is just the identity, since any tangent space of M can be identified with all of M.

    source
    ManifoldsBase.vector_transport_toMethod
    vector_transport_to(M::Euclidean, p, X, q, ::AbstractVectorTransportMethod)

    Transport the vector X from the tangent space at p to the tangent space at q on the Euclidean M, which simplifies to the identity.

    source
    diff --git a/previews/PR644/manifolds/fixedrankmatrices.html b/previews/PR644/manifolds/fixedrankmatrices.html new file mode 100644 index 0000000000..455879a06c --- /dev/null +++ b/previews/PR644/manifolds/fixedrankmatrices.html @@ -0,0 +1,16 @@ + +Fixed-rank matrices · Manifolds.jl

    Fixed-rank matrices

    Manifolds.FixedRankMatricesType
    FixedRankMatrices{m,n,k,𝔽} <: AbstractDecoratorManifold{𝔽}

    The manifold of $m × n$ real-valued or complex-valued matrices of fixed rank $k$, i.e.

    \[\bigl\{ p ∈ 𝔽^{m × n}\ \big|\ \operatorname{rank}(p) = k\bigr\},\]

    where $𝔽 ∈ \{ℝ,ℂ\}$ and the rank is the number of linearly independent columns of a matrix.

    Representation with 3 matrix factors

    A point $p ∈ \mathcal M$ can be stored using unitary matrices $U ∈ 𝔽^{m × k}$, $V ∈ 𝔽^{n × k}$ as well as the $k$ singular values of $p = U_p S V_p^\mathrm{H}$, where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian. In other words, $U$ and $V$ are from the manifolds Stiefel(m,k,𝔽) and Stiefel(n,k,𝔽), respectively; see SVDMPoint for details.

    The tangent space $T_p \mathcal M$ at a point $p ∈ \mathcal M$ with $p=U_p S V_p^\mathrm{H}$ is given by

    \[T_p\mathcal M = \bigl\{ U_p M V_p^\mathrm{H} + U_X V_p^\mathrm{H} + U_p V_X^\mathrm{H} : + M ∈ 𝔽^{k × k}, + U_X ∈ 𝔽^{m × k}, + V_X ∈ 𝔽^{n × k} + \text{ s.t. } + U_p^\mathrm{H}U_X = 0_k, + V_p^\mathrm{H}V_X = 0_k +\bigr\},\]

    where $0_k$ is the $k × k$ zero matrix. See UMVTVector for details.

    The (default) metric of this manifold is obtained by restricting the metric on $ℝ^{m × n}$ to the tangent bundle[Vandereycken2013].

    Constructor

    FixedRankMatrices(m, n, k[, field=ℝ])

    Generate the manifold of m-by-n (field-valued) matrices of rank k.

    source
    Manifolds.SVDMPointType
    SVDMPoint <: AbstractManifoldPoint

    A point on a certain manifold, where the data is stored in a svd like fashion, i.e. in the form $USV^\mathrm{H}$, where this structure stores $U$, $S$ and $V^\mathrm{H}$. The storage might also be shortened to just $k$ singular values and accordingly shortened $U$ (columns) and $V^\mathrm{H}$ (rows).

    Constructors

    • SVDMPoint(A) for a matrix A, stores its svd factors (i.e. implicitly $k=\min\{m,n\}$)
    • SVDMPoint(S) for an SVD object, stores its svd factors (i.e. implicitly $k=\min\{m,n\}$)
    • SVDMPoint(U,S,Vt) for the svd factors to initialize the SVDMPoint(i.e. implicitlyk=\min\{m,n\}`)
    • SVDMPoint(A,k) for a matrix A, stores its svd factors shortened to the best rank $k$ approximation
    • SVDMPoint(S,k) for an SVD object, stores its svd factors shortened to the best rank $k$ approximation
    • SVDMPoint(U,S,Vt,k) for the svd factors to initialize the SVDMPoint, stores its svd factors shortened to the best rank $k$ approximation
    source
    Manifolds.UMVTVectorType
    UMVTVector <: TVector

    A tangent vector that can be described as a product $U_p M V_p^\mathrm{H} + U_X V_p^\mathrm{H} + U_p V_X^\mathrm{H}$, where $X = U_X S V_X^\mathrm{H}$ is its base point, see for example FixedRankMatrices.

    The base point $p$ is required for example embedding this point, but it is not stored. The fields of thie tangent vector are U for $U_X$, M and Vt to store $V_X^\mathrm{H}$

    Constructors

    • UMVTVector(U,M,Vt) store umv factors to initialize the UMVTVector
    • UMVTVector(U,M,Vt,k) store the umv factors after shortening them down to inner dimensions k.
    source
    Base.randMethod
    Random.rand(M::FixedRankMatrices; vector_at=nothing, kwargs...)

    If vector_at is nothing, return a random point on the FixedRankMatrices manifold. The orthogonal matrices are sampled from the Stiefel manifold and the singular values are sampled uniformly at random.

    If vector_at is not nothing, generate a random tangent vector in the tangent space of the point vector_at on the FixedRankMatrices manifold M.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::FixedRankMatrices{m,n,k}, p; kwargs...)

    Check whether the matrix or SVDMPoint x ids a valid point on the FixedRankMatrices{m,n,k,𝔽} M, i.e. is an m-byn matrix of rank k. For the SVDMPoint the internal representation also has to have the right shape, i.e. p.U and p.Vt have to be unitary. The keyword arguments are passed to the rank function that verifies the rank of p.

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M:FixedRankMatrices{m,n,k}, p, X; kwargs...)

    Check whether the tangent UMVTVector X is from the tangent space of the SVDMPoint p on the FixedRankMatrices M, i.e. that v.U and v.Vt are (columnwise) orthogonal to x.U and x.Vt, respectively, and its dimensions are consistent with p and X.M, i.e. correspond to m-by-n matrices of rank k.

    source
    ManifoldsBase.embedMethod
    embed(M::FixedRankMatrices, p, X)

    Embed the tangent vector X at point p in M from its UMVTVector representation into the set of $m×n$ matrices.

    The formula reads

    \[U_pMV_p^{\mathrm{H}} + U_XV_p^{\mathrm{H}} + U_pV_X^{\mathrm{H}}\]

    source
    ManifoldsBase.embedMethod
    embed(::FixedRankMatrices, p::SVDMPoint)

    Embed the point p from its SVDMPoint representation into the set of $m×n$ matrices by computing $USV^{\mathrm{H}}$.

    source
    ManifoldsBase.innerMethod
    inner(M::FixedRankMatrices, p::SVDMPoint, X::UMVTVector, Y::UMVTVector)

    Compute the inner product of X and Y in the tangent space of p on the FixedRankMatrices M, which is inherited from the embedding, i.e. can be computed using dot on the elements (U, Vt, M) of X and Y.

    source
    ManifoldsBase.retractMethod
    retract(M, p, X, ::PolarRetraction)

    Compute an SVD-based retraction on the FixedRankMatrices M by computing

    \[ q = U_kS_kV_k^\mathrm{H},\]

    where $U_k S_k V_k^\mathrm{H}$ is the shortened singular value decomposition $USV^\mathrm{H}=p+X$, in the sense that $S_k$ is the diagonal matrix of size $k × k$ with the $k$ largest singular values and $U$ and $V$ are shortened accordingly.

    source

    Literature

    [Ngu23]
    +
    +
    D. Nguyen. Operator-Valued Formulas for Riemannian Gradient and Hessian and Families of Tractable Metrics in Riemannian Optimization. Journal of Optimization Theory and Applications 198, 135–164 (2023).
    +
    [Van13]
    +
    +
    B. Vandereycken. Low-rank matrix completion by Riemannian optimization. SIAM Journal on Optimization 23, 1214–1236 (2013-01).
    +
    +
    • Vandereycken2013

      Bart Vandereycken: "Low-rank matrix completion by Riemannian Optimization, SIAM Journal on Optiomoization, 23(2), pp. 1214–1236, 2013. doi: 10.1137/110845768, arXiv: 1209.3834.

    • HosseiniUschmajew2017

      S. Hosseini and A. Uschmajew, “A Riemannian Gradient Sampling Algorithm for Nonsmooth Optimization on Manifolds,” SIAM J. Optim., vol. 27, no. 1, pp. 173–189, Jan. 2017, doi: 10.1137/16M1069298.

    diff --git a/previews/PR644/manifolds/flag.html b/previews/PR644/manifolds/flag.html new file mode 100644 index 0000000000..4e4de27dd7 --- /dev/null +++ b/previews/PR644/manifolds/flag.html @@ -0,0 +1,19 @@ + +Flag · Manifolds.jl

    Flag manifold

    Manifolds.FlagType
    Flag{N,d} <: AbstractDecoratorManifold{ℝ}

    Flag manifold of $d$ subspaces of $ℝ^N$[YeWongLim2022]. By default the manifold uses the Stiefel coordinates representation, embedding it in the Stiefel manifold. The other available representation is an embedding in OrthogonalMatrices. It can be utilized using OrthogonalPoint and OrthogonalTVector wrappers.

    Tangent space is represented in the block-skew-symmetric form.

    Constructor

    Flag(N, n1, n2, ..., nd)

    Generate the manifold $\operatorname{Flag}(n_1, n_2, ..., n_d; N)$ of subspaces

    \[𝕍_1 ⊆ 𝕍_2 ⊆ ⋯ ⊆ V_d, \quad \operatorname{dim}(𝕍_i) = n_i\]

    where $𝕍_i$ for $i ∈ 1, 2, …, d$ are subspaces of $ℝ^N$ of dimension $\operatorname{dim} 𝕍_i = n_i$.

    source
    Manifolds.OrthogonalPointType
    OrthogonalPoint <: AbstractManifoldPoint

    A type to represent points on a manifold Flag in the orthogonal coordinates representation, i.e. a rotation matrix.

    source
    Manifolds.ZeroTupleType
    ZeroTuple

    Internal structure for representing shape of a Flag manifold. Behaves like a normal tuple, except at index zero returns value 0.

    source
    Base.convertMethod
    convert(::Type{AbstractMatrix}, M::Flag, p::OrthogonalPoint, X::OrthogonalTVector)

    Convert tangent vector from Flag manifold M from orthogonal representation to Stiefel representation.

    source
    Base.convertMethod
    convert(::Type{AbstractMatrix}, M::Flag, p::OrthogonalPoint)

    Convert point p from Flag manifold M from orthogonal representation to Stiefel representation.

    source
    Base.convertMethod
    convert(::Type{OrthogonalPoint}, M::Flag, p::AbstractMatrix)

    Convert point p from Flag manifold M from Stiefel representation to orthogonal representation.

    source
    Base.convertMethod
    convert(::Type{OrthogonalTVector}, M::Flag, p::AbstractMatrix, X::AbstractMatrix)

    Convert tangent vector from Flag manifold M from Stiefel representation to orthogonal representation.

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::Flag)

    Return dimension of flag manifold $\operatorname{Flag}(n_1, n_2, ..., n_d; N)$. The formula reads $\sum_{i=1}^d (n_i-n_{i-1})(N-n_i)$.

    source

    The flag manifold represented as points on the Stiefel manifold

    ManifoldsBase.check_vectorMethod
    check_vector(M::Flag, p::AbstractMatrix, X::AbstractMatrix; kwargs... )

    Check whether X is a tangent vector to point p on the Flag manifold M $\operatorname{Flag}(n_1, n_2, ..., n_d; N)$ in the Stiefel representation, i.e. that X is a matrix of the form

    \[X = \begin{bmatrix} +0 & B_{1,2} & \cdots & B_{1,d} \\ +-B_{1,2}^\mathrm{T} & 0 & \cdots & B_{2,d} \\ +\vdots & \vdots & \ddots & \vdots \\ +-B_{1,d}^\mathrm{T} & -B_{2,d}^\mathrm{T} & \cdots & 0 \\ +-B_{1,d+1}^\mathrm{T} & -B_{2,d+1}^\mathrm{T} & \cdots & -B_{d,d+1}^\mathrm{T} +\end{bmatrix}\]

    where $B_{i,j} ∈ ℝ^{(n_i - n_{i-1}) × (n_j - n_{j-1})}$, for $1 ≤ i < j ≤ d+1$.

    source
    ManifoldsBase.projectMethod
    project(::Flag, p, X)

    Project vector X in the Euclidean embedding to the tangent space at point p on Flag manifold. The formula reads[YeWongLim2022]:

    \[Y_i = X_i - (p_i p_i^{\mathrm{T}}) X_i + \sum_{j \neq i} p_j X_j^{\mathrm{T}} p_i\]

    for $i$ from 1 to $d$ where the resulting vector is $Y = [Y_1, Y_2, …, Y_d]$ and $X = [X_1, X_2, …, X_d]$, $p = [p_1, p_2, …, p_d]$ are decompositions into basis vector matrices for consecutive subspaces of the flag.

    source
    ManifoldsBase.retractMethod
    retract(M::Flag, p, X, ::PolarRetraction)

    Compute the SVD-based retraction PolarRetraction on the Flag M. With $USV = p + X$ the retraction reads

    \[\operatorname{retr}_p X = UV^\mathrm{H},\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian.

    source

    The flag manifold represented as orthogonal matrices

    ManifoldsBase.check_vectorMethod
    check_vector(M::Flag, p::OrthogonalPoint, X::OrthogonalTVector; kwargs... )

    Check whether X is a tangent vector to point p on the Flag manifold M $\operatorname{Flag}(n_1, n_2, ..., n_d; N)$ in the orthogonal matrix representation, i.e. that X is block-skew-symmetric with zero diagonal:

    \[X = \begin{bmatrix} +0 & B_{1,2} & \cdots & B_{1,d+1} \\ +-B_{1,2}^\mathrm{T} & 0 & \cdots & B_{2,d+1} \\ +\vdots & \vdots & \ddots & \vdots \\ +-B_{1,d+1}^\mathrm{T} & -B_{2,d+1}^\mathrm{T} & \cdots & 0 +\end{bmatrix}\]

    where $B_{i,j} ∈ ℝ^{(n_i - n_{i-1}) × (n_j - n_{j-1})}$, for $1 ≤ i < j ≤ d+1$.

    source
    ManifoldsBase.projectMethod
    project(M::Flag, p::OrthogonalPoint, X::OrthogonalTVector)

    Project vector X to tangent space at point p from Flag manifold M $\operatorname{Flag}(n_1, n_2, ..., n_d; N)$, in the orthogonal matrix representation. It works by first projecting X to the space of SkewHermitianMatrices and then setting diagonal blocks to 0:

    \[X = \begin{bmatrix} +0 & B_{1,2} & \cdots & B_{1,d+1} \\ +-B_{1,2}^\mathrm{T} & 0 & \cdots & B_{2,d+1} \\ +\vdots & \vdots & \ddots & \vdots \\ +-B_{1,d+1}^\mathrm{T} & -B_{2,d+1}^\mathrm{T} & \cdots & 0 +\end{bmatrix}\]

    where $B_{i,j} ∈ ℝ^{(n_i - n_{i-1}) × (n_j - n_{j-1})}$, for $1 ≤ i < j ≤ d+1$.

    source
    ManifoldsBase.retractMethod
    retract(M::Flag, p::OrthogonalPoint, X::OrthogonalTVector, ::QRRetraction)

    Compute the QR retraction on the Flag in the orthogonal matrix representation as the first order approximation to the exponential map. Similar to QR retraction for [GeneralUnitaryMatrices].

    source
    diff --git a/previews/PR644/manifolds/generalizedgrassmann.html b/previews/PR644/manifolds/generalizedgrassmann.html new file mode 100644 index 0000000000..c6674f3b9f --- /dev/null +++ b/previews/PR644/manifolds/generalizedgrassmann.html @@ -0,0 +1,11 @@ + +Generalized Grassmann · Manifolds.jl

    Generalized Grassmann

    Manifolds.GeneralizedGrassmannType
    GeneralizedGrassmann{n,k,𝔽} <: AbstractDecoratorManifold{𝔽}

    The generalized Grassmann manifold $\operatorname{Gr}(n,k,B)$ consists of all subspaces spanned by $k$ linear independent vectors $𝔽^n$, where $𝔽 ∈ \{ℝ, ℂ\}$ is either the real- (or complex-) valued vectors. This yields all $k$-dimensional subspaces of $ℝ^n$ for the real-valued case and all $2k$-dimensional subspaces of $ℂ^n$ for the second.

    The manifold can be represented as

    \[\operatorname{Gr}(n, k, B) := \bigl\{ \operatorname{span}(p)\ \big|\ p ∈ 𝔽^{n × k}, p^\mathrm{H}Bp = I_k\},\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate (or Hermitian) transpose and $I_k$ is the $k × k$ identity matrix. This means, that the columns of $p$ form an unitary basis of the subspace with respect to the scaled inner product, that is a point on $\operatorname{Gr}(n,k,B)$, and hence the subspace can actually be represented by a whole equivalence class of representers. For $B=I_n$ this simplifies to the Grassmann manifold.

    The tangent space at a point (subspace) $p$ is given by

    \[T_x\mathrm{Gr}(n,k,B) = \bigl\{ +X ∈ 𝔽^{n × k} : +X^{\mathrm{H}}Bp + p^{\mathrm{H}}BX = 0_{k} \bigr\},\]

    where $0_{k}$ denotes the $k × k$ zero matrix.

    Note that a point $p ∈ \operatorname{Gr}(n,k,B)$ might be represented by different matrices (i.e. matrices with $B$-unitary column vectors that span the same subspace). Different representations of $p$ also lead to different representation matrices for the tangent space $T_p\mathrm{Gr}(n,k,B)$

    The manifold is named after Hermann G. Graßmann (1809-1877).

    Constructor

    GeneralizedGrassmann(n, k, B=I_n, field=ℝ)

    Generate the (real-valued) Generalized Grassmann manifold of $n\times k$ dimensional orthonormal matrices with scalar product B.

    source
    Base.expMethod
    exp(M::GeneralizedGrassmann, p, X)

    Compute the exponential map on the GeneralizedGrassmann M$= \mathrm{Gr}(n,k,B)$ starting in p with tangent vector (direction) X. Let $X^{\mathrm{H}}BX = USV$ denote the SVD decomposition of $X^{\mathrm{H}}BX$. Then the exponential map is written using

    \[\exp_p X = p V\cos(S)V^\mathrm{H} + U\sin(S)V^\mathrm{H},\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian and the cosine and sine are applied element wise to the diagonal entries of $S$.

    source
    Base.logMethod
    log(M::GeneralizedGrassmann, p, q)

    Compute the logarithmic map on the GeneralizedGrassmann M$ = \mathcal M=\mathrm{Gr}(n,k,B)$, i.e. the tangent vector X whose corresponding geodesic starting from p reaches q after time 1 on M. The formula reads

    \[\log_p q = V\cdot \operatorname{atan}(S) \cdot U^\mathrm{H},\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. The matrices $U$ and $V$ are the unitary matrices, and $S$ is the diagonal matrix containing the singular values of the SVD-decomposition

    \[USV = (q^\mathrm{H}Bp)^{-1} ( q^\mathrm{H} - q^\mathrm{H}Bpp^\mathrm{H}).\]

    In this formula the $\operatorname{atan}$ is meant elementwise.

    source
    Base.randMethod
    rand(::GeneralizedGrassmann; vector_at=nothing, σ::Real=1.0)

    When vector_at is nothing, return a random (Gaussian) point p on the GeneralizedGrassmann manifold M by generating a (Gaussian) matrix with standard deviation σ and return the (generalized) orthogonalized version, i.e. return the projection onto the manifold of the Q component of the QR decomposition of the random matrix of size $n×k$.

    When vector_at is not nothing, return a (Gaussian) random vector from the tangent space $T_{vector\_at}\mathrm{St}(n,k)$ with mean zero and standard deviation σ by projecting a random Matrix onto the tangent vector at vector_at.

    source
    ManifoldsBase.change_metricMethod
    change_metric(M::GeneralizedGrassmann, ::EuclideanMetric, p X)

    Change X to the corresponding vector with respect to the metric of the GeneralizedGrassmann M, i.e. let $B=LL'$ be the Cholesky decomposition of the matrix M.B, then the corresponding vector is $L\X$.

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::GeneralizedGrassmann, ::EuclideanMetric, p, X)

    Change X to the corresponding representer of a cotangent vector at p with respect to the scaled metric of the GeneralizedGrassmann M, i.e, since

    \[g_p(X,Y) = \operatorname{tr}(Y^{\mathrm{H}}BZ) = \operatorname{tr}(X^{\mathrm{H}}Z) = ⟨X,Z⟩\]

    has to hold for all $Z$, where the repreenter X is given, the resulting representer with respect to the metric on the GeneralizedGrassmann is given by $Y = B^{-1}X$.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::GeneralizedGrassmann{n,k,𝔽}, p)

    Check whether p is representing a point on the GeneralizedGrassmann M, i.e. its a n-by-k matrix of unitary column vectors with respect to the B inner prudct and of correct eltype with respect to 𝔽.

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::GeneralizedGrassmann{n,k,𝔽}, p, X; kwargs...)

    Check whether X is a tangent vector in the tangent space of p on the GeneralizedGrassmann M, i.e. that X is of size and type as well as that

    \[ p^{\mathrm{H}}BX + \overline{X^{\mathrm{H}}Bp} = 0_k,\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, $\overline{\cdot}$ the (elementwise) complex conjugate, and $0_k$ denotes the $k × k$ zero natrix.

    source
    ManifoldsBase.distanceMethod
    distance(M::GeneralizedGrassmann, p, q)

    Compute the Riemannian distance on GeneralizedGrassmann manifold M$= \mathrm{Gr}(n,k,B)$.

    The distance is given by

    \[d_{\mathrm{Gr}(n,k,B)}(p,q) = \operatorname{norm}(\log_p(q)).\]

    source
    ManifoldsBase.innerMethod
    inner(M::GeneralizedGrassmann, p, X, Y)

    Compute the inner product for two tangent vectors X, Y from the tangent space of p on the GeneralizedGrassmann manifold M. The formula reads

    \[g_p(X,Y) = \operatorname{tr}(X^{\mathrm{H}}BY),\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian.

    source
    ManifoldsBase.projectMethod
    project(M::GeneralizedGrassmann, p, X)

    Project the n-by-k X onto the tangent space of p on the GeneralizedGrassmann M, which is computed by

    \[\operatorname{proj_p}(X) = X - pp^{\mathrm{H}}B^\mathrm{T}X,\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian and $\cdot^{\mathrm{T}}$ the transpose.

    source
    ManifoldsBase.projectMethod
    project(M::GeneralizedGrassmann, p)

    Project p from the embedding onto the GeneralizedGrassmann M, i.e. compute q as the polar decomposition of $p$ such that $q^{\mathrm{H}}Bq$ is the identity, where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose.

    source
    diff --git a/previews/PR644/manifolds/generalizedstiefel.html b/previews/PR644/manifolds/generalizedstiefel.html new file mode 100644 index 0000000000..4f3fbb078d --- /dev/null +++ b/previews/PR644/manifolds/generalizedstiefel.html @@ -0,0 +1,8 @@ + +Generalized Stiefel · Manifolds.jl

    Generalized Stiefel

    Manifolds.GeneralizedStiefelType
    GeneralizedStiefel{n,k,𝔽,B} <: AbstractDecoratorManifold{𝔽}

    The Generalized Stiefel manifold consists of all $n\times k$, $n\geq k$ orthonormal matrices w.r.t. an arbitrary scalar product with symmetric positive definite matrix $B\in R^{n × n}$, i.e.

    \[\operatorname{St}(n,k,B) = \bigl\{ p \in \mathbb F^{n × k}\ \big|\ p^{\mathrm{H}} B p = I_k \bigr\},\]

    where $𝔽 ∈ \{ℝ, ℂ\}$, $\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and $I_k \in \mathbb R^{k × k}$ denotes the $k × k$ identity matrix.

    In the case $B=I_k$ one gets the usual Stiefel manifold.

    The tangent space at a point $p\in\mathcal M=\operatorname{St}(n,k,B)$ is given by

    \[T_p\mathcal M = \{ X \in 𝔽^{n × k} : p^{\mathrm{H}}BX + X^{\mathrm{H}}Bp=0_n\},\]

    where $0_k$ is the $k × k$ zero matrix.

    This manifold is modeled as an embedded manifold to the Euclidean, i.e. several functions like the zero_vector are inherited from the embedding.

    The manifold is named after Eduard L. Stiefel (1909–1978).

    Constructor

    GeneralizedStiefel(n, k, B=I_n, F=ℝ)

    Generate the (real-valued) Generalized Stiefel manifold of $n\times k$ dimensional orthonormal matrices with scalar product B.

    source
    Base.randMethod
    rand(::GeneralizedStiefel; vector_at=nothing, σ::Real=1.0)

    When vector_at is nothing, return a random (Gaussian) point p on the GeneralizedStiefel manifold M by generating a (Gaussian) matrix with standard deviation σ and return the (generalized) orthogonalized version, i.e. return the projection onto the manifold of the Q component of the QR decomposition of the random matrix of size $n×k$.

    When vector_at is not nothing, return a (Gaussian) random vector from the tangent space $T_{vector\_at}\mathrm{St}(n,k)$ with mean zero and standard deviation σ by projecting a random Matrix onto the tangent vector at vector_at.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::GeneralizedStiefel, p; kwargs...)

    Check whether p is a valid point on the GeneralizedStiefel M=$\operatorname{St}(n,k,B)$, i.e. that it has the right AbstractNumbers type and $x^{\mathrm{H}}Bx$ is (approximately) the identity, where $\cdot^{\mathrm{H}}$ is the complex conjugate transpose. The settings for approximately can be set with kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::GeneralizedStiefel, p, X; kwargs...)

    Check whether X is a valid tangent vector at p on the GeneralizedStiefel M=$\operatorname{St}(n,k,B)$, i.e. the AbstractNumbers fits, p is a valid point on M and it (approximately) holds that $p^{\mathrm{H}}BX + \overline{X^{\mathrm{H}}Bp} = 0$, where kwargs... is passed to the isapprox.

    source
    ManifoldsBase.innerMethod
    inner(M::GeneralizedStiefel, p, X, Y)

    Compute the inner product for two tangent vectors X, Y from the tangent space of p on the GeneralizedStiefel manifold M. The formula reads

    \[(X, Y)_p = \operatorname{trace}(v^{\mathrm{H}}Bw),\]

    i.e. the metric induced by the scalar product B from the embedding, restricted to the tangent space.

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::GeneralizedStiefel)

    Return the dimension of the GeneralizedStiefel manifold M=$\operatorname{St}(n,k,B,𝔽)$. The dimension is given by

    \[\begin{aligned} +\dim \mathrm{St}(n, k, B, ℝ) &= nk - \frac{1}{2}k(k+1) \\ +\dim \mathrm{St}(n, k, B, ℂ) &= 2nk - k^2\\ +\dim \mathrm{St}(n, k, B, ℍ) &= 4nk - k(2k-1) +\end{aligned}\]

    source
    ManifoldsBase.projectMethod
    project(M:GeneralizedStiefel, p, X)

    Project X onto the tangent space of p to the GeneralizedStiefel manifold M. The formula reads

    \[\operatorname{proj}_{\operatorname{St}(n,k)}(p,X) = X - p\operatorname{Sym}(p^{\mathrm{H}}BX),\]

    where $\operatorname{Sym}(y)$ is the symmetrization of $y$, e.g. by $\operatorname{Sym}(y) = \frac{y^{\mathrm{H}}+y}{2}$.

    source
    ManifoldsBase.projectMethod
    project(M::GeneralizedStiefel,p)

    Project p from the embedding onto the GeneralizedStiefel M, i.e. compute q as the polar decomposition of $p$ such that $q^{\mathrm{H}}Bq$ is the identity, where $\cdot^{\mathrm{H}}$ denotes the hermitian, i.e. complex conjugate transposed.

    source
    ManifoldsBase.retractMethod
    retract(M::GeneralizedStiefel, p, X)
    +retract(M::GeneralizedStiefel, p, X, ::PolarRetraction)
    +retract(M::GeneralizedStiefel, p, X, ::ProjectionRetraction)

    Compute the SVD-based retraction PolarRetraction on the GeneralizedStiefel manifold M, which in this case is the same as the projection based retraction employing the exponential map in the embedding and projecting the result back to the manifold.

    The default retraction for this manifold is the ProjectionRetraction.

    source
    diff --git a/previews/PR644/manifolds/generalunitary.html b/previews/PR644/manifolds/generalunitary.html new file mode 100644 index 0000000000..66dde2dbab --- /dev/null +++ b/previews/PR644/manifolds/generalunitary.html @@ -0,0 +1,37 @@ + +Orthogonal and Unitary Matrices · Manifolds.jl

    Orthogonal and Unitary matrices

    Both OrthogonalMatrices and UnitaryMatrices are quite similar, as are Rotations, as well as unitary matrices with determinant equal to one. So these share a {common implementation}(@ref generalunitarymatrices)

    Orthogonal Matrices

    Manifolds.OrthogonalMatricesType
     OrthogonalMatrices{n} = GeneralUnitaryMatrices{n,ℝ,AbsoluteDeterminantOneMatrices}

    The manifold of (real) orthogonal matrices $\mathrm{O}(n)$.

    OrthogonalMatrices(n)
    source

    Unitary Matrices

    Manifolds.UnitaryMatricesType
    const UnitaryMatrices{n,𝔽} = AbstarctUnitaryMatrices{n,𝔽,AbsoluteDeterminantOneMatrices}

    The manifold $U(n,𝔽)$ of $n×n$ complex matrices (when 𝔽=ℂ) or quaternionic matrices (when 𝔽=ℍ) such that

    $p^{\mathrm{H}}p = \mathrm{I}_n,$

    where $\mathrm{I}_n$ is the $n×n$ identity matrix. Such matrices p have a property that $\lVert \det(p) \rVert = 1$.

    The tangent spaces are given by

    \[ T_pU(n) \coloneqq \bigl\{ + X \big| pY \text{ where } Y \text{ is skew symmetric, i. e. } Y = -Y^{\mathrm{H}} + \bigr\}\]

    But note that tangent vectors are represented in the Lie algebra, i.e. just using $Y$ in the representation above.

    Constructor

    UnitaryMatrices(n, 𝔽::AbstractNumbers=ℂ)

    see also OrthogonalMatrices for the real valued case.

    source

    Common functions

    Manifolds.AbsoluteDeterminantOneMatricesType
    AbsoluteDeterminantOneMatrices <: AbstractMatrixType

    A type to indicate that we require (orthogonal / unitary) matrices with normed determinant, i.e. that the absolute value of the determinant is 1.

    source
    Manifolds.GeneralUnitaryMatricesType
    GeneralUnitaryMatrices{n,𝔽,S<:AbstractMatrixType} <: AbstractDecoratorManifold

    A common parametric type for matrices with a unitary property of size $n×n$ over the field $\mathbb F$ which additionally have the AbstractMatrixType, e.g. are DeterminantOneMatrices.

    source
    Base.expMethod
    exp(M::Rotations, p, X)
    +exp(M::OrthogonalMatrices, p, X)
    +exp(M::UnitaryMatrices, p, X)

    Compute the exponential map, that is, since $X$ is represented in the Lie algebra,

    exp_p(X) = p\mathrm{e}^X

    For different sizes, like $n=2,3,4$ there is specialised implementations

    The algorithm used is a more numerically stable form of those proposed in [Gallier2002] and [Andrica2013].

    source
    Base.logMethod
    log(M::Rotations, p, X)
    +log(M::OrthogonalMatrices, p, X)
    +log(M::UnitaryMatrices, p, X)

    Compute the logarithmic map, that is, since the resulting $X$ is represented in the Lie algebra,

    log_p q = \log(p^{\mathrm{H}q)

    which is projected onto the skew symmetric matrices for numerical stability.

    source
    Base.logMethod
    log(M::Rotations, p, q)

    Compute the logarithmic map on the Rotations manifold M which is given by

    \[\log_p q = \operatorname{log}(p^{\mathrm{T}}q)\]

    where $\operatorname{Log}$ denotes the matrix logarithm. For numerical stability, the result is projected onto the set of skew symmetric matrices.

    For antipodal rotations the function returns deterministically one of the tangent vectors that point at q.

    source
    Manifolds.cos_angles_4d_rotation_matrixMethod
    cos_angles_4d_rotation_matrix(R)

    4D rotations can be described by two orthogonal planes that are unchanged by the action of the rotation (vectors within a plane rotate only within the plane). The cosines of the two angles $α,β$ of rotation about these planes may be obtained from the distinct real parts of the eigenvalues of the rotation matrix. This function computes these more efficiently by solving the system

    \[\begin{aligned} +\cos α + \cos β &= \frac{1}{2} \operatorname{tr}(R)\\ +\cos α \cos β &= \frac{1}{8} \operatorname{tr}(R)^2 + - \frac{1}{16} \operatorname{tr}((R - R^T)^2) - 1. +\end{aligned}\]

    By convention, the returned values are sorted in decreasing order. See also angles_4d_skew_sym_matrix.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::Rotations, p; kwargs...)

    Check whether p is a valid point on the UnitaryMatrices M, i.e. that $p$ has an determinante of absolute value one, i.e. that $p^{\mathrm{H}}p$

    The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.check_pointMethod
    check_point(M::UnitaryMatrices, p; kwargs...)
    +check_point(M::OrthogonalMatrices, p; kwargs...)
    +check_point(M::GeneralUnitaryMatrices{n,𝔽}, p; kwargs...)

    Check whether p is a valid point on the UnitaryMatrices or [OrthogonalMatrices] M, i.e. that $p$ has an determinante of absolute value one

    The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::UnitaryMatrices{n}, p, X; kwargs... )
    +check_vector(M::OrthogonalMatrices{n}, p, X; kwargs... )
    +check_vector(M::Rotations{n}, p, X; kwargs... )
    +check_vector(M::GeneralUnitaryMatrices{n,𝔽}, p, X; kwargs... )

    Check whether X is a tangent vector to p on the UnitaryMatrices space M, i.e. after check_point(M,p), X has to be skew symmetric (Hermitian) and orthogonal to p.

    The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.embedMethod
    embed(M::GeneralUnitaryMatrices{n,𝔽}, p, X)

    Embed the tangent vector X at point p in M from its Lie algebra representation (set of skew matrices) into the Riemannian submanifold representation

    The formula reads

    \[X_{\text{embedded}} = p * X\]

    source
    ManifoldsBase.get_coordinatesMethod
    get_coordinates(M::Rotations, p, X)
    +get_coordinates(M::OrthogonalMatrices, p, X)
    +get_coordinates(M::UnitaryMatrices, p, X)

    Extract the unique tangent vector components $X^i$ at point p on Rotations $\mathrm{SO}(n)$ from the matrix representation X of the tangent vector.

    The basis on the Lie algebra $𝔰𝔬(n)$ is chosen such that for $\mathrm{SO}(2)$, $X^1 = θ = X_{21}$ is the angle of rotation, and for $\mathrm{SO}(3)$, $(X^1, X^2, X^3) = (X_{32}, X_{13}, X_{21}) = θ u$ is the angular velocity and axis-angle representation, where $u$ is the unit vector along the axis of rotation.

    For $\mathrm{SO}(n)$ where $n ≥ 4$, the additional elements of $X^i$ are $X^{j (j - 3)/2 + k + 1} = X_{jk}$, for $j ∈ [4,n], k ∈ [1,j)$.

    source
    ManifoldsBase.get_embeddingMethod
    get_embedding(M::OrthogonalMatrices{n})
    +get_embedding(M::Rotations{n})
    +get_embedding(M::UnitaryMatrices{n})

    Return the embedding, i.e. The $\mathbb F^{n×n}$, where $\mathbb F = \mathbb R$ for the first two and $\mathbb F = \mathbb C$ for the unitary matrices.

    source
    ManifoldsBase.get_vectorMethod
    get_vector(M::OrthogonalMatrices, p, Xⁱ, B::DefaultOrthogonalBasis)
    +get_vector(M::Rotations, p, Xⁱ, B::DefaultOrthogonalBasis)

    Convert the unique tangent vector components Xⁱ at point p on Rotations or OrthogonalMatrices to the matrix representation $X$ of the tangent vector. See get_coordinates for the conventions used.

    source
    ManifoldsBase.injectivity_radiusMethod
    injectivity_radius(G::GeneraliUnitaryMatrices)

    Return the injectivity radius for general unitary matrix manifolds, which is[1]

    \[ \operatorname{inj}_{\mathrm{U}(n)} = π.\]

    source
    ManifoldsBase.injectivity_radiusMethod
    injectivity_radius(G::GeneralUnitaryMatrices{n,ℂ,DeterminantOneMatrices})

    Return the injectivity radius for general complex unitary matrix manifolds, where the determinant is $+1$, which is[1]

    \[ \operatorname{inj}_{\mathrm{SU}(n)} = π \sqrt{2}.\]

    source
    ManifoldsBase.injectivity_radiusMethod
    injectivity_radius(G::SpecialOrthogonal)
    +injectivity_radius(G::Orthogonal)
    +injectivity_radius(M::Rotations)
    +injectivity_radius(M::Rotations, ::ExponentialRetraction)

    Return the radius of injectivity on the Rotations manifold M, which is $π\sqrt{2}$. [1]

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::GeneralUnitaryMatrices{n,ℂ,DeterminantOneMatrices})

    Return the dimension of the manifold of special unitary matrices.

    \[\dim_{\mathrm{SU}(n)} = n^2-1.\]

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::Rotations)
    +manifold_dimension(M::OrthogonalMatrices)

    Return the dimension of the manifold orthogonal matrices and of the manifold of rotations

    \[\dim_{\mathrm{O}(n)} = \dim_{\mathrm{SO}(n)} = \frac{n(n-1)}{2}.\]

    source
    ManifoldsBase.projectMethod
     project(M::OrthogonalMatrices{n}, p, X)
    + project(M::Rotations{n}, p, X)
    + project(M::UnitaryMatrices{n}, p, X)

    Orthogonally project the tangent vector $X ∈ 𝔽^{n × n}$, $\mathbb F ∈ \{\mathbb R, \mathbb C\}$ to the tangent space of M at p, and change the representer to use the corresponding Lie algebra, i.e. we compute

    \[ \operatorname{proj}_p(X) = \frac{p^{\mathrm{H}} X - (p^{\mathrm{H}} X)^{\mathrm{H}}}{2},\]

    source
    ManifoldsBase.projectMethod
     project(G::UnitaryMatrices{n}, p)
    + project(G::OrthogonalMatrices{n}, p)

    Project the point $p ∈ 𝔽^{n × n}$ to the nearest point in $\mathrm{U}(n,𝔽)=$Unitary(n,𝔽) under the Frobenius norm. If $p = U S V^\mathrm{H}$ is the singular value decomposition of $p$, then the projection is

    \[ \operatorname{proj}_{\mathrm{U}(n,𝔽)} \colon p ↦ U V^\mathrm{H}.\]

    source
    ManifoldsBase.retractMethod
    retract(M::Rotations, p, X, ::PolarRetraction)
    +retract(M::OrthogonalMatrices, p, X, ::PolarRetraction)

    Compute the SVD-based retraction on the Rotations and OrthogonalMatrices M from p in direction X (as an element of the Lie group) and is a second-order approximation of the exponential map. Let

    \[USV = p + pX\]

    be the singular value decomposition, then the formula reads

    \[\operatorname{retr}_p X = UV^\mathrm{T}.\]

    source
    ManifoldsBase.retractMethod
    retract(M::Rotations, p, X, ::QRRetraction)
    +retract(M::OrthogonalMatrices, p. X, ::QRRetraction)

    Compute the QR-based retraction on the Rotations and OrthogonalMatrices M from p in direction X (as an element of the Lie group), which is a first-order approximation of the exponential map.

    This is also the default retraction on these manifolds.

    source

    Footnotes and References

    • Gallier2002

      Gallier J.; Xu D.; Computing exponentials of skew-symmetric matrices and logarithms of orthogonal matrices. International Journal of Robotics and Automation (2002), 17(4), pp. 1-11. pdf.

    • Andrica2013

      Andrica D.; Rohan R.-A.; Computing the Rodrigues coefficients of the exponential map of the Lie groups of matrices. Balkan Journal of Geometry and Its Applications (2013), 18(2), pp. 1-2. pdf.

    • 1

      For a derivation of the injectivity radius, see sethaxen.com/blog/2023/02/the-injectivity-radii-of-the-unitary-groups/.

    • Rentmeesters2011

      Q. Rentmeesters, “A gradient method for geodesic data fitting on some symmetric Riemannian manifolds,” in 2011 50th IEEE Conference on Decision and Control and European Control Conference, Dec. 2011, pp. 7141–7146. doi: 10.1109/CDC.2011.6161280.

    diff --git a/previews/PR644/manifolds/graph.html b/previews/PR644/manifolds/graph.html new file mode 100644 index 0000000000..3b2a956732 --- /dev/null +++ b/previews/PR644/manifolds/graph.html @@ -0,0 +1,18 @@ + +Graph manifold · Manifolds.jl

    Graph manifold

    For a given graph $G(V,E)$ implemented using Graphs.jl, the GraphManifold models a PowerManifold either on the nodes or edges of the graph, depending on the GraphManifoldType. i.e., it's either a $\mathcal M^{\lvert V \rvert}$ for the case of a vertex manifold or a $\mathcal M^{\lvert E \rvert}$ for the case of a edge manifold.

    Example

    To make a graph manifold over $ℝ^2$ with three vertices and two edges, one can use

    using Manifolds
    +using Graphs
    +M = Euclidean(2)
    +p = [[1., 4.], [2., 5.], [3., 6.]]
    +q = [[4., 5.], [6., 7.], [8., 9.]]
    +x = [[6., 5.], [4., 3.], [2., 8.]]
    +G = SimpleGraph(3)
    +add_edge!(G, 1, 2)
    +add_edge!(G, 2, 3)
    +N = GraphManifold(G, M, VertexManifold())
    GraphManifold
    +Graph:
    + {3, 2} undirected simple Int64 graph
    +AbstractManifold on vertices:
    + Euclidean(2; field = ℝ)

    It supports all AbstractPowerManifold operations (it is based on NestedPowerRepresentation) and furthermore it is possible to compute a graph logarithm:

    incident_log(N, p)
    3-element Vector{Vector{Float64}}:
    + [1.0, 1.0]
    + [0.0, 0.0]
    + [-1.0, -1.0]

    Types and functions

    Manifolds.incident_logMethod
    incident_log(M::GraphManifold, x)

    Return the tangent vector on the (vertex) GraphManifold, where at each node the sum of the logs to incident nodes is computed. For a SimpleGraph, an egde is interpreted as double edge in the corresponding SimpleDiGraph

    If the internal graph is a SimpleWeightedGraph the weighted sum of the tangent vectors is computed.

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::GraphManifold, p, X; kwargs...)

    Check whether p is a valid point on the GraphManifold, and X it from its tangent space, i.e. its length equals the number of vertices (for VertexManifolds) or the number of edges (for EdgeManifolds) and that each element of X together with its corresponding entry of p passes the check_vector test for the base manifold M.manifold.

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(N::GraphManifold{G,𝔽,M,EdgeManifold})

    returns the manifold dimension of the GraphManifold N on the edges of a graph $G=(V,E)$, i.e.

    \[\dim(\mathcal N) = \lvert E \rvert \dim(\mathcal M),\]

    where $\mathcal M$ is the manifold of the data on the edges.

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(N::GraphManifold{G,𝔽,M,VertexManifold})

    returns the manifold dimension of the GraphManifold N on the vertices of a graph $G=(V,E)$, i.e.

    \[\dim(\mathcal N) = \lvert V \rvert \dim(\mathcal M),\]

    where $\mathcal M$ is the manifold of the data on the nodes.

    source
    diff --git a/previews/PR644/manifolds/grassmann.html b/previews/PR644/manifolds/grassmann.html new file mode 100644 index 0000000000..42a5a955c1 --- /dev/null +++ b/previews/PR644/manifolds/grassmann.html @@ -0,0 +1,26 @@ + +Grassmann · Manifolds.jl

    Grassmannian manifold

    Manifolds.GrassmannType
    Grassmann{n,k,𝔽} <: AbstractDecoratorManifold{𝔽}

    The Grassmann manifold $\operatorname{Gr}(n,k)$ consists of all subspaces spanned by $k$ linear independent vectors $𝔽^n$, where $𝔽 ∈ \{ℝ, ℂ\}$ is either the real- (or complex-) valued vectors. This yields all $k$-dimensional subspaces of $ℝ^n$ for the real-valued case and all $2k$-dimensional subspaces of $ℂ^n$ for the second.

    The manifold can be represented as

    \[\operatorname{Gr}(n,k) := \bigl\{ \operatorname{span}(p) : p ∈ 𝔽^{n × k}, p^\mathrm{H}p = I_k\},\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian and $I_k$ is the $k × k$ identity matrix. This means, that the columns of $p$ form an unitary basis of the subspace, that is a point on $\operatorname{Gr}(n,k)$, and hence the subspace can actually be represented by a whole equivalence class of representers. Another interpretation is, that

    \[\operatorname{Gr}(n,k) = \operatorname{St}(n,k) / \operatorname{O}(k),\]

    i.e the Grassmann manifold is the quotient of the Stiefel manifold and the orthogonal group $\operatorname{O}(k)$ of orthogonal $k × k$ matrices. Note that it doesn't matter whether we start from the Euclidean or canonical metric on the Stiefel manifold, the resulting quotient metric on Grassmann is the same.

    The tangent space at a point (subspace) $p$ is given by

    \[T_p\mathrm{Gr}(n,k) = \bigl\{ +X ∈ 𝔽^{n × k} : +X^{\mathrm{H}}p + p^{\mathrm{H}}X = 0_{k} \bigr\},\]

    where $0_k$ is the $k × k$ zero matrix.

    Note that a point $p ∈ \operatorname{Gr}(n,k)$ might be represented by different matrices (i.e. matrices with unitary column vectors that span the same subspace). Different representations of $p$ also lead to different representation matrices for the tangent space $T_p\mathrm{Gr}(n,k)$

    For a representation of points as orthogonal projectors. Here

    \[\operatorname{Gr}(n,k) := \bigl\{ p \in \mathbb R^{n×n} : p = p^˜\mathrm{T}, p^2 = p, \operatorname{rank}(p) = k\},\]

    with tangent space

    \[T_p\mathrm{Gr}(n,k) = \bigl\{ +X ∈ \mathbb R^{n × n} : X=X^{\mathrm{T}} \text{ and } X = pX+Xp \bigr\},\]

    see also ProjectorPoint and ProjectorTVector.

    The manifold is named after Hermann G. Graßmann (1809-1877).

    A good overview can be found in[BendokatZimmermannAbsil2020].

    Constructor

    Grassmann(n,k,field=ℝ)

    Generate the Grassmann manifold $\operatorname{Gr}(n,k)$, where the real-valued case field = ℝ is the default.

    source
    Base.convertMethod
    convert(::Type{ProjectorPoint}, p::AbstractMatrix)

    Convert a point p on Stiefel that also represents a point (i.e. subspace) on Grassmann to a projector representation of said subspace, i.e. compute the canonical_project! for

    \[ π^{\mathrm{SG}}(p) = pp^{\mathrm{T)}.\]

    source
    Base.convertMethod
    convert(::Type{ProjectorPoint}, ::Stiefelpoint)

    Convert a point p on Stiefel that also represents a point (i.e. subspace) on Grassmann to a projector representation of said subspace, i.e. compute the canonical_project! for

    \[ π^{\mathrm{SG}}(p) = pp^{\mathrm{T}}.\]

    source
    ManifoldsBase.change_metricMethod
    change_metric(M::Grassmann, ::EuclideanMetric, p X)

    Change X to the corresponding vector with respect to the metric of the Grassmann M, which is just the identity, since the manifold is isometrically embedded.

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::Grassmann, ::EuclideanMetric, p, X)

    Change X to the corresponding representer of a cotangent vector at p. Since the Grassmann manifold M, is isometrically embedded, this is the identity

    source

    The Grassmanian represented as points on the Stiefel manifold

    Manifolds.StiefelPointType
    StiefelPoint <: AbstractManifoldPoint

    A point on a Stiefel manifold. This point is mainly used for representing points on the Grassmann where this is also the default representation and hence equivalent to using AbstractMatrices thereon. they can also used be used as points on Stiefel.

    source
    Manifolds.StiefelTVectorType
    StiefelTVector <: TVector

    A tangent vector on the Grassmann manifold represented by a tangent vector from the tangent space of a corresponding point from the Stiefel manifold, see StiefelPoint. This is the default representation so is can be used interchangeably with just abstract matrices.

    source
    Base.expMethod
    exp(M::Grassmann, p, X)

    Compute the exponential map on the Grassmann M$= \mathrm{Gr}(n,k)$ starting in p with tangent vector (direction) X. Let $X = USV$ denote the SVD decomposition of $X$. Then the exponential map is written using

    \[z = p V\cos(S)V^\mathrm{H} + U\sin(S)V^\mathrm{H},\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian and the cosine and sine are applied element wise to the diagonal entries of $S$. A final QR decomposition $z=QR$ is performed for numerical stability reasons, yielding the result as

    \[\exp_p X = Q.\]

    source
    Base.logMethod
    log(M::Grassmann, p, q)

    Compute the logarithmic map on the Grassmann M$ = \mathcal M=\mathrm{Gr}(n,k)$, i.e. the tangent vector X whose corresponding geodesic starting from p reaches q after time 1 on M. The formula reads

    \[\log_p q = V\cdot \operatorname{atan}(S) \cdot U^\mathrm{H},\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. The matrices $U$ and $V$ are the unitary matrices, and $S$ is the diagonal matrix containing the singular values of the SVD-decomposition

    \[USV = (q^\mathrm{H}p)^{-1} ( q^\mathrm{H} - q^\mathrm{H}pp^\mathrm{H}).\]

    In this formula the $\operatorname{atan}$ is meant elementwise.

    source
    Base.randMethod
    rand(M::Grassmann; σ::Real=1.0, vector_at=nothing)

    When vector_at is nothing, return a random point p on Grassmann manifold M by generating a random (Gaussian) matrix with standard deviation σ in matching size, which is orthonormal.

    When vector_at is not nothing, return a (Gaussian) random vector from the tangent space $T_p\mathrm{Gr}(n,k)$ with mean zero and standard deviation σ by projecting a random Matrix onto the tangent space at vector_at.

    source
    ManifoldDiff.riemannian_HessianMethod
    riemannian_Hessian(M::Grassmann, p, G, H, X)

    The Riemannian Hessian can be computed by adopting Eq. (6.6) [Ngu23], where we use for the EuclideanMetric $α_0=α_1=1$ in their formula. Let $\nabla f(p)$ denote the Euclidean gradient G, $\nabla^2 f(p)[X]$ the Euclidean Hessian H. Then the formula reads

    \[ \operatorname{Hess}f(p)[X] + = + \operatorname{proj}_{T_p\mathcal M}\Bigl( + ∇^2f(p)[X] - X p^{\mathrm{H}}∇f(p) + \Bigr).\]

    Compared to Eq. (5.6) also the metric conversion simplifies to the identity.

    source
    Manifolds.uniform_distributionMethod
    uniform_distribution(M::Grassmann{n,k,ℝ}, p)

    Uniform distribution on given (real-valued) Grassmann M. Specifically, this is the normalized Haar measure on M. Generated points will be of similar type as p.

    The implementation is based on Section 2.5.1 in [Chikuse2003]; see also Theorem 2.2.2(iii) in [Chikuse2003].

    source
    ManifoldsBase.distanceMethod
    distance(M::Grassmann, p, q)

    Compute the Riemannian distance on Grassmann manifold M$= \mathrm{Gr}(n,k)$.

    The distance is given by

    \[d_{\mathrm{Gr}(n,k)}(p,q) = \operatorname{norm}(\log_p(q)).\]

    source
    ManifoldsBase.innerMethod
    inner(M::Grassmann, p, X, Y)

    Compute the inner product for two tangent vectors X, Y from the tangent space of p on the Grassmann manifold M. The formula reads

    \[g_p(X,Y) = \operatorname{tr}(X^{\mathrm{H}}Y),\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian.

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::Grassmann, p, q, ::PolarInverseRetraction)

    Compute the inverse retraction for the PolarRetraction, on the Grassmann manifold M, i.e.,

    \[\operatorname{retr}_p^{-1}q = q*(p^\mathrm{H}q)^{-1} - p,\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian.

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M, p, q, ::QRInverseRetraction)

    Compute the inverse retraction for the QRRetraction, on the Grassmann manifold M, i.e.,

    \[\operatorname{retr}_p^{-1}q = q(p^\mathrm{H}q)^{-1} - p,\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian.

    source
    ManifoldsBase.projectMethod
    project(M::Grassmann, p)

    Project p from the embedding onto the Grassmann M, i.e. compute q as the polar decomposition of $p$ such that $q^{\mathrm{H}}q$ is the identity, where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed.

    source
    ManifoldsBase.projectMethod
    project(M::Grassmann, p, X)

    Project the n-by-k X onto the tangent space of p on the Grassmann M, which is computed by

    \[\operatorname{proj_p}(X) = X - pp^{\mathrm{H}}X,\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian.

    source
    ManifoldsBase.retractMethod
    retract(M::Grassmann, p, X, ::PolarRetraction)

    Compute the SVD-based retraction PolarRetraction on the Grassmann M. With $USV = p + X$ the retraction reads

    \[\operatorname{retr}_p X = UV^\mathrm{H},\]

    where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian.

    source
    ManifoldsBase.retractMethod
    retract(M::Grassmann, p, X, ::QRRetraction )

    Compute the QR-based retraction QRRetraction on the Grassmann M. With $QR = p + X$ the retraction reads

    \[\operatorname{retr}_p X = QD,\]

    where D is a $m × n$ matrix with

    \[D = \operatorname{diag}\left( \operatorname{sgn}\left(R_{ii}+\frac{1}{2}\right)_{i=1}^n \right).\]

    source
    ManifoldsBase.vector_transport_toMethod
    vector_transport_to(M::Grassmann,p,X,q,::ProjectionTransport)

    compute the projection based transport on the Grassmann M by interpreting X from the tangent space at p as a point in the embedding and projecting it onto the tangent space at q.

    source
    ManifoldsBase.zero_vectorMethod
    zero_vector(M::Grassmann, p)

    Return the zero tangent vector from the tangent space at p on the Grassmann M, which is given by a zero matrix the same size as p.

    source

    The Grassmannian represented as projectors

    Manifolds.ProjectorPointType
    ProjectorPoint <: AbstractManifoldPoint

    A type to represent points on a manifold Grassmann that are orthogonal projectors, i.e. a matrix $p ∈ \mathbb F^{n,n}$ projecting onto a $k$-dimensional subspace.

    source
    Base.expMethod
    exp(M::Grassmann, p::ProjectorPoint, X::ProjectorTVector)

    Compute the exponential map on the Grassmann as

    \[ \exp_pX = \operatorname{Exp}([X,p])p\operatorname{Exp}(-[X,p]),\]

    where $\operatorname{Exp}$ denotes the matrix exponential and $[A,B] = AB-BA$ denotes the matrix commutator.

    For details, see Proposition 3.2 in [BendokatZimmermannAbsil2020].

    source
    Manifolds.horizontal_liftMethod
    horizontal_lift(N::Stiefel{n,k}, q, X::ProjectorTVector)

    Compute the horizontal lift of X from the tangent space at $p=π(q)$ on the Grassmann manifold, i.e.

    \[Y = Xq ∈ T_q\mathrm{St}(n,k)\]

    source
    ManifoldsBase.check_pointMethod
    check_point(::Grassmann{n,k}, p::ProjectorPoint; kwargs...)

    Check whether an orthogonal projector is a point from the Grassmann(n,k) manifold, i.e. the ProjectorPoint $p ∈ \mathbb F^{n×n}$, $\mathbb F ∈ \{\mathbb R, \mathbb C\}$ has to fulfill $p^{\mathrm{T}} = p$, $p^2=p$, and `\operatorname{rank} p = k.

    source
    ManifoldsBase.check_vectorMethod
    check_vector(::Grassmann{n,k,𝔽}, p::ProjectorPoint, X::ProjectorTVector; kwargs...) where {n,k,𝔽}

    Check whether the ProjectorTVector X is from the tangent space $T_p\operatorname{Gr}(n,k)$ at the ProjectorPoint p on the Grassmann manifold $\operatorname{Gr}(n,k)$. This means that X has to be symmetric and that

    \[Xp + pX = X\]

    must hold, where the kwargs can be used to check both for symmetrix of $X$` and this equality up to a certain tolerance.

    source
    ManifoldsBase.parallel_transport_directionMethod
    parallel_transport_direction(
    +    M::Grassmann,
    +    p::ProjectorPoint,
    +    X::ProjectorTVector,
    +    d::ProjectorTVector
    +)

    Compute the parallel transport of X from the tangent space at p into direction d, i.e. to $q=\exp_pd$. The formula is given in Proposition 3.5 of [BendokatZimmermannAbsil2020] as

    \[\mathcal{P}_{q ← p}(X) = \operatorname{Exp}([d,p])X\operatorname{Exp}(-[d,p]),\]

    where $\operatorname{Exp}$ denotes the matrix exponential and $[A,B] = AB-BA$ denotes the matrix commutator.

    source

    Literature

    [Ngu23]
    +
    +
    D. Nguyen. Operator-Valued Formulas for Riemannian Gradient and Hessian and Families of Tractable Metrics in Riemannian Optimization. Journal of Optimization Theory and Applications 198, 135–164 (2023).
    +
    +
    diff --git a/previews/PR644/manifolds/group.html b/previews/PR644/manifolds/group.html new file mode 100644 index 0000000000..2f2cd1a7a6 --- /dev/null +++ b/previews/PR644/manifolds/group.html @@ -0,0 +1,120 @@ + +Group manifold · Manifolds.jl

    Group manifolds and actions

    Lie groups, groups that are Riemannian manifolds with a smooth binary group operation AbstractGroupOperation, are implemented as AbstractDecoratorManifold and specifying the group operation using the IsGroupManifold or by decorating an existing manifold with a group operation using GroupManifold.

    The common addition and multiplication group operations of AdditionOperation and MultiplicationOperation are provided, though their behavior may be customized for a specific group.

    There are short introductions at the beginning of each subsection. They briefly mention what is available with links to more detailed descriptions.

    Contents

    Groups

    The following operations are available for group manifolds:

    • Identity: an allocation-free representation of the identity element of the group.
    • inv: get the inverse of a given element.
    • compose: compose two given elements of a group.
    • identity_element get the identity element of the group, in the representation used by other points from the group.

    Group manifold

    GroupManifold adds a group structure to the wrapped manifold. It does not affect metric (or connection) structure of the wrapped manifold, however it can to be further wrapped in MetricManifold to get invariant metrics, or in a ConnectionManifold to equip it with a Cartan-Schouten connection.

    Manifolds.AbstractGroupOperationType
    AbstractGroupOperation

    Abstract type for smooth binary operations $∘$ on elements of a Lie group $\mathcal{G}$:

    \[∘ : \mathcal{G} × \mathcal{G} → \mathcal{G}\]

    An operation can be either defined for a specific group manifold over number system 𝔽 or in general, by defining for an operation Op the following methods:

    identity_element!(::AbstractDecoratorManifold, q, q)
    +inv!(::AbstractDecoratorManifold, q, p)
    +_compose!(::AbstractDecoratorManifold, x, p, q)

    Note that a manifold is connected with an operation by wrapping it with a decorator, AbstractDecoratorManifold using the IsGroupManifold to specify the operation. For a concrete case the concrete wrapper GroupManifold can be used.

    source
    Manifolds.ForwardBackwardSwitchType
    struct ForwardBackwardSwitch <: AbstractDirectionSwitchType end

    Switch between forward and backward action, maintaining left/right direction.

    source
    Manifolds.GroupExponentialRetractionType
    GroupExponentialRetraction{D<:ActionDirection} <: AbstractRetractionMethod

    Retraction using the group exponential exp_lie "translated" to any point on the manifold.

    For more details, see retract.

    Constructor

    GroupExponentialRetraction(conv::ActionDirection = LeftForwardAction())
    source
    Manifolds.GroupLogarithmicInverseRetractionType
    GroupLogarithmicInverseRetraction{D<:ActionDirection} <: AbstractInverseRetractionMethod

    Retraction using the group logarithm log_lie "translated" to any point on the manifold.

    For more details, see inverse_retract.

    Constructor

    GroupLogarithmicInverseRetraction(conv::ActionDirection = LeftForwardAction())
    source
    Manifolds.IdentityType
    Identity{O<:AbstractGroupOperation}

    Represent the group identity element $e ∈ \mathcal{G}$ on a Lie group $\mathcal G$ with AbstractGroupOperation of type O.

    Similar to the philosophy that points are agnostic of their group at hand, the identity does not store the group g it belongs to. However it depends on the type of the AbstractGroupOperation used.

    See also identity_element on how to obtain the corresponding AbstractManifoldPoint or array representation.

    Constructors

    Identity(G::AbstractDecoratorManifold{𝔽})
    +Identity(o::O)
    +Identity(::Type{O})

    create the identity of the corresponding subtype O<:AbstractGroupOperation

    source
    Manifolds.IsGroupManifoldType
    IsGroupManifold{O<:AbstractGroupOperation} <: AbstractTrait

    A trait to declare an AbstractManifold as a manifold with group structure with operation of type O.

    Using this trait you can turn a manifold that you implement implictly into a Lie group. If you wish to decorate an existing manifold with one (or different) AbstractGroupActions, see GroupManifold.

    Constructor

    IsGroupManifold(op)
    source
    Manifolds.LeftBackwardActionType
    LeftBackwardAction()

    Left action of a group on a manifold. For an action $α: X × G → X$ it is characterized by

    \[α(α(x, h), g) = α(x, gh)\]

    for all $g, h ∈ G$ and $x ∈ X$.

    Note that a left action may still act from the right side in an expression.

    source
    Manifolds.LeftForwardActionType
    LeftForwardAction()

    Left action of a group on a manifold. For an action $α: G × X → X$ it is characterized by

    \[α(g, α(h, x)) = α(gh, x)\]

    for all $g, h ∈ G$ and $x ∈ X$.

    source
    Manifolds.LeftRightSwitchType
    struct LeftRightSwitch <: AbstractDirectionSwitchType end

    Switch between left and right action, maintaining forward/backward direction.

    source
    Manifolds.RightBackwardActionType
    RightBackwardAction()

    Right action of a group on a manifold. For an action $α: X × G → X$ it is characterized by

    \[α(α(x, h), g) = α(x, hg)\]

    for all $g, h ∈ G$ and $x ∈ X$.

    Note that a right action may still act from the left side in an expression.

    source
    Manifolds.RightForwardActionType
    RightForwardAction()

    Right action of a group on a manifold. For an action $α: G × X → X$ it is characterized by

    \[α(g, α(h, x)) = α(hg, x)\]

    for all $g, h ∈ G$ and $x ∈ X$.

    Note that a right action may still act from the left side in an expression.

    source
    Base.invMethod
    inv(G::AbstractDecoratorManifold, p)

    Inverse $p^{-1} ∈ \mathcal{G}$ of an element $p ∈ \mathcal{G}$, such that $p \circ p^{-1} = p^{-1} \circ p = e ∈ \mathcal{G}$, where $e$ is the Identity element of $\mathcal{G}$.

    source
    Manifolds.adjoint_actionMethod
    adjoint_action(G::AbstractDecoratorManifold, p, X)

    Adjoint action of the element p of the Lie group G on the element X of the corresponding Lie algebra.

    It is defined as the differential of the group authomorphism $Ψ_p(q) = pqp⁻¹$ at the identity of G.

    The formula reads

    \[\operatorname{Ad}_p(X) = dΨ_p(e)[X]\]

    where $e$ is the identity element of G.

    Note that the adjoint representation of a Lie group isn't generally faithful. Notably the adjoint representation of SO(2) is trivial.

    source
    Manifolds.composeMethod
    compose(G::AbstractDecoratorManifold, p, q)

    Compose elements $p,q ∈ \mathcal{G}$ using the group operation $p \circ q$.

    For implementing composition on a new group manifold, please overload _compose instead so that methods with Identity arguments are not ambiguous.

    source
    Manifolds.exp_lieMethod
    exp_lie(G, X)
    +exp_lie!(G, q, X)

    Compute the group exponential of the Lie algebra element X. It is equivalent to the exponential map defined by the CartanSchoutenMinus connection.

    Given an element $X ∈ 𝔤 = T_e \mathcal{G}$, where $e$ is the Identity element of the group $\mathcal{G}$, and $𝔤$ is its Lie algebra, the group exponential is the map

    \[\exp : 𝔤 → \mathcal{G},\]

    such that for $t,s ∈ ℝ$, $γ(t) = \exp (t X)$ defines a one-parameter subgroup with the following properties. Note that one-parameter subgroups are commutative (see [Suhubi2013], section 3.5), even if the Lie group itself is not commutative.

    \[\begin{aligned} +γ(t) &= γ(-t)^{-1}\\ +γ(t + s) &= γ(t) \circ γ(s) = γ(s) \circ γ(t)\\ +γ(0) &= e\\ +\lim_{t → 0} \frac{d}{dt} γ(t) &= X. +\end{aligned}\]

    Note

    In general, the group exponential map is distinct from the Riemannian exponential map exp.

    For example for the MultiplicationOperation and either Number or AbstractMatrix the Lie exponential is the numeric/matrix exponential.

    \[\exp X = \operatorname{Exp} X = \sum_{n=0}^∞ \frac{1}{n!} X^n.\]

    Since this function also depends on the group operation, make sure to implement the corresponding trait version exp_lie(::TraitList{<:IsGroupManifold}, G, X).

    source
    Manifolds.get_vector_lieMethod
    get_vector_lie(G::AbstractDecoratorManifold, a, B::AbstractBasis)

    Reconstruct a tangent vector from the Lie algebra of G from cooordinates a of a basis B. This is similar to calling get_vector at the p=Identity(G).

    source
    Manifolds.identity_elementMethod
    identity_element(G)

    Return a point representation of the Identity on the IsGroupManifold G. By default this representation is the default array or number representation. It should return the corresponding default representation of $e$ as a point on G if points are not represented by arrays.

    source
    Manifolds.inverse_translateMethod
    inverse_translate(G::AbstractDecoratorManifold, p, q, conv::ActionDirection=LeftForwardAction())

    Inverse translate group element $q$ by $p$ with the inverse translation $τ_p^{-1}$ with the specified convention, either left ($L_p^{-1}$) or right ($R_p^{-1}$), defined as

    \[\begin{aligned} +L_p^{-1} &: q ↦ p^{-1} \circ q\\ +R_p^{-1} &: q ↦ q \circ p^{-1}. +\end{aligned}\]

    source
    Manifolds.inverse_translate_diffMethod
    inverse_translate_diff(G::AbstractDecoratorManifold, p, q, X, conv::ActionDirection=LeftForwardAction())

    For group elements $p, q ∈ \mathcal{G}$ and tangent vector $X ∈ T_q \mathcal{G}$, compute the action on $X$ of the differential of the inverse translation $τ_p$ by $p$, with the specified left or right convention. The differential transports vectors:

    \[(\mathrm{d}τ_p^{-1})_q : T_q \mathcal{G} → T_{τ_p^{-1} q} \mathcal{G}\\\]

    source
    Manifolds.lie_bracketMethod
    lie_bracket(G::AbstractDecoratorManifold, X, Y)

    Lie bracket between elements X and Y of the Lie algebra corresponding to the Lie group G, cf. IsGroupManifold.

    This can be used to compute the adjoint representation of a Lie algebra. Note that this representation isn't generally faithful. Notably the adjoint representation of 𝔰𝔬(2) is trivial.

    source
    Manifolds.log_lieMethod
    log_lie(G, q)
    +log_lie!(G, X, q)

    Compute the Lie group logarithm of the Lie group element q. It is equivalent to the logarithmic map defined by the CartanSchoutenMinus connection.

    Given an element $q ∈ \mathcal{G}$, compute the right inverse of the group exponential map exp_lie, that is, the element $\log q = X ∈ 𝔤 = T_e \mathcal{G}$, such that $q = \exp X$

    Note

    In general, the group logarithm map is distinct from the Riemannian logarithm map log.

    For matrix Lie groups this is equal to the (matrix) logarithm:

    \[\log q = \operatorname{Log} q = \sum_{n=1}^∞ \frac{(-1)^{n+1}}{n} (q - e)^n,\]

    where $e$ here is the Identity element, that is, $1$ for numeric $q$ or the identity matrix $I_m$ for matrix $q ∈ ℝ^{m × m}$.

    Since this function also depends on the group operation, make sure to implement either

    • _log_lie(G, q) and _log_lie!(G, X, q) for the points not being the Identity
    • the trait version log_lie(::TraitList{<:IsGroupManifold}, G, e), log_lie(::TraitList{<:IsGroupManifold}, G, X, e) for own implementations of the identity case.
    source
    Manifolds.switch_directionMethod
    switch_direction(::ActionDirection, type::AbstractDirectionSwitchType = SimultaneousSwitch())

    Returns type of action between left and right, forward or backward, or both at the same type, depending on type, which is either of LeftRightSwitch, ForwardBackwardSwitch or SimultaneousSwitch.

    source
    Manifolds.translateMethod
    translate(G::AbstractDecoratorManifold, p, q, conv::ActionDirection=LeftForwardAction()])

    Translate group element $q$ by $p$ with the translation $τ_p$ with the specified convention, either left forward ($L_p$), left backward ($R'_p$), right backward ($R_p$) or right forward ($L'_p$), defined as

    \[\begin{aligned} +L_p &: q ↦ p \circ q\\ +L'_p &: q ↦ p^{-1} \circ q\\ +R_p &: q ↦ q \circ p\\ +R'_p &: q ↦ q \circ p^{-1}. +\end{aligned}\]

    source
    Manifolds.translate_diffMethod
    translate_diff(G::AbstractDecoratorManifold, p, q, X, conv::ActionDirection=LeftForwardAction())

    For group elements $p, q ∈ \mathcal{G}$ and tangent vector $X ∈ T_q \mathcal{G}$, compute the action of the differential of the translation $τ_p$ by $p$ on $X$, with the specified left or right convention. The differential transports vectors:

    \[(\mathrm{d}τ_p)_q : T_q \mathcal{G} → T_{τ_p q} \mathcal{G}\\\]

    source
    ManifoldsBase.hatMethod
    hat(M::AbstractDecoratorManifold{𝔽,O}, ::Identity{O}, Xⁱ) where {𝔽,O<:AbstractGroupOperation}

    Given a basis $e_i$ on the tangent space at a the Identity and tangent component vector $X^i$, compute the equivalent vector representation ``X=X^i e_i**, where Einstein summation notation is used:

    \[∧ : X^i ↦ X^i e_i\]

    For array manifolds, this converts a vector representation of the tangent vector to an array representation. The vee map is the hat map's inverse.

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(
    +    G::AbstractDecoratorManifold,
    +    p,
    +    X,
    +    method::GroupLogarithmicInverseRetraction{<:ActionDirection},
    +)

    Compute the inverse retraction using the group logarithm log_lie "translated" to any point on the manifold. With a group translation (translate) $τ_p$ in a specified direction, the retraction is

    \[\operatorname{retr}_p^{-1} = (\mathrm{d}τ_p)_e \circ \log \circ τ_p^{-1},\]

    where $\log$ is the group logarithm (log_lie), and $(\mathrm{d}τ_p)_e$ is the action of the differential of translation $τ_p$ evaluated at the identity element $e$ (see translate_diff).

    source
    ManifoldsBase.retractMethod
    retract(
    +    G::AbstractDecoratorManifold,
    +    p,
    +    X,
    +    method::GroupExponentialRetraction{<:ActionDirection},
    +)

    Compute the retraction using the group exponential exp_lie "translated" to any point on the manifold. With a group translation (translate) $τ_p$ in a specified direction, the retraction is

    \[\operatorname{retr}_p = τ_p \circ \exp \circ (\mathrm{d}τ_p^{-1})_p,\]

    where $\exp$ is the group exponential (exp_lie), and $(\mathrm{d}τ_p^{-1})_p$ is the action of the differential of inverse translation $τ_p^{-1}$ evaluated at $p$ (see inverse_translate_diff).

    source
    ManifoldsBase.veeMethod
    vee(M::AbstractManifold, p, X)

    Given a basis $e_i$ on the tangent space at a point p and tangent vector X, compute the vector components $X^i$, such that $X = X^i e_i$, where Einstein summation notation is used:

    \[\vee : X^i e_i ↦ X^i\]

    For array manifolds, this converts an array representation of the tangent vector to a vector representation. The hat map is the vee map's inverse.

    source

    GroupManifold

    As a concrete wrapper for manifolds (e.g. when the manifold per se is a group manifold but another group structure should be implemented), there is the GroupManifold

    Manifolds.GroupManifoldType
    GroupManifold{𝔽,M<:AbstractManifold{𝔽},O<:AbstractGroupOperation} <: AbstractDecoratorManifold{𝔽}

    Decorator for a smooth manifold that equips the manifold with a group operation, thus making it a Lie group. See IsGroupManifold for more details.

    Group manifolds by default forward metric-related operations to the wrapped manifold.

    Constructor

    GroupManifold(manifold, op)
    source

    Generic Operations

    For groups based on an addition operation or a group operation, several default implementations are provided.

    Addition Operation

    Multiplication Operation

    Circle group

    General linear group

    Manifolds.GeneralLinearType
    GeneralLinear{n,𝔽} <:
    +    AbstractDecoratorManifold{𝔽}

    The general linear group, that is, the group of all invertible matrices in $𝔽^{n×n}$.

    The default metric is the left-$\mathrm{GL}(n)$-right-$\mathrm{O}(n)$-invariant metric whose inner product is

    \[⟨X_p,Y_p⟩_p = ⟨p^{-1}X_p,p^{-1}Y_p⟩_\mathrm{F} = ⟨X_e, Y_e⟩_\mathrm{F},\]

    where $X_p, Y_p ∈ T_p \mathrm{GL}(n, 𝔽)$, $X_e = p^{-1}X_p ∈ 𝔤𝔩(n) = T_e \mathrm{GL}(n, 𝔽) = 𝔽^{n×n}$ is the corresponding vector in the Lie algebra, and $⟨⋅,⋅⟩_\mathrm{F}$ denotes the Frobenius inner product.

    By default, tangent vectors $X_p$ are represented with their corresponding Lie algebra vectors $X_e = p^{-1}X_p$.

    source
    Base.logMethod
    log(G::GeneralLinear, p, q)

    Compute the logarithmic map on the GeneralLinear(n) group.

    The algorithm proceeds in two stages. First, the point $r = p^{-1} q$ is projected to the nearest element (under the Frobenius norm) of the direct product subgroup $\mathrm{O}(n) × S^+$, whose logarithmic map is exactly computed using the matrix logarithm. This initial tangent vector is then refined using the NLSolveInverseRetraction.

    For GeneralLinear(n, ℂ), the logarithmic map is instead computed on the realified supergroup GeneralLinear(2n) and the resulting tangent vector is then complexified.

    Note that this implementation is experimental.

    source
    Base.randMethod
    Random.rand(G::GeneralLinear; vector_at=nothing, kwargs...)

    If vector_at is nothing, return a random point on the GeneralLinear group G by using rand in the embedding.

    If vector_at is not nothing, return a random tangent vector from the tangent space of the point vector_at on the GeneralLinear by using by using rand in the embedding.

    source

    Heisenberg group

    Manifolds.HeisenbergGroupType
    HeisenbergGroup{n} <: AbstractDecoratorManifold{ℝ}

    Heisenberg group HeisenbergGroup(n) is the group of $(n+2) × (n+2)$ matrices [BinzPods2008]

    \[\begin{bmatrix} 1 & \mathbf{a} & c \\ +\mathbf{0} & I_n & \mathbf{b} \\ +0 & \mathbf{0} & 1 \end{bmatrix}\]

    where $I_n$ is the $n×n$ unit matrix, $\mathbf{a}$ is a row vector of length $n$, $\mathbf{b}$ is a column vector of length $n$ and $c$ is a real number. The group operation is matrix multiplication.

    The left-invariant metric on the manifold is used.

    source
    Base.expMethod
    exp(M::HeisenbergGroup, p, X)

    Exponential map on the HeisenbergGroup M with the left-invariant metric. The expression reads

    \[\exp_{\begin{bmatrix} 1 & \mathbf{a}_p & c_p \\ +\mathbf{0} & I_n & \mathbf{b}_p \\ +0 & \mathbf{0} & 1 \end{bmatrix}}\left(\begin{bmatrix} 0 & \mathbf{a}_X & c_X \\ +\mathbf{0} & 0_n & \mathbf{b}_X \\ +0 & \mathbf{0} & 0 \end{bmatrix}\right) = +\begin{bmatrix} 1 & \mathbf{a}_p + \mathbf{a}_X & c_p + c_X + \mathbf{a}_X⋅\mathbf{b}_X/2 + \mathbf{a}_p⋅\mathbf{b}_X \\ +\mathbf{0} & I_n & \mathbf{b}_p + \mathbf{b}_X \\ +0 & \mathbf{0} & 1 \end{bmatrix}\]

    where $I_n$ is the $n×n$ identity matrix, $0_n$ is the $n×n$ zero matrix and $\mathbf{a}⋅\mathbf{b}$ is dot product of vectors.

    source
    Base.logMethod
    log(G::HeisenbergGroup, p, q)

    Compute the logarithmic map on the HeisenbergGroup group. The formula reads

    \[\log_{\begin{bmatrix} 1 & \mathbf{a}_p & c_p \\ +\mathbf{0} & I_n & \mathbf{b}_p \\ +0 & \mathbf{0} & 1 \end{bmatrix}}\left(\begin{bmatrix} 1 & \mathbf{a}_q & c_q \\ +\mathbf{0} & I_n & \mathbf{b}_q \\ +0 & \mathbf{0} & 1 \end{bmatrix}\right) = +\begin{bmatrix} 0 & \mathbf{a}_q - \mathbf{a}_p & c_q - c_p + \mathbf{a}_p⋅\mathbf{b}_p - \mathbf{a}_q⋅\mathbf{b}_q - (\mathbf{a}_q - \mathbf{a}_p)⋅(\mathbf{b}_q - \mathbf{b}_p) / 2 \\ +\mathbf{0} & 0_n & \mathbf{b}_q - \mathbf{b}_p \\ +0 & \mathbf{0} & 0 \end{bmatrix}\]

    where $I_n$ is the $n×n$ identity matrix, $0_n$ is the $n×n$ zero matrix and $\mathbf{a}⋅\mathbf{b}$ is dot product of vectors.

    source
    Base.randMethod
    Random.rand(M::HeisenbergGroup; vector_at = nothing, σ::Real=1.0)

    If vector_at is nothing, return a random point on the HeisenbergGroup M by sampling elements of the first row and the last column from the normal distribution with mean 0 and standard deviation σ.

    If vector_at is not nothing, return a random tangent vector from the tangent space of the point vector_at on the HeisenbergGroup by using a normal distribution with mean 0 and standard deviation σ.

    source
    Manifolds.exp_lieMethod
    exp_lie(M::HeisenbergGroup, X)

    Lie group exponential for the HeisenbergGroup M of the vector X. The formula reads

    \[\exp\left(\begin{bmatrix} 0 & \mathbf{a} & c \\ +\mathbf{0} & 0_n & \mathbf{b} \\ +0 & \mathbf{0} & 0 \end{bmatrix}\right) = \begin{bmatrix} 1 & \mathbf{a} & c + \mathbf{a}⋅\mathbf{b}/2 \\ +\mathbf{0} & I_n & \mathbf{b} \\ +0 & \mathbf{0} & 1 \end{bmatrix}\]

    where $I_n$ is the $n×n$ identity matrix, $0_n$ is the $n×n$ zero matrix and $\mathbf{a}⋅\mathbf{b}$ is dot product of vectors.

    source
    Manifolds.log_lieMethod
    log_lie(M::HeisenbergGroup, p)

    Lie group logarithm for the HeisenbergGroup M of the point p. The formula reads

    \[\log\left(\begin{bmatrix} 1 & \mathbf{a} & c \\ +\mathbf{0} & I_n & \mathbf{b} \\ +0 & \mathbf{0} & 1 \end{bmatrix}\right) = +\begin{bmatrix} 0 & \mathbf{a} & c - \mathbf{a}⋅\mathbf{b}/2 \\ +\mathbf{0} & 0_n & \mathbf{b} \\ +0 & \mathbf{0} & 0 \end{bmatrix}\]

    where $I_n$ is the $n×n$ identity matrix, $0_n$ is the $n×n$ zero matrix and $\mathbf{a}⋅\mathbf{b}$ is dot product of vectors.

    source
    ManifoldsBase.get_coordinatesMethod
    get_coordinates(M::HeisenbergGroup, p, X, ::DefaultOrthonormalBasis{ℝ,TangentSpaceType})

    Get coordinates of tangent vector X at point p from the HeisenbergGroup M. Given a matrix

    \[\begin{bmatrix} 1 & \mathbf{a} & c \\ +\mathbf{0} & I_n & \mathbf{b} \\ +0 & \mathbf{0} & 1 \end{bmatrix}\]

    the coordinates are concatenated vectors $\mathbf{a}$, $\mathbf{b}$, and number $c$.

    source
    ManifoldsBase.get_vectorMethod
    get_vector(M::HeisenbergGroup, p, Xⁱ, ::DefaultOrthonormalBasis{ℝ,TangentSpaceType})

    Get tangent vector with coordinates Xⁱ at point p from the HeisenbergGroup M. Given a vector of coordinates $\begin{bmatrix}\mathbb{a} & \mathbb{b} & c\end{bmatrix}$ the tangent vector is equal to

    \[\begin{bmatrix} 1 & \mathbf{a} & c \\ +\mathbf{0} & I_n & \mathbf{b} \\ +0 & \mathbf{0} & 1 \end{bmatrix}\]

    source
    ManifoldsBase.projectMethod
    project(M::HeisenbergGroup{n}, p, X)

    Project a matrix X in the Euclidean embedding onto the Lie algebra of HeisenbergGroup M. Sets the diagonal elements to 0 and all non-diagonal elements except the first row and the last column to 0.

    source
    ManifoldsBase.projectMethod
    project(M::HeisenbergGroup{n}, p)

    Project a matrix p in the Euclidean embedding onto the HeisenbergGroup M. Sets the diagonal elements to 1 and all non-diagonal elements except the first row and the last column to 0.

    source

    (Special) Orthogonal and (Special) Unitary group

    Since the orthogonal, unitary and special orthogonal and special unitary groups share many common functions, these are also implemented on a common level.

    Common functions

    Manifolds.exp_lieMethod
     exp_lie(G::Orthogonal{2}, X)
    + exp_lie(G::SpecialOrthogonal{2}, X)

    Compute the Lie group exponential map on the Orthogonal(2) or SpecialOrthogonal(2) group. Given $X = \begin{pmatrix} 0 & -θ \\ θ & 0 \end{pmatrix}$, the group exponential is

    \[\exp_e \colon X ↦ \begin{pmatrix} \cos θ & -\sin θ \\ \sin θ & \cos θ \end{pmatrix}.\]

    source

    Orthogonal group

    Special orthogonal group

    Manifolds.SpecialOrthogonalType
    SpecialOrthogonal{n} <: GroupManifold{ℝ,Rotations{n},MultiplicationOperation}

    Special orthogonal group $\mathrm{SO}(n)$ represented by rotation matrices, see Rotations.

    Constructor

    SpecialOrthogonal(n)
    source

    Special unitary group

    Manifolds.SpecialUnitaryType
    SpecialUnitary{n} = GeneralUnitaryMultiplicationGroup{n,ℝ,GeneralUnitaryMatrices{n,ℂ,DeterminantOneMatrices}}

    The special unitary group $\mathrm{SU}(n)$ represented by unitary matrices of determinant +1.

    The tangent spaces are of the form

    \[T_p\mathrm{SU}(x) = \bigl\{ X \in \mathbb C^{n×n} \big| X = pY \text{ where } Y = -Y^{\mathrm{H}} \bigr\}\]

    and we represent tangent vectors by just storing the SkewHermitianMatrices $Y$, or in other words we represent the tangent spaces employing the Lie algebra $\mathfrak{su}(n)$.

    Constructor

    SpecialUnitary(n)

    Generate the Lie group of $n×n$ unitary matrices with determinant +1.

    source
    ManifoldsBase.projectMethod
    project(G::SpecialUnitary, p)

    Project p to the nearest point on the SpecialUnitary group G.

    Given the singular value decomposition $p = U S V^\mathrm{H}$, with the singular values sorted in descending order, the projection is

    \[\operatorname{proj}_{\mathrm{SU}(n)}(p) = +U\operatorname{diag}\left[1,1,…,\det(U V^\mathrm{H})\right] V^\mathrm{H}.\]

    The diagonal matrix ensures that the determinant of the result is $+1$.

    source

    Unitary group

    Manifolds.UnitaryType
     Unitary{n,𝔽} = GeneralUnitaryMultiplicationGroup{n,𝔽,AbsoluteDeterminantOneMatrices}

    The group of unitary matrices $\mathrm{U}(n, 𝔽)$, either complex (when 𝔽=ℂ) or quaternionic (when 𝔽=ℍ)

    The group consists of all points $p ∈ 𝔽^{n × n}$ where $p^\mathrm{H}p = pp^\mathrm{H} = I$.

    The tangent spaces are if the form

    \[T_p\mathrm{U}(n) = \bigl\{ X \in 𝔽^{n×n} \big| X = pY \text{ where } Y = -Y^{\mathrm{H}} \bigr\}\]

    and we represent tangent vectors by just storing the SkewHermitianMatrices $Y$, or in other words we represent the tangent spaces employing the Lie algebra $\mathfrak{u}(n, 𝔽)$.

    Quaternionic unitary group is isomorphic to the compact symplectic group of the same dimension.

    Constructor

    Unitary(n, 𝔽::AbstractNumbers=ℂ)

    Construct $\mathrm{U}(n, 𝔽)$. See also Orthogonal(n) for the real-valued case.

    source
    Manifolds.exp_lieMethod
    exp_lie(G::Unitary{2,ℂ}, X)

    Compute the group exponential map on the Unitary(2) group, which is

    \[\exp_e \colon X ↦ e^{\operatorname{tr}(X) / 2} \left(\cos θ I + \frac{\sin θ}{θ} \left(X - \frac{\operatorname{tr}(X)}{2} I\right)\right),\]

    where $θ = \frac{1}{2} \sqrt{4\det(X) - \operatorname{tr}(X)^2}$.

    source

    Power group

    Manifolds.PowerGroupMethod
    PowerGroup{𝔽,T} <: GroupManifold{𝔽,<:AbstractPowerManifold{𝔽,M,RPT},ProductOperation}

    Decorate a power manifold with a ProductOperation.

    Constituent manifold of the power manifold must also have a IsGroupManifold or a decorated instance of one. This type is mostly useful for equipping the direct product of group manifolds with an Identity element.

    Constructor

    PowerGroup(manifold::AbstractPowerManifold)
    source

    Product group

    Manifolds.ProductGroupMethod
    ProductGroup{𝔽,T} <: GroupManifold{𝔽,ProductManifold{T},ProductOperation}

    Decorate a product manifold with a ProductOperation.

    Each submanifold must also have a IsGroupManifold or a decorated instance of one. This type is mostly useful for equipping the direct product of group manifolds with an Identity element.

    Constructor

    ProductGroup(manifold::ProductManifold)
    source

    Semidirect product group

    Manifolds.SemidirectProductGroupMethod
    SemidirectProductGroup(N::GroupManifold, H::GroupManifold, A::AbstractGroupAction)

    A group that is the semidirect product of a normal group $\mathcal{N}$ and a subgroup $\mathcal{H}$, written $\mathcal{G} = \mathcal{N} ⋊_θ \mathcal{H}$, where $θ: \mathcal{H} × \mathcal{N} → \mathcal{N}$ is an automorphism action of $\mathcal{H}$ on $\mathcal{N}$. The group $\mathcal{G}$ has the composition rule

    \[g \circ g' = (n, h) \circ (n', h') = (n \circ θ_h(n'), h \circ h')\]

    and the inverse

    \[g^{-1} = (n, h)^{-1} = (θ_{h^{-1}}(n^{-1}), h^{-1}).\]

    source
    Manifolds.SemidirectProductOperationType
    SemidirectProductOperation(action::AbstractGroupAction)

    Group operation of a semidirect product group. The operation consists of the operation opN on a normal subgroup N, the operation opH on a subgroup H, and an automorphism action of elements of H on N. Only the action is stored.

    source
    Manifolds.translate_diffMethod
    translate_diff(G::SemidirectProductGroup, p, q, X, conX::LeftForwardAction)

    Perform differential of the left translation on the semidirect product group G.

    Since the left translation is defined as (cf. SemidirectProductGroup):

    \[L_{(n', h')} (n, h) = ( L_{n'} θ_{h'}(n), L_{h'} h)\]

    then its differential can be computed as

    \[\mathrm{d}L_{(n', h')}(X_n, X_h) = ( \mathrm{d}L_{n'} (\mathrm{d}θ_{h'}(X_n)), \mathrm{d}L_{h'} X_h).\]

    source

    Special Euclidean group

    Manifolds.SpecialEuclideanType
    SpecialEuclidean(n)

    Special Euclidean group $\mathrm{SE}(n)$, the group of rigid motions.

    $\mathrm{SE}(n)$ is the semidirect product of the TranslationGroup on $ℝ^n$ and SpecialOrthogonal(n)

    \[\mathrm{SE}(n) ≐ \mathrm{T}(n) ⋊_θ \mathrm{SO}(n),\]

    where $θ$ is the canonical action of $\mathrm{SO}(n)$ on $\mathrm{T}(n)$ by vector rotation.

    This constructor is equivalent to calling

    Tn = TranslationGroup(n)
    +SOn = SpecialOrthogonal(n)
    +SemidirectProductGroup(Tn, SOn, RotationAction(Tn, SOn))

    Points on $\mathrm{SE}(n)$ may be represented as points on the underlying product manifold $\mathrm{T}(n) × \mathrm{SO}(n)$. For group-specific functions, they may also be represented as affine matrices with size (n + 1, n + 1) (see affine_matrix), for which the group operation is MultiplicationOperation.

    source
    Manifolds.SpecialEuclideanInGeneralLinearType
    SpecialEuclideanInGeneralLinear

    An explicit isometric and homomorphic embedding of $\mathrm{SE}(n)$ in $\mathrm{GL}(n+1)$ and $𝔰𝔢(n)$ in $𝔤𝔩(n+1)$. Note that this is not a transparently isometric embedding.

    Constructor

    SpecialEuclideanInGeneralLinear(n)
    source
    Manifolds.adjoint_actionMethod
    adjoint_action(::SpecialEuclidean{3}, p, fX::TFVector{<:Any,VeeOrthogonalBasis{ℝ}})

    Adjoint action of the SpecialEuclidean group on the vector with coefficients fX tangent at point p.

    The formula for the coefficients reads $t×(R⋅ω) + R⋅r$ for the translation part and $R⋅ω$ for the rotation part, where t is the translation part of p, R is the rotation matrix part of p, r is the translation part of fX and ω is the rotation part of fX, $×$ is the cross product and $⋅$ is the matrix product.

    source
    Manifolds.affine_matrixMethod
    affine_matrix(G::SpecialEuclidean, p) -> AbstractMatrix

    Represent the point $p ∈ \mathrm{SE}(n)$ as an affine matrix. For $p = (t, R) ∈ \mathrm{SE}(n)$, where $t ∈ \mathrm{T}(n), R ∈ \mathrm{SO}(n)$, the affine representation is the $n + 1 × n + 1$ matrix

    \[\begin{pmatrix} +R & t \\ +0^\mathrm{T} & 1 +\end{pmatrix}.\]

    This function embeds $\mathrm{SE}(n)$ in the general linear group $\mathrm{GL}(n+1)$. It is an isometric embedding and group homomorphism [RicoMartinez1988].

    See also screw_matrix for matrix representations of the Lie algebra.

    source
    Manifolds.exp_lieMethod
    exp_lie(G::SpecialEuclidean{2}, X)

    Compute the group exponential of $X = (b, Ω) ∈ 𝔰𝔢(2)$, where $b ∈ 𝔱(2)$ and $Ω ∈ 𝔰𝔬(2)$:

    \[\exp X = (t, R) = (U(θ) b, \exp Ω),\]

    where $t ∈ \mathrm{T}(2)$, $R = \exp Ω$ is the group exponential on $\mathrm{SO}(2)$,

    \[U(θ) = \frac{\sin θ}{θ} I_2 + \frac{1 - \cos θ}{θ^2} Ω,\]

    and $θ = \frac{1}{\sqrt{2}} \lVert Ω \rVert_e$ (see norm) is the angle of the rotation.

    source
    Manifolds.exp_lieMethod
    exp_lie(G::SpecialEuclidean{3}, X)

    Compute the group exponential of $X = (b, Ω) ∈ 𝔰𝔢(3)$, where $b ∈ 𝔱(3)$ and $Ω ∈ 𝔰𝔬(3)$:

    \[\exp X = (t, R) = (U(θ) b, \exp Ω),\]

    where $t ∈ \mathrm{T}(3)$, $R = \exp Ω$ is the group exponential on $\mathrm{SO}(3)$,

    \[U(θ) = I_3 + \frac{1 - \cos θ}{θ^2} Ω + \frac{θ - \sin θ}{θ^3} Ω^2,\]

    and $θ = \frac{1}{\sqrt{2}} \lVert Ω \rVert_e$ (see norm) is the angle of the rotation.

    source
    Manifolds.exp_lieMethod
    exp_lie(G::SpecialEuclidean{n}, X)

    Compute the group exponential of $X = (b, Ω) ∈ 𝔰𝔢(n)$, where $b ∈ 𝔱(n)$ and $Ω ∈ 𝔰𝔬(n)$:

    \[\exp X = (t, R),\]

    where $t ∈ \mathrm{T}(n)$ and $R = \exp Ω$ is the group exponential on $\mathrm{SO}(n)$.

    In the screw_matrix representation, the group exponential is the matrix exponential (see exp_lie).

    source
    Manifolds.lie_bracketMethod
    lie_bracket(G::SpecialEuclidean, X::ProductRepr, Y::ProductRepr)
    +lie_bracket(G::SpecialEuclidean, X::ArrayPartition, Y::ArrayPartition)
    +lie_bracket(G::SpecialEuclidean, X::AbstractMatrix, Y::AbstractMatrix)

    Calculate the Lie bracket between elements X and Y of the special Euclidean Lie algebra. For the matrix representation (which can be obtained using screw_matrix) the formula is $[X, Y] = XY-YX$, while in the ProductRepr representation the formula reads $[X, Y] = [(t_1, R_1), (t_2, R_2)] = (R_1 t_2 - R_2 t_1, R_1 R_2 - R_2 R_1)$.

    source
    Manifolds.log_lieMethod
    log_lie(G::SpecialEuclidean{2}, p)

    Compute the group logarithm of $p = (t, R) ∈ \mathrm{SE}(2)$, where $t ∈ \mathrm{T}(2)$ and $R ∈ \mathrm{SO}(2)$:

    \[\log p = (b, Ω) = (U(θ)^{-1} t, \log R),\]

    where $b ∈ 𝔱(2)$, $Ω = \log R ∈ 𝔰𝔬(2)$ is the group logarithm on $\mathrm{SO}(2)$,

    \[U(θ) = \frac{\sin θ}{θ} I_2 + \frac{1 - \cos θ}{θ^2} Ω,\]

    and $θ = \frac{1}{\sqrt{2}} \lVert Ω \rVert_e$ (see norm) is the angle of the rotation.

    source
    Manifolds.log_lieMethod
    log_lie(G::SpecialEuclidean{3}, p)

    Compute the group logarithm of $p = (t, R) ∈ \mathrm{SE}(3)$, where $t ∈ \mathrm{T}(3)$ and $R ∈ \mathrm{SO}(3)$:

    \[\log p = (b, Ω) = (U(θ)^{-1} t, \log R),\]

    where $b ∈ 𝔱(3)$, $Ω = \log R ∈ 𝔰𝔬(3)$ is the group logarithm on $\mathrm{SO}(3)$,

    \[U(θ) = I_3 + \frac{1 - \cos θ}{θ^2} Ω + \frac{θ - \sin θ}{θ^3} Ω^2,\]

    and $θ = \frac{1}{\sqrt{2}} \lVert Ω \rVert_e$ (see norm) is the angle of the rotation.

    source
    Manifolds.log_lieMethod
    log_lie(G::SpecialEuclidean{n}, p) where {n}

    Compute the group logarithm of $p = (t, R) ∈ \mathrm{SE}(n)$, where $t ∈ \mathrm{T}(n)$ and $R ∈ \mathrm{SO}(n)$:

    \[\log p = (b, Ω),\]

    where $b ∈ 𝔱(n)$ and $Ω = \log R ∈ 𝔰𝔬(n)$ is the group logarithm on $\mathrm{SO}(n)$.

    In the affine_matrix representation, the group logarithm is the matrix logarithm (see log_lie):

    source
    Manifolds.screw_matrixMethod
    screw_matrix(G::SpecialEuclidean, X) -> AbstractMatrix

    Represent the Lie algebra element $X ∈ 𝔰𝔢(n) = T_e \mathrm{SE}(n)$ as a screw matrix. For $X = (b, Ω) ∈ 𝔰𝔢(n)$, where $Ω ∈ 𝔰𝔬(n) = T_e \mathrm{SO}(n)$, the screw representation is the $n + 1 × n + 1$ matrix

    \[\begin{pmatrix} +Ω & b \\ +0^\mathrm{T} & 0 +\end{pmatrix}.\]

    This function embeds $𝔰𝔢(n)$ in the general linear Lie algebra $𝔤𝔩(n+1)$ but it's not a homomorphic embedding (see SpecialEuclideanInGeneralLinear for a homomorphic one).

    See also affine_matrix for matrix representations of the Lie group.

    source
    Manifolds.translate_diffMethod
    translate_diff(G::SpecialEuclidean, p, q, X, ::RightBackwardAction)

    Differential of the right action of the SpecialEuclidean group on itself. The formula for the rotation part is the differential of the right rotation action, while the formula for the translation part reads

    \[R_q⋅X_R⋅t_p + X_t\]

    where $R_q$ is the rotation part of q, $X_R$ is the rotation part of X, $t_p$ is the translation part of p and $X_t$ is the translation part of X.

    source
    ManifoldsBase.embedMethod
    embed(M::SpecialEuclideanInGeneralLinear, p, X)

    Embed the tangent vector X at point p on SpecialEuclidean in the GeneralLinear group. Point p can use any representation valid for SpecialEuclidean. The embedding is similar from the one defined by screw_matrix but the translation part is multiplied by inverse of the rotation part.

    source

    Special linear group

    Manifolds.SpecialLinearType
    SpecialLinear{n,𝔽} <: AbstractDecoratorManifold

    The special linear group $\mathrm{SL}(n,𝔽)$ that is, the group of all invertible matrices with unit determinant in $𝔽^{n×n}$.

    The Lie algebra $𝔰𝔩(n, 𝔽) = T_e \mathrm{SL}(n,𝔽)$ is the set of all matrices in $𝔽^{n×n}$ with trace of zero. By default, tangent vectors $X_p ∈ T_p \mathrm{SL}(n,𝔽)$ for $p ∈ \mathrm{SL}(n,𝔽)$ are represented with their corresponding Lie algebra vector $X_e = p^{-1}X_p ∈ 𝔰𝔩(n, 𝔽)$.

    The default metric is the same left-$\mathrm{GL}(n)$-right-$\mathrm{O}(n)$-invariant metric used for GeneralLinear(n, 𝔽). The resulting geodesic on $\mathrm{GL}(n,𝔽)$ emanating from an element of $\mathrm{SL}(n,𝔽)$ in the direction of an element of $𝔰𝔩(n, 𝔽)$ is a closed subgroup of $\mathrm{SL}(n,𝔽)$. As a result, most metric functions forward to GeneralLinear.

    source
    ManifoldsBase.projectMethod
    project(G::SpecialLinear, p, X)

    Orthogonally project $X ∈ 𝔽^{n × n}$ onto the tangent space of $p$ to the SpecialLinear $G = \mathrm{SL}(n, 𝔽)$. The formula reads

    \[\operatorname{proj}_{p} + = (\mathrm{d}L_p)_e ∘ \operatorname{proj}_{𝔰𝔩(n, 𝔽)} ∘ (\mathrm{d}L_p^{-1})_p + \colon X ↦ X - \frac{\operatorname{tr}(X)}{n} I,\]

    where the last expression uses the tangent space representation as the Lie algebra.

    source
    ManifoldsBase.projectMethod
    project(G::SpecialLinear, p)

    Project $p ∈ \mathrm{GL}(n, 𝔽)$ to the SpecialLinear group $G=\mathrm{SL}(n, 𝔽)$.

    Given the singular value decomposition of $p$, written $p = U S V^\mathrm{H}$, the formula for the projection is

    \[\operatorname{proj}_{\mathrm{SL}(n, 𝔽)}(p) = U S D V^\mathrm{H},\]

    where

    \[D_{ij} = δ_{ij} \begin{cases} + 1 & \text{ if } i ≠ n \\ + \det(p)^{-1} & \text{ if } i = n +\end{cases}.\]

    source

    Translation group

    Manifolds.TranslationGroupType
    TranslationGroup{T<:Tuple,𝔽} <: GroupManifold{Euclidean{T,𝔽},AdditionOperation}

    Translation group $\mathrm{T}(n)$ represented by translation arrays.

    Constructor

    TranslationGroup(n₁,...,nᵢ; field = 𝔽)

    Generate the translation group on $𝔽^{n₁,…,nᵢ}$ = Euclidean(n₁,...,nᵢ; field = 𝔽), which is isomorphic to the group itself.

    source

    Group actions

    Group actions represent actions of a given group on a specified manifold. The following operations are available:

    Furthermore, group operation action features the following:

    The following group actions are available:

    Manifolds.adjoint_apply_diff_groupMethod
    adjoint_apply_diff_group(A::AbstractGroupAction, a, X, p)

    Pullback with respect to group element of group action A.

    \[(\mathrm{d}τ^{p,*}) : T_{τ_{a} p} \mathcal M → T_{a} \mathcal G\]

    source
    Manifolds.apply!Method
    apply!(A::AbstractGroupAction, q, a, p)

    Apply action a to the point p with the rule specified by A. The result is saved in q.

    source
    Manifolds.applyMethod
    apply(A::AbstractGroupAction, a, p)

    Apply action a to the point p using map $τ_a$, specified by A. Unless otherwise specified, the right action is defined in terms of the left action:

    \[\mathrm{R}_a = \mathrm{L}_{a^{-1}}\]

    source
    Manifolds.apply_diffMethod
    apply_diff(A::AbstractGroupAction, a, p, X)

    For point $p ∈ \mathcal M$ and tangent vector $X ∈ T_p \mathcal M$, compute the action on $X$ of the differential of the action of $a ∈ \mathcal{G}$, specified by rule A. Written as $(\mathrm{d}τ_a)_p$, with the specified left or right convention, the differential transports vectors

    \[(\mathrm{d}τ_a)_p : T_p \mathcal M → T_{τ_a p} \mathcal M\]

    source
    Manifolds.apply_diff_groupMethod
    apply_diff_group(A::AbstractGroupAction, a, X, p)

    Compute the value of differential of action AbstractGroupAction A on vector X, where element a is acting on p, with respect to the group element.

    Let $\mathcal G$ be the group acting on manifold $\mathcal M$ by the action A. The action is of element $g ∈ \mathcal G$ on a point $p ∈ \mathcal M$. The differential transforms vector X from the tangent space at a ∈ \mathcal G, $X ∈ T_a \mathcal G$ into a tangent space of the manifold $\mathcal M$. When action on element p is written as $\mathrm{d}τ^p$, with the specified left or right convention, the differential transforms vectors

    \[(\mathrm{d}τ^p) : T_{a} \mathcal G → T_{τ_a p} \mathcal M\]

    See also

    apply, apply_diff

    source
    Manifolds.center_of_orbitFunction
    center_of_orbit(
    +    A::AbstractGroupAction,
    +    pts,
    +    p,
    +    mean_method::AbstractEstimationMethod = GradientDescentEstimation(),
    +)

    Calculate an action element $a$ of action A that is the mean element of the orbit of p with respect to given set of points pts. The mean is calculated using the method mean_method.

    The orbit of $p$ with respect to the action of a group $\mathcal{G}$ is the set

    \[O = \{ τ_a p : a ∈ \mathcal{G} \}.\]

    This function is useful for computing means on quotients of manifolds by a Lie group action.

    source
    Manifolds.inverse_apply!Method
    inverse_apply!(A::AbstractGroupAction, q, a, p)

    Apply inverse of action a to the point p with the rule specified by A. The result is saved in q.

    source
    Manifolds.inverse_applyMethod
    inverse_apply(A::AbstractGroupAction, a, p)

    Apply inverse of action a to the point p. The action is specified by A.

    source
    Manifolds.inverse_apply_diffMethod
    inverse_apply_diff(A::AbstractGroupAction, a, p, X)

    For group point $p ∈ \mathcal M$ and tangent vector $X ∈ T_p \mathcal M$, compute the action on $X$ of the differential of the inverse action of $a ∈ \mathcal{G}$, specified by rule A. Written as $(\mathrm{d}τ_a^{-1})_p$, with the specified left or right convention, the differential transports vectors

    \[(\mathrm{d}τ_a^{-1})_p : T_p \mathcal M → T_{τ_a^{-1} p} \mathcal M\]

    source
    Manifolds.optimal_alignment!Method
    optimal_alignment!(A::AbstractGroupAction, x, p, q)

    Calculate an action element of action A that acts upon p to produce the element closest to q. The result is written to x.

    source
    Manifolds.optimal_alignmentMethod
    optimal_alignment(A::AbstractGroupAction, p, q)

    Calculate an action element $a$ of action A that acts upon p to produce the element closest to q in the metric of the G-manifold:

    \[\arg\min_{a ∈ \mathcal{G}} d_{\mathcal M}(τ_a p, q)\]

    where $\mathcal{G}$ is the group that acts on the G-manifold $\mathcal M$.

    source

    Group operation action

    Manifolds.GroupOperationActionType
    GroupOperationAction(group::AbstractDecoratorManifold, AD::ActionDirection = LeftForwardAction())

    Action of a group upon itself via left or right translation.

    source

    Rotation action

    Manifolds.ColumnwiseMultiplicationActionType
    ColumnwiseMultiplicationAction{
    +    TM<:AbstractManifold,
    +    TO<:GeneralUnitaryMultiplicationGroup,
    +    TAD<:ActionDirection,
    +} <: AbstractGroupAction{TAD}

    Action of the (special) unitary or orthogonal group GeneralUnitaryMultiplicationGroup of type On columns of points on a matrix manifold M.

    Constructor

    ColumnwiseMultiplicationAction(
    +    M::AbstractManifold,
    +    On::GeneralUnitaryMultiplicationGroup,
    +    AD::ActionDirection = LeftForwardAction(),
    +)
    source
    Manifolds.RotationActionType
    RotationAction(
    +    M::AbstractManifold,
    +    SOn::SpecialOrthogonal,
    +    AD::ActionDirection = LeftForwardAction(),
    +)

    Space of actions of the SpecialOrthogonal group $\mathrm{SO}(n)$ on a Euclidean-like manifold M of dimension n.

    source
    Manifolds.RowwiseMultiplicationActionType
    RowwiseMultiplicationAction{
    +    TM<:AbstractManifold,
    +    TO<:GeneralUnitaryMultiplicationGroup,
    +    TAD<:ActionDirection,
    +} <: AbstractGroupAction{TAD}

    Action of the (special) unitary or orthogonal group GeneralUnitaryMultiplicationGroup of type On columns of points on a matrix manifold M.

    Constructor

    RowwiseMultiplicationAction(
    +    M::AbstractManifold,
    +    On::GeneralUnitaryMultiplicationGroup,
    +    AD::ActionDirection = LeftForwardAction(),
    +)
    source
    Manifolds.applyMethod
    apply(A::RotationAroundAxisAction, θ, p)

    Rotate point p from Euclidean(3) manifold around axis A.axis by angle θ. The formula reads

    \[p_{rot} = (\cos(θ))p + (k×p) \sin(θ) + k (k⋅p) (1-\cos(θ)),\]

    where $k$ is the vector A.axis and is the dot product.

    source
    Manifolds.optimal_alignmentMethod
    optimal_alignment(A::LeftColumnwiseMultiplicationAction, p, q)

    Compute optimal alignment for the left ColumnwiseMultiplicationAction, i.e. the group element $O^{*}$ that, when it acts on p, returns the point closest to q. Details of computation are described in Section 2.2.1 of [Srivastava2016].

    The formula reads

    \[O^{*} = \begin{cases} +UV^T & \text{if } \operatorname{det}(p q^{\mathrm{T}})\\ +U K V^{\mathrm{T}} & \text{otherwise} +\end{cases}\]

    where $U \Sigma V^{\mathrm{T}}$ is the SVD decomposition of $p q^{\mathrm{T}}$ and $K$ is the unit diagonal matrix with the last element on the diagonal replaced with -1.

    References

    source

    Translation action

    Manifolds.TranslationActionType
    TranslationAction(
    +    M::AbstractManifold,
    +    Rn::TranslationGroup,
    +    AD::ActionDirection = LeftForwardAction(),
    +)

    Space of actions of the TranslationGroup $\mathrm{T}(n)$ on a Euclidean-like manifold M.

    The left and right actions are equivalent.

    source

    Metrics on groups

    Lie groups by default typically forward all metric-related operations like exponential or logarithmic map to the underlying manifold, for example SpecialOrthogonal uses methods for Rotations (which is, incidentally, bi-invariant), or SpecialEuclidean uses product metric of the translation and rotation parts (which is not invariant under group operation).

    It is, however, possible to change the metric used by a group by wrapping it in a MetricManifold decorator.

    Invariant metrics

    Manifolds.directionMethod
    direction(::AbstractDecoratorManifold) -> AD

    Get the direction of the action a certain Lie group with its implicit metric has

    source
    Manifolds.has_approx_invariant_metricMethod
    has_approx_invariant_metric(
    +    G::AbstractDecoratorManifold,
    +    p,
    +    X,
    +    Y,
    +    qs::AbstractVector,
    +    conv::ActionDirection = LeftForwardAction();
    +    kwargs...,
    +) -> Bool

    Check whether the metric on the group $\mathcal{G}$ is (approximately) invariant using a set of predefined points. Namely, for $p ∈ \mathcal{G}$, $X,Y ∈ T_p \mathcal{G}$, a metric $g$, and a translation map $τ_q$ in the specified direction, check for each $q ∈ \mathcal{G}$ that the following condition holds:

    \[g_p(X, Y) ≈ g_{τ_q p}((\mathrm{d}τ_q)_p X, (\mathrm{d}τ_q)_p Y).\]

    This is necessary but not sufficient for invariance.

    Optionally, kwargs passed to isapprox may be provided.

    source

    Cartan-Schouten connections

    Manifolds.CartanSchoutenMinusType
    CartanSchoutenMinus

    The unique Cartan-Schouten connection such that all left-invariant vector fields are globally defined by their value at identity. It is biinvariant with respect to the group operation.

    source
    Manifolds.CartanSchoutenPlusType
    CartanSchoutenPlus

    The unique Cartan-Schouten connection such that all right-invariant vector fields are globally defined by their value at identity. It is biinvariant with respect to the group operation.

    source
    Manifolds.CartanSchoutenZeroType
    CartanSchoutenZero

    The unique torsion-free Cartan-Schouten connection. It is biinvariant with respect to the group operation.

    If the metric on the underlying manifold is bi-invariant then it is equivalent to the Levi-Civita connection of that metric.

    source
    Base.expMethod
    exp(M::ConnectionManifold{𝔽,<:AbstractDecoratorManifold{𝔽},<:AbstractCartanSchoutenConnection}, p, X) where {𝔽}

    Compute the exponential map on the ConnectionManifold M with a Cartan-Schouten connection. See Sections 5.3.2 and 5.3.3 of [Pennec2020] for details.

    source
    Base.logMethod
    log(M::ConnectionManifold{𝔽,<:AbstractDecoratorManifold{𝔽},<:AbstractCartanSchoutenConnection}, p, q) where {𝔽}

    Compute the logarithmic map on the ConnectionManifold M with a Cartan-Schouten connection. See Sections 5.3.2 and 5.3.3 of [Pennec2020] for details.

    source
    • Suhubi2013

      E. Suhubi, Exterior Analysis: Using Applications of Differential Forms, 1st edition. Amsterdam: Academic Press, 2013.

    • AndruchowLarotondaRechtVarela2014

      Andruchow E., Larotonda G., Recht L., and Varela A.: “The left invariant metric in the general linear group”, Journal of Geometry and Physics 86, pp. 241-257, 2014. doi: 10.1016/j.geomphys.2014.08.009, arXiv: 1109.0520v1.

    • MartinNeff2016

      Martin, R. J. and Neff, P.: “Minimal geodesics on GL(n) for left-invariant, right-O(n)-invariant Riemannian metrics”, Journal of Geometric Mechanics 8(3), pp. 323-357, 2016. doi: 10.3934/jgm.2016010, arXiv: 1409.7849v2.

    • BinzPods2008

      E. Binz and S. Pods, The Geometry of Heisenberg Groups: With Applications in Signal Theory, Optics, Quantization, and Field Quantization. American Mathematical Soc., 2008.

    • Gallier2002

      Gallier J.; Xu D.; Computing exponentials of skew-symmetric matrices and logarithms of orthogonal matrices. International Journal of Robotics and Automation (2002), 17(4), pp. 1-11. pdf.

    • Andrica2013

      Andrica D.; Rohan R.-A.; Computing the Rodrigues coefficients of the exponential map of the Lie groups of matrices. Balkan Journal of Geometry and Its Applications (2013), 18(2), pp. 1-2. pdf.

    • RicoMartinez1988

      Rico Martinez, J. M., “Representations of the Euclidean group and its applications to the kinematics of spatial chains,” PhD Thesis, University of Florida, 1988.

    • Srivastava2016

      A. Srivastava and E. P. Klassen, Functional and Shape Data Analysis. Springer New York, 2016. ISBN: 978-1-4939-4018-9. doi: 10.1007/978-1-4939-4020-2.

    • Pennec2020

      X. Pennec and M. Lorenzi, “5 - Beyond Riemannian geometry: The affine connection setting for transformation groups,” in Riemannian Geometric Statistics in Medical Image Analysis, X. Pennec, S. Sommer, and T. Fletcher, Eds. Academic Press, 2020, pp. 169–229. doi: 10.1016/B978-0-12-814725-2.00012-1.

    diff --git a/previews/PR644/manifolds/hyperbolic.html b/previews/PR644/manifolds/hyperbolic.html new file mode 100644 index 0000000000..a77ee67492 --- /dev/null +++ b/previews/PR644/manifolds/hyperbolic.html @@ -0,0 +1,6827 @@ + +Hyperbolic space · Manifolds.jl

    Hyperbolic space

    The hyperbolic space can be represented in three different models.

    In the following the common functions are collected.

    A function in this general section uses vectors interpreted as if in the hyperboloid model, and other representations usually just convert to this representation to use these general functions.

    Manifolds.HyperbolicType
    Hyperbolic{N} <: AbstractDecoratorManifold{ℝ}

    The hyperbolic space $\mathcal H^n$ represented by $n+1$-Tuples, i.e. embedded in the Lorentzian manifold equipped with the MinkowskiMetric $⟨\cdot,\cdot⟩_{\mathrm{M}}$. The space is defined as

    \[\mathcal H^n = \Bigl\{p ∈ ℝ^{n+1}\ \Big|\ ⟨p,p⟩_{\mathrm{M}}= -p_{n+1}^2 + + \displaystyle\sum_{k=1}^n p_k^2 = -1, p_{n+1} > 0\Bigr\},.\]

    The tangent space $T_p \mathcal H^n$ is given by

    \[T_p \mathcal H^n := \bigl\{ +X ∈ ℝ^{n+1} : ⟨p,X⟩_{\mathrm{M}} = 0 +\bigr\}.\]

    Note that while the MinkowskiMetric renders the Lorentz manifold (only) pseudo-Riemannian, on the tangent bundle of the Hyperbolic space it induces a Riemannian metric. The corresponding sectional curvature is $-1$.

    If p and X are Vectors of length n+1 they are assumed to be a HyperboloidPoint and a HyperboloidTVector, respectively

    Other models are the Poincaré ball model, see PoincareBallPoint and PoincareBallTVector, respectiely and the Poincaré half space model, see PoincareHalfSpacePoint and PoincareHalfSpaceTVector, respectively.

    Constructor

    Hyperbolic(n)

    Generate the Hyperbolic manifold of dimension n.

    source
    Manifolds.HyperboloidPointType
    HyperboloidPoint <: AbstractManifoldPoint

    In the Hyperboloid model of the Hyperbolic $\mathcal H^n$ points are represented as vectors in $ℝ^{n+1}$ with MinkowskiMetric equal to $-1$.

    This representation is the default, i.e. AbstractVectors are assumed to have this repesentation.

    source
    Manifolds.HyperboloidTVectorType
    HyperboloidTVector <: TVector

    In the Hyperboloid model of the Hyperbolic $\mathcal H^n$ tangent vctors are represented as vectors in $ℝ^{n+1}$ with MinkowskiMetric $⟨p,X⟩_{\mathrm{M}}=0$ to their base point $p$.

    This representation is the default, i.e. vectors are assumed to have this repesentation.

    source
    Base.expMethod
    exp(M::Hyperbolic, p, X)

    Compute the exponential map on the Hyperbolic space $\mathcal H^n$ emanating from p towards X. The formula reads

    \[\exp_p X = \cosh(\sqrt{⟨X,X⟩_{\mathrm{M}}})p ++ \sinh(\sqrt{⟨X,X⟩_{\mathrm{M}}})\frac{X}{\sqrt{⟨X,X⟩_{\mathrm{M}}}},\]

    where $⟨\cdot,\cdot⟩_{\mathrm{M}}$ denotes the MinkowskiMetric on the embedding, the Lorentzian manifold.

    source
    Base.logMethod
    log(M::Hyperbolic, p, q)

    Compute the logarithmic map on the Hyperbolic space $\mathcal H^n$, the tangent vector representing the geodesic starting from p reaches q after time 1. The formula reads for $p ≠ q$

    \[\log_p q = d_{\mathcal H^n}(p,q) +\frac{q-⟨p,q⟩_{\mathrm{M}} p}{\lVert q-⟨p,q⟩_{\mathrm{M}} p \rVert_2},\]

    where $⟨\cdot,\cdot⟩_{\mathrm{M}}$ denotes the MinkowskiMetric on the embedding, the Lorentzian manifold. For $p=q$ the logarihmic map is equal to the zero vector.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::Hyperbolic, p; kwargs...)

    Check whether p is a valid point on the Hyperbolic M.

    For the HyperboloidPoint or plain vectors this means that, p is a vector of length $n+1$ with inner product in the embedding of -1, see MinkowskiMetric. The tolerance for the last test can be set using the kwargs....

    For the PoincareBallPoint a valid point is a vector $p ∈ ℝ^n$ with a norm stricly less than 1.

    For the PoincareHalfSpacePoint a valid point is a vector from $p ∈ ℝ^n$ with a positive last entry, i.e. $p_n>0$

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::Hyperbolic{n}, p, X; kwargs... )

    Check whether X is a tangent vector to p on the Hyperbolic M, i.e. after check_point(M,p), X has to be of the same dimension as p. The tolerance for the last test can be set using the kwargs....

    For a the hyperboloid model or vectors, X has to be orthogonal to p with respect to the inner product from the embedding, see MinkowskiMetric.

    For a the Poincaré ball as well as the Poincaré half plane model, X has to be a vector from $ℝ^{n}$.

    source
    ManifoldsBase.parallel_transport_toMethod
    parallel_transport_to(M::Hyperbolic, p, X, q)

    Compute the paralllel transport of the X from the tangent space at p on the Hyperbolic space $\mathcal H^n$ to the tangent at q along the geodesic connecting p and q. The formula reads

    \[\mathcal P_{q←p}X = X - \frac{⟨\log_p q,X⟩_p}{d^2_{\mathcal H^n}(p,q)} +\bigl(\log_p q + \log_qp \bigr),\]

    where $⟨\cdot,\cdot⟩_p$ denotes the inner product in the tangent space at p.

    source
    ManifoldsBase.projectMethod
    project(M::Hyperbolic, p, X)

    Perform an orthogonal projection with respect to the Minkowski inner product of X onto the tangent space at p of the Hyperbolic space M.

    The formula reads

    \[Y = X + ⟨p,X⟩_{\mathrm{M}} p,\]

    where $⟨\cdot, \cdot⟩_{\mathrm{M}}$ denotes the MinkowskiMetric on the embedding, the Lorentzian manifold.

    Note

    Projection is only available for the (default) HyperboloidTVector representation, the others don't have such an embedding

    source

    hyperboloid model

    Base.convertMethod
    convert(::Type{HyperboloidPoint}, p::PoincareBallPoint)
    +convert(::Type{AbstractVector}, p::PoincareBallPoint)

    convert a point PoincareBallPoint x (from $ℝ^n$) from the Poincaré ball model of the Hyperbolic manifold $\mathcal H^n$ to a HyperboloidPoint $π(p) ∈ ℝ^{n+1}$. The isometry is defined by

    \[π(p) = \frac{1}{1-\lVert p \rVert^2} +\begin{pmatrix}2p_1\\⋮\\2p_n\\1+\lVert p \rVert^2\end{pmatrix}\]

    Note that this is also used, when the type to convert to is a vector.

    source
    Base.convertMethod
    convert(::Type{HyperboloidPoint}, p::PoincareHalfSpacePoint)
    +convert(::Type{AbstractVector}, p::PoincareHalfSpacePoint)

    convert a point PoincareHalfSpacePoint p (from $ℝ^n$) from the Poincaré half plane model of the Hyperbolic manifold $\mathcal H^n$ to a HyperboloidPoint $π(p) ∈ ℝ^{n+1}$.

    This is done in two steps, namely transforming it to a Poincare ball point and from there further on to a Hyperboloid point.

    source
    Base.convertMethod
    convert(::Type{HyperboloidTVector}, p::PoincareBallPoint, X::PoincareBallTVector)
    +convert(::Type{AbstractVector}, p::PoincareBallPoint, X::PoincareBallTVector)

    Convert the PoincareBallTVector X from the tangent space at p to a HyperboloidTVector by computing the push forward of the isometric map, cf. convert(::Type{HyperboloidPoint}, p::PoincareBallPoint).

    The push forward $π_*(p)$ maps from $ℝ^n$ to a subspace of $ℝ^{n+1}$, the formula reads

    \[π_*(p)[X] = \begin{pmatrix} + \frac{2X_1}{1-\lVert p \rVert^2} + \frac{4}{(1-\lVert p \rVert^2)^2}⟨X,p⟩p_1\\ + ⋮\\ + \frac{2X_n}{1-\lVert p \rVert^2} + \frac{4}{(1-\lVert p \rVert^2)^2}⟨X,p⟩p_n\\ + \frac{4}{(1-\lVert p \rVert^2)^2}⟨X,p⟩ +\end{pmatrix}.\]

    source
    Base.convertMethod
    convert(::Type{HyperboloidTVector}, p::PoincareHalfSpacePoint, X::PoincareHalfSpaceTVector)
    +convert(::Type{AbstractVector}, p::PoincareHalfSpacePoint, X::PoincareHalfSpaceTVector)

    convert a point PoincareHalfSpaceTVector X (from $ℝ^n$) at p from the Poincaré half plane model of the Hyperbolic manifold $\mathcal H^n$ to a HyperboloidTVector $π(p) ∈ ℝ^{n+1}$.

    This is done in two steps, namely transforming it to a Poincare ball point and from there further on to a Hyperboloid point.

    source
    Base.convertMethod
    convert(
    +    ::Type{Tuple{HyperboloidPoint,HyperboloidTVector}}.
    +    (p,X)::Tuple{PoincareBallPoint,PoincareBallTVector}
    +)
    +convert(
    +    ::Type{Tuple{P,T}},
    +    (p, X)::Tuple{PoincareBallPoint,PoincareBallTVector},
    +) where {P<:AbstractVector, T <: AbstractVector}

    Convert a PoincareBallPoint p and a PoincareBallTVector X to a HyperboloidPoint and a HyperboloidTVector simultaneously, see convert(::Type{HyperboloidPoint}, ::PoincareBallPoint) and convert(::Type{HyperboloidTVector}, ::PoincareBallPoint, ::PoincareBallTVector) for the formulae.

    source
    Base.convertMethod
    convert(
    +    ::Type{Tuple{HyperboloidPoint,HyperboloidTVector},
    +    (p,X)::Tuple{PoincareHalfSpacePoint, PoincareHalfSpaceTVector}
    +)
    +convert(
    +    ::Type{Tuple{T,T},
    +    (p,X)::Tuple{PoincareHalfSpacePoint, PoincareHalfSpaceTVector}
    +) where {T<:AbstractVector}

    convert a point PoincareHalfSpaceTVector X (from $ℝ^n$) at p from the Poincaré half plane model of the Hyperbolic manifold $\mathcal H^n$ to a tuple of a HyperboloidPoint and a HyperboloidTVector $π(p) ∈ ℝ^{n+1}$ simultaneously.

    This is done in two steps, namely transforming it to the Poincare ball model and from there further on to a Hyperboloid.

    source
    ManifoldDiff.riemannian_HessianMethod
    riemannian_Hessian(M::Hyperbolic, p, G, H, X)

    The Riemannian Hessian can be computed by adopting Remark 4.1 in [Ngu23]. Let $\nabla f(p)$ denote the Euclidean gradient G, $\nabla^2 f(p)[X]$ the Euclidean Hessian H, and $\mathbf{g} = \mathbf{g}^{-1} = \operatorname{diag}(1,...,1,-1)$. The formula reads

    \[ \operatorname{Hess}f(p)[X] + = + \operatorname{proj}_{T_p\mathcal M}\bigl( \mathbf{g}^-1\nabla^2f(p)[X] + X⟨p,\mathbf{g}^{-1}∇f(p)⟩_p\bigr).\]

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::Hyperbolic{n}, ::EuclideanMetric, p, X)

    Change the Eucliden representer X of a cotangent vector at point p. We only have to correct for the metric, which means that the sign of the last entry changes, since for the result $Y$ we are looking for a tangent vector such that

    \[ g_p(Y,Z) = -y_{n+1}z_{n+1} + \sum_{i=1}^n y_iz_i = \sum_{i=1}^{n+1} z_ix_i\]

    holds, which directly yields $y_i=x_i$ for $i=1,\ldots,n$ and $y_{n+1}=-x_{n+1}$.

    source
    ManifoldsBase.distanceMethod
    distance(M::Hyperbolic, p, q)
    +distance(M::Hyperbolic, p::HyperboloidPoint, q::HyperboloidPoint)

    Compute the distance on the Hyperbolic M, which reads

    \[d_{\mathcal H^n}(p,q) = \operatorname{acosh}( - ⟨p, q⟩_{\mathrm{M}}),\]

    where $⟨\cdot,\cdot⟩_{\mathrm{M}}$ denotes the MinkowskiMetric on the embedding, the Lorentzian manifold.

    source
    ManifoldsBase.get_coordinatesMethod
    get_coordinates(M::Hyperbolic, p, X, ::DefaultOrthonormalBasis)

    Compute the coordinates of the vector X with respect to the orthogonalized version of the unit vectors from $ℝ^n$, where $n$ is the manifold dimension of the Hyperbolic M, utting them intop the tangent space at p and orthonormalizing them.

    source
    ManifoldsBase.get_vectorMethod
    get_vector(M::Hyperbolic, p, c, ::DefaultOrthonormalBasis)

    Compute the vector from the coordinates with respect to the orthogonalized version of the unit vectors from $ℝ^n$, where $n$ is the manifold dimension of the Hyperbolic M, utting them intop the tangent space at p and orthonormalizing them.

    source
    ManifoldsBase.innerMethod
    inner(M::Hyperbolic{n}, p, X, Y)
    +inner(M::Hyperbolic{n}, p::HyperboloidPoint, X::HyperboloidTVector, Y::HyperboloidTVector)

    Cmpute the inner product in the Hyperboloid model, i.e. the minkowski_metric in the embedding. The formula reads

    \[g_p(X,Y) = ⟨X,Y⟩_{\mathrm{M}} = -X_{n}Y_{n} + \displaystyle\sum_{k=1}^{n-1} X_kY_k.\]

    This employs the metric of the embedding, see Lorentz space.

    source

    Visualization of the Hyperboloid

    For the case of Hyperbolic(2) there is plotting available based on a PlottingRecipe. You can easily plot points, connecting geodesics as well as tangent vectors.

    Note

    The recipes are only loaded if Plots.jl or RecipesBase.jl is loaded.

    If we consider a set of points, we can first plot these and their connecting geodesics using the geodesic_interpolation for the points. This variable specifies with how many points a geodesic between two successive points is sampled (per default it's -1, which deactivates geodesics) and the line style is set to be a path.

    In general you can plot the surface of the hyperboloid either as wireframe (wireframe=true) additionally specifying wires (or wires_x and wires_y) to change the density of wires and a wireframe_color. The same holds for the plot as a surface (which is false by default) and its surface_resolution (or surface_resolution_x or surface_resolution_y) and a surface_color.

    using Manifolds, Plots
    +M = Hyperbolic(2)
    +pts =  [ [0.85*cos(φ), 0.85*sin(φ), sqrt(0.85^2+1)] for φ ∈ range(0,2π,length=11) ]
    +scene = plot(M, pts; geodesic_interpolation=100)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    To just plot the points atop, we can just omit the geodesic_interpolation parameter to obtain a scatter plot. Note that we avoid redrawing the wireframe in the following plot! calls.

    plot!(scene, M, pts; wireframe=false)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    We can further generate tangent vectors in these spaces and use a plot for there. Keep in mind that a tangent vector in plotting always requires its base point.

    pts2 = [ [0.45 .*cos(φ + 6π/11), 0.45 .*sin(φ + 6π/11), sqrt(0.45^2+1) ] for φ ∈ range(0,2π,length=11)]
    +vecs = log.(Ref(M),pts,pts2)
    +plot!(scene, M, pts, vecs; wireframe=false)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Just to illustrate, for the first point the tangent vector is pointing along the following geodesic

    plot!(scene, M, [pts[1], pts2[1]]; geodesic_interpolation=100, wireframe=false)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Internal functions

    The following functions are available for internal use to construct points in the hyperboloid model

    Manifolds._hyperbolizeMethod
    _hyperbolize(M, p, Y)

    Given the Hyperbolic(n) manifold using the hyperboloid model and a point p thereon, we can put a vector $Y\in ℝ^n$ into the tangent space by computing its last component such that for the resulting p we have that its minkowski_metric is $⟨p,X⟩_{\mathrm{M}} = 0$, i.e. $X_{n+1} = \frac{⟨\tilde p, Y⟩}{p_{n+1}}$, where $\tilde p = (p_1,\ldots,p_n)$.

    source
    Manifolds._hyperbolizeMethod
    _hyperbolize(M, q)

    Given the Hyperbolic(n) manifold using the hyperboloid model, a point from the $q\in ℝ^n$ can be set onto the manifold by computing its last component such that for the resulting p we have that its minkowski_metric is $⟨p,p⟩_{\mathrm{M}} = - 1$, i.e. $p_{n+1} = \sqrt{\lVert q \rVert^2 - 1}$

    source

    Poincaré ball model

    Base.convertMethod
    convert(::Type{PoincareBallPoint}, p::HyperboloidPoint)
    +convert(::Type{PoincareBallPoint}, p::T) where {T<:AbstractVector}

    convert a HyperboloidPoint $p∈ℝ^{n+1}$ from the hyperboloid model of the Hyperbolic manifold $\mathcal H^n$ to a PoincareBallPoint $π(p)∈ℝ^{n}$ in the Poincaré ball model. The isometry is defined by

    \[π(p) = \frac{1}{1+p_{n+1}} \begin{pmatrix}p_1\\⋮\\p_n\end{pmatrix}\]

    Note that this is also used, when x is a vector.

    source
    Base.convertMethod
    convert(::Type{PoincareBallPoint}, p::PoincareHalfSpacePoint)

    convert a point PoincareHalfSpacePoint p (from $ℝ^n$) from the Poincaré half plane model of the Hyperbolic manifold $\mathcal H^n$ to a PoincareBallPoint $π(p) ∈ ℝ^n$. Denote by $\tilde p = (p_1,\ldots,p_{d-1})^{\mathrm{T}}$. Then the isometry is defined by

    \[π(p) = \frac{1}{\lVert \tilde p \rVert^2 + (p_n+1)^2} +\begin{pmatrix}2p_1\\⋮\\2p_{n-1}\\\lVert p\rVert^2 - 1\end{pmatrix}.\]

    source
    Base.convertMethod
    convert(::Type{PoincareBallTVector}, p::HyperboloidPoint, X::HyperboloidTVector)
    +convert(::Type{PoincareBallTVector}, p::P, X::T) where {P<:AbstractVector, T<:AbstractVector}

    convert a HyperboloidTVector X at p to a PoincareBallTVector on the Hyperbolic manifold $\mathcal H^n$ by computing the push forward $π_*(p)[X]$ of the isometry $π$ that maps from the Hyperboloid to the Poincaré ball, cf. convert(::Type{PoincareBallPoint}, ::HyperboloidPoint).

    The formula reads

    \[π_*(p)[X] = \frac{1}{p_{n+1}+1}\Bigl(\tilde X - \frac{X_{n+1}}{p_{n+1}+1}\tilde p \Bigl),\]

    where $\tilde X = \begin{pmatrix}X_1\\⋮\\X_n\end{pmatrix}$ and $\tilde p = \begin{pmatrix}p_1\\⋮\\p_n\end{pmatrix}$.

    source
    Base.convertMethod
    convert(
    +    ::Type{PoincareBallTVector},
    +    p::PoincareHalfSpacePoint,
    +    X::PoincareHalfSpaceTVector
    +)

    convert a PoincareHalfSpaceTVector X at p to a PoincareBallTVector on the Hyperbolic manifold $\mathcal H^n$ by computing the push forward $π_*(p)[X]$ of the isometry $π$ that maps from the Poincaré half space to the Poincaré ball, cf. convert(::Type{PoincareBallPoint}, ::PoincareHalfSpacePoint).

    The formula reads

    \[π_*(p)[X] = +\frac{1}{\lVert \tilde p\rVert^2 + (1+p_n)^2} +\begin{pmatrix} +2X_1\\ +⋮\\ +2X_{n-1}\\ +2⟨X,p⟩ +\end{pmatrix} +- +\frac{2}{(\lVert \tilde p\rVert^2 + (1+p_n)^2)^2} +\begin{pmatrix} +2p_1(⟨X,p⟩+X_n)\\ +⋮\\ +2p_{n-1}(⟨X,p⟩+X_n)\\ +(\lVert p \rVert^2-1)(⟨X,p⟩+X_n) +\end{pmatrix}\]

    where $\tilde p = \begin{pmatrix}p_1\\⋮\\p_{n-1}\end{pmatrix}$.

    source
    Base.convertMethod
    convert(
    +    ::Type{Tuple{PoincareBallPoint,PoincareBallTVector}},
    +    (p,X)::Tuple{HyperboloidPoint,HyperboloidTVector}
    +)
    +convert(
    +    ::Type{Tuple{PoincareBallPoint,PoincareBallTVector}},
    +    (p, X)::Tuple{P,T},
    +) where {P<:AbstractVector, T <: AbstractVector}

    Convert a HyperboloidPoint p and a HyperboloidTVector X to a PoincareBallPoint and a PoincareBallTVector simultaneously, see convert(::Type{PoincareBallPoint}, ::HyperboloidPoint) and convert(::Type{PoincareBallTVector}, ::HyperboloidPoint, ::HyperboloidTVector) for the formulae.

    source
    Base.convertMethod
    convert(
    +    ::Type{Tuple{PoincareBallPoint,PoincareBallTVector}},
    +    (p,X)::Tuple{HyperboloidPoint,HyperboloidTVector}
    +)
    +convert(
    +    ::Type{Tuple{PoincareBallPoint,PoincareBallTVector}},
    +    (p, X)::Tuple{T,T},
    +) where {T <: AbstractVector}

    Convert a PoincareHalfSpacePoint p and a PoincareHalfSpaceTVector X to a PoincareBallPoint and a PoincareBallTVector simultaneously, see convert(::Type{PoincareBallPoint}, ::PoincareHalfSpacePoint) and convert(::Type{PoincareBallTVector}, ::PoincareHalfSpacePoint, ::PoincareHalfSpaceTVector) for the formulae.

    source
    ManifoldsBase.change_metricMethod
    change_metric(M::Hyperbolic{n}, ::EuclideanMetric, p::PoincareBallPoint, X::PoincareBallTVector)

    Since in the metric we always have the term $α = \frac{2}{1-\sum_{i=1}^n p_i^2}$ per element, the correction for the metric reads $Z = \frac{1}{α}X$.

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::Hyperbolic{n}, ::EuclideanMetric, p::PoincareBallPoint, X::PoincareBallTVector)

    Since in the metric we have the term $α = \frac{2}{1-\sum_{i=1}^n p_i^2}$ per element, the correction for the gradient reads $Y = \frac{1}{α^2}X$.

    source
    ManifoldsBase.distanceMethod
    distance(::Hyperbolic, p::PoincareBallPoint, q::PoincareBallPoint)

    Compute the distance on the Hyperbolic manifold $\mathcal H^n$ represented in the Poincaré ball model. The formula reads

    \[d_{\mathcal H^n}(p,q) = +\operatorname{acosh}\Bigl( + 1 + \frac{2\lVert p - q \rVert^2}{(1-\lVert p\rVert^2)(1-\lVert q\rVert^2)} +\Bigr)\]

    source
    ManifoldsBase.innerMethod
    inner(::Hyperbolic, p::PoincareBallPoint, X::PoincareBallTVector, Y::PoincareBallTVector)

    Compute the inner producz in the Poincaré ball model. The formula reads

    \[g_p(X,Y) = \frac{4}{(1-\lVert p \rVert^2)^2} ⟨X, Y⟩ .\]

    source
    ManifoldsBase.projectMethod
    project(::Hyperbolic, ::PoincareBallPoint, ::PoincareBallTVector)

    projction of tangent vectors in the Poincaré ball model is just the identity, since the tangent space consists of all $ℝ^n$.

    source

    Visualization of the Poincaré ball

    For the case of Hyperbolic(2) there is a plotting available based on a PlottingRecipe you can easily plot points, connecting geodesics as well as tangent vectors.

    Note

    The recipes are only loaded if Plots.jl or RecipesBase.jl is loaded.

    If we consider a set of points, we can first plot these and their connecting geodesics using the geodesic_interpolation For the points. This variable specifies with how many points a geodesic between two successive points is sampled (per default it's -1, which deactivates geodesics) and the line style is set to be a path. Another keyword argument added is the border of the Poincaré disc, namely circle_points = 720 resolution of the drawn boundary (every hlaf angle) as well as its color, hyperbolic_border_color = RGBA(0.0, 0.0, 0.0, 1.0).

    using Manifolds, Plots
    +M = Hyperbolic(2)
    +pts = PoincareBallPoint.( [0.85 .* [cos(φ), sin(φ)] for φ ∈ range(0,2π,length=11)])
    +scene = plot(M, pts, geodesic_interpolation = 100)
    + + + + + + + + + + + + + + + + + + + + + + + + +

    To just plot the points atop, we can just omit the geodesic_interpolation parameter to obtain a scatter plot

    plot!(scene, M, pts)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    We can further generate tangent vectors in these spaces and use a plot for there. Keep in mind, that a tangent vector in plotting always requires its base point

    pts2 = PoincareBallPoint.( [0.45 .* [cos(φ + 6π/11), sin(φ + 6π/11)] for φ ∈ range(0,2π,length=11)])
    +vecs = log.(Ref(M),pts,pts2)
    +plot!(scene, M, pts,vecs)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Just to illustrate, for the first point the tangent vector is pointing along the following geodesic

    plot!(scene, M, [pts[1], pts2[1]], geodesic_interpolation=100)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Poincaré half space model

    Base.convertMethod
    convert(::Type{PoincareHalfSpacePoint}, p::Hyperboloid)
    +convert(::Type{PoincareHalfSpacePoint}, p)

    convert a HyperboloidPoint or Vectorp (from $ℝ^{n+1}$) from the Hyperboloid model of the Hyperbolic manifold $\mathcal H^n$ to a PoincareHalfSpacePoint $π(x) ∈ ℝ^{n}$.

    This is done in two steps, namely transforming it to a Poincare ball point and from there further on to a PoincareHalfSpacePoint point.

    source
    Base.convertMethod
    convert(::Type{PoincareHalfSpacePoint}, p::PoincareBallPoint)

    convert a point PoincareBallPoint p (from $ℝ^n$) from the Poincaré ball model of the Hyperbolic manifold $\mathcal H^n$ to a PoincareHalfSpacePoint $π(p) ∈ ℝ^n$. Denote by $\tilde p = (p_1,\ldots,p_{n-1})$. Then the isometry is defined by

    \[π(p) = \frac{1}{\lVert \tilde p \rVert^2 - (p_n-1)^2} +\begin{pmatrix}2p_1\\⋮\\2p_{n-1}\\1-\lVert p\rVert^2\end{pmatrix}.\]

    source
    Base.convertMethod
    convert(::Type{PoincareHalfSpaceTVector}, p::HyperboloidPoint, ::HyperboloidTVector)
    +convert(::Type{PoincareHalfSpaceTVector}, p::P, X::T) where {P<:AbstractVector, T<:AbstractVector}

    convert a HyperboloidTVector X at p to a PoincareHalfSpaceTVector on the Hyperbolic manifold $\mathcal H^n$ by computing the push forward $π_*(p)[X]$ of the isometry $π$ that maps from the Hyperboloid to the Poincaré half space, cf. convert(::Type{PoincareHalfSpacePoint}, ::HyperboloidPoint).

    This is done similarly to the approach there, i.e. by using the Poincaré ball model as an intermediate step.

    source
    Base.convertMethod
    convert(::Type{PoincareHalfSpaceTVector}, p::PoincareBallPoint, X::PoincareBallTVector)

    convert a PoincareBallTVector X at p to a PoincareHalfSpacePoint on the Hyperbolic manifold $\mathcal H^n$ by computing the push forward $π_*(p)[X]$ of the isometry $π$ that maps from the Poincaré ball to the Poincaré half space, cf. convert(::Type{PoincareHalfSpacePoint}, ::PoincareBallPoint).

    The formula reads

    \[π_*(p)[X] = +\frac{1}{\lVert \tilde p\rVert^2 + (1-p_n)^2} +\begin{pmatrix} +2X_1\\ +⋮\\ +2X_{n-1}\\ +-2⟨X,p⟩ +\end{pmatrix} +- +\frac{2}{(\lVert \tilde p\rVert^2 + (1-p_n)^2)^2} +\begin{pmatrix} +2p_1(⟨X,p⟩-X_n)\\ +⋮\\ +2p_{n-1}(⟨X,p⟩-X_n)\\ +(\lVert p \rVert^2-1)(⟨X,p⟩-X_n) +\end{pmatrix}\]

    where $\tilde p = \begin{pmatrix}p_1\\⋮\\p_{n-1}\end{pmatrix}$.

    source
    Base.convertMethod
    convert(
    +    ::Type{Tuple{PoincareHalfSpacePoint,PoincareHalfSpaceTVector}},
    +    (p,X)::Tuple{HyperboloidPoint,HyperboloidTVector}
    +)
    +convert(
    +    ::Type{Tuple{PoincareHalfSpacePoint,PoincareHalfSpaceTVector}},
    +    (p, X)::Tuple{P,T},
    +) where {P<:AbstractVector, T <: AbstractVector}

    Convert a HyperboloidPoint p and a HyperboloidTVector X to a PoincareHalfSpacePoint and a PoincareHalfSpaceTVector simultaneously, see convert(::Type{PoincareHalfSpacePoint}, ::HyperboloidPoint) and convert(::Type{PoincareHalfSpaceTVector}, ::Tuple{HyperboloidPoint,HyperboloidTVector}) for the formulae.

    source
    ManifoldsBase.distanceMethod
    distance(::Hyperbolic, p::PoincareHalfSpacePoint, q::PoincareHalfSpacePoint)

    Compute the distance on the Hyperbolic manifold $\mathcal H^n$ represented in the Poincaré half space model. The formula reads

    \[d_{\mathcal H^n}(p,q) = \operatorname{acosh}\Bigl( 1 + \frac{\lVert p - q \rVert^2}{2 p_n q_n} \Bigr)\]

    source
    ManifoldsBase.innerMethod
    inner(
    +    ::Hyperbolic{n},
    +    p::PoincareHalfSpacePoint,
    +    X::PoincareHalfSpaceTVector,
    +    Y::PoincareHalfSpaceTVector
    +)

    Compute the inner product in the Poincaré half space model. The formula reads

    \[g_p(X,Y) = \frac{⟨X,Y⟩}{p_n^2}.\]

    source
    ManifoldsBase.projectMethod
    project(::Hyperbolic, ::PoincareHalfSpacePoint ::PoincareHalfSpaceTVector)

    projction of tangent vectors in the Poincaré half space model is just the identity, since the tangent space consists of all $ℝ^n$.

    source

    Visualization on the Poincaré half plane

    For the case of Hyperbolic(2) there is a plotting available based on a PlottingRecipe you can easily plot points, connecting geodesics as well as tangent vectors.

    Note

    The recipes are only loaded if Plots.jl or RecipesBase.jl is loaded.

    We again have two different recipes, one for points, one for tangent vectors, where the first one again can be equipped with geodesics between the points. In the following example we generate 7 points on an ellipse in the Hyperboloid model.

    using Manifolds, Plots
    +M = Hyperbolic(2)
    +pre_pts = [2.0 .* [5.0*cos(φ), sin(φ)] for φ ∈ range(0,2π,length=7)]
    +pts = convert.(
    +    Ref(PoincareHalfSpacePoint),
    +    Manifolds._hyperbolize.(Ref(M), pre_pts)
    +)
    +scene = plot(M, pts, geodesic_interpolation = 100)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    To just plot the points atop, we can just omit the geodesic_interpolation parameter to obtain a scatter plot

    plot!(scene, M, pts)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    We can further generate tangent vectors in these spaces and use a plot for there. Keep in mind, that a tangent vector in plotting always requires its base point. Here we would like to look at the tangent vectors pointing to the origin

    origin = PoincareHalfSpacePoint([0.0,1.0])
    +vecs = [log(M,p,origin) for p ∈ pts]
    +scene = plot!(scene, M, pts, vecs)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    And we can again look at the corresponding geodesics, for example

    plot!(scene, M, [pts[1], origin], geodesic_interpolation=100)
    +plot!(scene, M, [pts[2], origin], geodesic_interpolation=100)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Literature

    [Ngu23]
    +
    +
    D. Nguyen. Operator-Valued Formulas for Riemannian Gradient and Hessian and Families of Tractable Metrics in Riemannian Optimization. Journal of Optimization Theory and Applications 198, 135–164 (2023).
    +
    +
    diff --git a/previews/PR644/manifolds/lorentz.html b/previews/PR644/manifolds/lorentz.html new file mode 100644 index 0000000000..d5c3373f9c --- /dev/null +++ b/previews/PR644/manifolds/lorentz.html @@ -0,0 +1,3 @@ + +Lorentzian manifold · Manifolds.jl

    Lorentzian Manifold

    The Lorentz manifold is a pseudo-Riemannian manifold. It is named after the Dutch physicist Hendrik Lorentz (1853–1928). The default LorentzMetric is the MinkowskiMetric named after the German mathematician Hermann Minkowski (1864–1909).

    Within Manifolds.jl it is used as the embedding of the Hyperbolic space.

    Manifolds.LorentzType
    Lorentz{N} = MetricManifold{Euclidean{N,ℝ},LorentzMetric}

    The Lorentz manifold (or Lorentzian) is a pseudo-Riemannian manifold.

    Constructor

    Lorentz(n[, metric=MinkowskiMetric()])

    Generate the Lorentz manifold of dimension n with the LorentzMetric m, which is by default set to the MinkowskiMetric.

    source
    Manifolds.LorentzMetricType
    LorentzMetric <: AbstractMetric

    Abstract type for Lorentz metrics, which have a single time dimension. These metrics assume the spacelike convention with the time dimension being last, giving the signature $(++...+-)$.

    source
    Manifolds.minkowski_metricMethod
    minkowski_metric(a,b)

    Compute the minkowski metric on $\mathbb R^n$ is given by

    \[⟨a,b⟩_{\mathrm{M}} = -a_{n}b_{n} + +\displaystyle\sum_{k=1}^{n-1} a_kb_k.\]

    source
    diff --git a/previews/PR644/manifolds/metric.html b/previews/PR644/manifolds/metric.html new file mode 100644 index 0000000000..6c3715ac38 --- /dev/null +++ b/previews/PR644/manifolds/metric.html @@ -0,0 +1,7 @@ + +Metric manifold · Manifolds.jl

    Metric manifold

    A Riemannian manifold always consists of a topological manifold together with a smoothly varying metric $g$.

    However, often there is an implicitly assumed (default) metric, like the usual inner product on Euclidean space. This decorator takes this into account. It is not necessary to use this decorator if you implement just one (or the first) metric. If you later introduce a second, the old (first) metric can be used with the (non MetricManifold) AbstractManifold, i.e. without an explicitly stated metric.

    This manifold decorator serves two purposes:

    1. to implement different metrics (e.g. in closed form) for one AbstractManifold
    2. to provide a way to compute geodesics on manifolds, where this AbstractMetric does not yield closed formula.

    Note that a metric manifold is has a IsConnectionManifold trait referring to the LeviCivitaConnection of the metric $g$, and thus a large part of metric manifold's functionality relies on this.

    Let's first look at the provided types.

    Types

    Manifolds.IsMetricManifoldType
    IsMetricManifold <: AbstractTrait

    Specify that a certain decorated Manifold is a metric manifold in the sence that it provides explicit metric properties, extending/changing the default metric properties of a manifold.

    source
    Manifolds.MetricManifoldType
    MetricManifold{𝔽,M<:AbstractManifold{𝔽},G<:AbstractMetric} <: AbstractDecoratorManifold{𝔽}

    Equip a AbstractManifold explicitly with an AbstractMetric G.

    For a Metric AbstractManifold, by default, assumes, that you implement the linear form from local_metric in order to evaluate the exponential map.

    If the corresponding AbstractMetric G yields closed form formulae for e.g. the exponential map and this is implemented directly (without solving the ode), you can of course still implement that directly.

    Constructor

    MetricManifold(M, G)

    Generate the AbstractManifold M as a manifold with the AbstractMetric G.

    source

    Implement Different Metrics on the same Manifold

    In order to distinguish different metrics on one manifold, one can introduce two AbstractMetrics and use this type to dispatch on the metric, see SymmetricPositiveDefinite. To avoid overhead, one AbstractMetric can then be marked as being the default, i.e. the one that is used, when no MetricManifold decorator is present. This avoids reimplementation of the first existing metric, access to the metric-dependent functions that were implemented using the undecorated manifold, as well as the transparent fallback of the corresponding MetricManifold with default metric to the undecorated implementations. This does not cause any runtime overhead. Introducing a default AbstractMetric serves a better readability of the code when working with different metrics.

    Implementation of Metrics

    For the case that a local_metric is implemented as a bilinear form that is positive definite, the following further functions are provided, unless the corresponding AbstractMetric is marked as default – then the fallbacks mentioned in the last section are used for e.g. the exponential map.

    Manifolds.det_local_metricMethod
    det_local_metric(M::AbstractManifold, p, B::AbstractBasis)

    Return the determinant of local matrix representation of the metric tensor $g$, i.e. of the matrix $G(p)$ representing the metric in the tangent space at $p$ with as a matrix.

    See also local_metric

    source
    Manifolds.flatMethod
    flat(N::MetricManifold{M,G}, p, X::TFVector)

    Compute the musical isomorphism to transform the tangent vector X from the AbstractManifold M equipped with AbstractMetric G to a cotangent by computing

    \[X^♭= G_p X,\]

    where $G_p$ is the local matrix representation of G, see local_metric

    source
    Manifolds.inverse_local_metricMethod
    inverse_local_metric(M::AbstractcManifold{𝔽}, p, B::AbstractBasis)

    Return the local matrix representation of the inverse metric (cometric) tensor of the tangent space at p on the AbstractManifold M with respect to the AbstractBasis basis B.

    The metric tensor (see local_metric) is usually denoted by $G = (g_{ij}) ∈ 𝔽^{d×d}$, where $d$ is the dimension of the manifold.

    Then the inverse local metric is denoted by $G^{-1} = g^{ij}$.

    source
    Manifolds.local_metricMethod
    local_metric(M::AbstractManifold{𝔽}, p, B::AbstractBasis)

    Return the local matrix representation at the point p of the metric tensor $g$ with respect to the AbstractBasis B on the AbstractManifold M. Let $d$denote the dimension of the manifold and $b_1,\ldots,b_d$ the basis vectors. Then the local matrix representation is a matrix $G\in 𝔽^{n\times n}$ whose entries are given by $g_{ij} = g_p(b_i,b_j), i,j\in\{1,…,d\}$.

    This yields the property for two tangent vectors (using Einstein summation convention) $X = X^ib_i, Y=Y^ib_i \in T_p\mathcal M$ we get $g_p(X, Y) = g_{ij} X^i Y^j$.

    source
    Manifolds.local_metric_jacobianMethod
    local_metric_jacobian(
    +    M::AbstractManifold,
    +    p,
    +    B::AbstractBasis;
    +    backend::AbstractDiffBackend,
    +)

    Get partial derivatives of the local metric of M at p in basis B with respect to the coordinates of p, $\frac{∂}{∂ p^k} g_{ij} = g_{ij,k}$. The dimensions of the resulting multi-dimensional array are ordered $(i,j,k)$.

    source
    Manifolds.log_local_metric_densityMethod
    log_local_metric_density(M::AbstractManifold, p, B::AbstractBasis)

    Return the natural logarithm of the metric density $ρ$ of M at p, which is given by $ρ = \log \sqrt{|\det [g_{ij}]|}$ for the metric tensor expressed in basis B.

    source
    Manifolds.ricci_curvatureMethod
    ricci_curvature(M::AbstractManifold, p, B::AbstractBasis; backend::AbstractDiffBackend = default_differential_backend())

    Compute the Ricci scalar curvature of the manifold M at the point p using basis B. The curvature is computed as the trace of the Ricci curvature tensor with respect to the metric, that is $R=g^{ij}R_{ij}$ where $R$ is the scalar Ricci curvature at p, $g^{ij}$ is the inverse local metric (see inverse_local_metric) at p and $R_{ij}$ is the Riccie curvature tensor, see ricci_tensor. Both the tensor and inverse local metric are expressed in local coordinates defined by B, and the formula uses the Einstein summation convention.

    source
    Manifolds.sharpMethod
    sharp(N::MetricManifold{M,G}, p, ξ::CoTFVector)

    Compute the musical isomorphism to transform the cotangent vector ξ from the AbstractManifold M equipped with AbstractMetric G to a tangent by computing

    \[ξ^♯ = G_p^{-1} ξ,\]

    where $G_p$ is the local matrix representation of G, i.e. one employs inverse_local_metric here to obtain $G_p^{-1}$.

    source
    ManifoldsBase.innerMethod
    inner(N::MetricManifold{M,G}, p, X, Y)

    Compute the inner product of X and Y from the tangent space at p on the AbstractManifold M using the AbstractMetric G. If M has G as its IsDefaultMetric trait, this is done using inner(M, p, X, Y), otherwise the local_metric(M, p) is employed as

    \[g_p(X, Y) = ⟨X, G_p Y⟩,\]

    where $G_p$ is the loal matrix representation of the AbstractMetric G.

    source

    Metrics, charts and bases of vector spaces

    Metric-related functions, similarly to connection-related functions, need to operate in a basis of a vector space, see here.

    Metric-related functions can take bases of associated tangent spaces as arguments. For example local_metric can take the basis of the tangent space it is supposed to operate on instead of a custom basis of the space of symmetric bilinear operators.

    diff --git a/previews/PR644/manifolds/multinomial.html b/previews/PR644/manifolds/multinomial.html new file mode 100644 index 0000000000..df3562988c --- /dev/null +++ b/previews/PR644/manifolds/multinomial.html @@ -0,0 +1,2 @@ + +Multinomial matrices · Manifolds.jl

    Multinomial matrices

    Manifolds.MultinomialMatricesType
    MultinomialMatrices{n,m} <: AbstractPowerManifold{ℝ}

    The multinomial manifold consists of m column vectors, where each column is of length n and unit norm, i.e.

    \[\mathcal{MN}(n,m) \coloneqq \bigl\{ p ∈ ℝ^{n×m}\ \big|\ p_{i,j} > 0 \text{ for all } i=1,…,n, j=1,…,m \text{ and } p^{\mathrm{T}}\mathbb{1}_m = \mathbb{1}_n\bigr\},\]

    where $\mathbb{1}_k$ is the vector of length $k$ containing ones.

    This yields exactly the same metric as considering the product metric of the probablity vectors, i.e. PowerManifold of the $(n-1)$-dimensional ProbabilitySimplex.

    The ProbabilitySimplex is stored internally within M.manifold, such that all functions of AbstractPowerManifold can be used directly.

    Constructor

    MultinomialMatrices(n, m)

    Generate the manifold of matrices $\mathbb R^{n×m}$ such that the $m$ columns are discrete probability distributions, i.e. sum up to one.

    source

    Functions

    Most functions are directly implemented for an AbstractPowerManifold with ArrayPowerRepresentation except the following special cases:

    diff --git a/previews/PR644/manifolds/multinomialdoublystochastic.html b/previews/PR644/manifolds/multinomialdoublystochastic.html new file mode 100644 index 0000000000..9609dd3856 --- /dev/null +++ b/previews/PR644/manifolds/multinomialdoublystochastic.html @@ -0,0 +1,17 @@ + +Multinomial doubly stochastic matrices · Manifolds.jl

    Multinomial doubly stochastic matrices

    Manifolds.MultinomialDoubleStochasticType
    MultinomialDoublyStochastic{n} <: AbstractMultinomialDoublyStochastic{N}

    The set of doubly stochastic multinomial matrices consists of all $n×n$ matrices with stochastic columns and rows, i.e.

    \[\begin{aligned} +\mathcal{DP}(n) \coloneqq \bigl\{p ∈ ℝ^{n×n}\ \big|\ &p_{i,j} > 0 \text{ for all } i=1,…,n, j=1,…,m,\\ +& p\mathbf{1}_n = p^{\mathrm{T}}\mathbf{1}_n = \mathbf{1}_n +\bigr\}, +\end{aligned}\]

    where $\mathbf{1}_n$ is the vector of length $n$ containing ones.

    The tangent space can be written as

    \[T_p\mathcal{DP}(n) \coloneqq \bigl\{ +X ∈ ℝ^{n×n}\ \big|\ X = X^{\mathrm{T}} \text{ and } +X\mathbf{1}_n = X^{\mathrm{T}}\mathbf{1}_n = \mathbf{0}_n +\bigr\},\]

    where $\mathbf{0}_n$ is the vector of length $n$ containing zeros.

    More details can be found in Section III[DouikHassibi2019].

    Constructor

    MultinomialDoubleStochastic(n)

    Generate the manifold of matrices $\mathbb R^{n×n}$ that are doubly stochastic and symmetric.

    source
    ManifoldsBase.projectMethod
    project(
    +    M::AbstractMultinomialDoublyStochastic,
    +    p;
    +    maxiter = 100,
    +    tolerance = eps(eltype(p))
    +)

    project a matrix p with positive entries applying Sinkhorn's algorithm. Note that this projct method – different from the usual case, accepts keywords.

    source
    ManifoldsBase.projectMethod
    project(M::MultinomialDoubleStochastic{n}, p, Y) where {n}

    Project Y onto the tangent space at p on the MultinomialDoubleStochastic M, return the result in X. The formula reads

    \[ \operatorname{proj}_p(Y) = Y - (α\mathbf{1}_n^{\mathrm{T}} + \mathbf{1}_nβ^{\mathrm{T}}) ⊙ p,\]

    where $⊙$ denotes the Hadamard or elementwise product and $\mathbb{1}_n$ is the vector of length $n$ containing ones. The two vectors $α,β ∈ ℝ^{n×n}$ are computed as a solution (typically using the left pseudo inverse) of

    \[ \begin{pmatrix} I_n & p\\p^{\mathrm{T}} & I_n \end{pmatrix} + \begin{pmatrix} α\\ β\end{pmatrix} + = + \begin{pmatrix} Y\mathbf{1}\\Y^{\mathrm{T}}\mathbf{1}\end{pmatrix},\]

    where $I_n$ is the $n×n$ unit matrix and $\mathbf{1}_n$ is the vector of length $n$ containing ones.

    source
    ManifoldsBase.retractMethod
    retract(M::MultinomialDoubleStochastic, p, X, ::ProjectionRetraction)

    compute a projection based retraction by projecting $p\odot\exp(X⨸p)$ back onto the manifold, where $⊙,⨸$ are elementwise multiplication and division, respectively. Similarly, $\exp$ refers to the elementwise exponentiation.

    source

    Literature

    • DouikHassibi2019

      A. Douik, B. Hassibi: AbstractManifold Optimization Over the Set of Doubly Stochastic Matrices: A Second-Order Geometry, IEEE Transactions on Signal Processing 67(22), pp. 5761–5774, 2019. doi: 10.1109/tsp.2019.2946024, arXiv: 1802.02628.

    diff --git a/previews/PR644/manifolds/multinomialsymmetric.html b/previews/PR644/manifolds/multinomialsymmetric.html new file mode 100644 index 0000000000..9c18988d20 --- /dev/null +++ b/previews/PR644/manifolds/multinomialsymmetric.html @@ -0,0 +1,10 @@ + +Multinomial symmetric matrices · Manifolds.jl

    Multinomial symmetric matrices

    Manifolds.MultinomialSymmetricType
    MultinomialSymmetric{n} <: AbstractMultinomialDoublyStochastic{N}

    The multinomial symmetric matrices manifold consists of all symmetric $n×n$ matrices with positive entries such that each column sums to one, i.e.

    \[\begin{aligned} +\mathcal{SP}(n) \coloneqq \bigl\{p ∈ ℝ^{n×n}\ \big|\ &p_{i,j} > 0 \text{ for all } i=1,…,n, j=1,…,m,\\ +& p^\mathrm{T} = p,\\ +& p\mathbf{1}_n = \mathbf{1}_n +\bigr\}, +\end{aligned}\]

    where $\mathbf{1}_n$ is the vector of length $n$ containing ones.

    It is modeled as IsIsometricEmbeddedManifold. via the AbstractMultinomialDoublyStochastic type, since it shares a few functions also with AbstractMultinomialDoublyStochastic, most and foremost projection of a point from the embedding onto the manifold.

    The tangent space can be written as

    \[T_p\mathcal{SP}(n) \coloneqq \bigl\{ +X ∈ ℝ^{n×n}\ \big|\ X = X^{\mathrm{T}} \text{ and } +X\mathbf{1}_n = \mathbf{0}_n +\bigr\},\]

    where $\mathbf{0}_n$ is the vector of length $n$ containing zeros.

    More details can be found in Section IV[DouikHassibi2019].

    Constructor

    MultinomialSymmetric(n)

    Generate the manifold of matrices $\mathbb R^{n×n}$ that are doubly stochastic and symmetric.

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::MultinomialSymmetric p, X; kwargs...)

    Checks whether X is a valid tangent vector to p on the MultinomialSymmetric M. This means, that p is valid, that X is of correct dimension, symmetric, and sums to zero along any row.

    source
    ManifoldsBase.projectMethod
    project(M::MultinomialSymmetric{n}, p, Y) where {n}

    Project Y onto the tangent space at p on the MultinomialSymmetric M, return the result in X. The formula reads

    \[ \operatorname{proj}_p(Y) = Y - (α\mathbf{1}_n^{\mathrm{T}} + \mathbf{1}_n α^{\mathrm{T}}) ⊙ p,\]

    where $⊙$ denotes the Hadamard or elementwise product and $\mathbb{1}_n$ is the vector of length $n$ containing ones. The two vector $α ∈ ℝ^{n×n}$ is given by solving

    \[ (I_n+p)α = Y\mathbf{1},\]

    where $I_n$ is teh $n×n$ unit matrix and $\mathbf{1}_n$ is the vector of length $n$ containing ones.

    source
    ManifoldsBase.retractMethod
    retract(M::MultinomialSymmetric, p, X, ::ProjectionRetraction)

    compute a projection based retraction by projecting $p\odot\exp(X⨸p)$ back onto the manifold, where $⊙,⨸$ are elementwise multiplication and division, respectively. Similarly, $\exp$ refers to the elementwise exponentiation.

    source

    Literature

    • DouikHassibi2019

      A. Douik, B. Hassibi: AbstractManifold Optimization Over the Set of Doubly Stochastic Matrices: A Second-Order Geometry, IEEE Transactions on Signal Processing 67(22), pp. 5761–5774, 2019. doi: 10.1109/tsp.2019.2946024, arXiv: 1802.02628.

    diff --git a/previews/PR644/manifolds/oblique.html b/previews/PR644/manifolds/oblique.html new file mode 100644 index 0000000000..2fa13e0420 --- /dev/null +++ b/previews/PR644/manifolds/oblique.html @@ -0,0 +1,2 @@ + +Oblique manifold · Manifolds.jl

    Oblique manifold

    The oblique manifold $\mathcal{OB}(n,m)$ is modeled as an AbstractPowerManifold of the (real-valued) Sphere and uses ArrayPowerRepresentation. Points on the torus are hence matrices, $x ∈ ℝ^{n,m}$.

    Manifolds.ObliqueType
    Oblique{N,M,𝔽} <: AbstractPowerManifold{𝔽}

    The oblique manifold $\mathcal{OB}(n,m)$ is the set of 𝔽-valued matrices with unit norm column endowed with the metric from the embedding. This yields exactly the same metric as considering the product metric of the unit norm vectors, i.e. PowerManifold of the $(n-1)$-dimensional Sphere.

    The Sphere is stored internally within M.manifold, such that all functions of AbstractPowerManifold can be used directly.

    Constructor

    Oblique(n,m)

    Generate the manifold of matrices $\mathbb R^{n × m}$ such that the $m$ columns are unit vectors, i.e. from the Sphere(n-1).

    source

    Functions

    Most functions are directly implemented for an AbstractPowerManifold with ArrayPowerRepresentation except the following special cases:

    ManifoldsBase.check_pointMethod
    check_point(M::Oblique{n,m},p)

    Checks whether p is a valid point on the Oblique{m,n} M, i.e. is a matrix of m unit columns from $\mathbb R^{n}$, i.e. each column is a point from Sphere(n-1).

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::Oblique p, X; kwargs...)

    Checks whether X is a valid tangent vector to p on the Oblique M. This means, that p is valid, that X is of correct dimension and columnswise a tangent vector to the columns of p on the Sphere.

    source
    diff --git a/previews/PR644/manifolds/positivenumbers.html b/previews/PR644/manifolds/positivenumbers.html new file mode 100644 index 0000000000..49af369a4e --- /dev/null +++ b/previews/PR644/manifolds/positivenumbers.html @@ -0,0 +1,2 @@ + +Positive numbers · Manifolds.jl

    Positive Numbers

    The manifold PositiveNumbers represents positive numbers with hyperbolic geometry. Additionally, there are also short forms for its corresponding PowerManifolds, i.e. PositiveVectors, PositiveMatrices, and PositiveArrays.

    Manifolds.PositiveNumbersType
    PositiveNumbers <: AbstractManifold{ℝ}

    The hyperbolic manifold of positive numbers $H^1$ is a the hyperbolic manifold represented by just positive numbers.

    Constructor

    PositiveNumbers()

    Generate the -valued hyperbolic model represented by positive positive numbers. To use this with arrays (1-element arrays), please use SymmetricPositiveDefinite(1).

    source
    Base.expMethod
    exp(M::PositiveNumbers, p, X)

    Compute the exponential map on the PositiveNumbers M.

    \[\exp_p X = p\operatorname{exp}(X/p).\]

    source
    ManifoldsBase.change_metricMethod
    change_metric(M::PositiveNumbers, E::EuclideanMetric, p, X)

    Given a tangent vector $X ∈ T_p\mathcal M$ representing a linear function with respect to the EuclideanMetric g_E, this function changes the representer into the one with respect to the positivity metric of PositiveNumbers M.

    For all $Z,Y$ we are looking for the function $c$ on the tangent space at $p$ such that

    \[ ⟨Z,Y⟩ = XY = \frac{c(Z)c(Y)}{p^2} = g_p(c(Y),c(Z))\]

    and hence $C(X) = pX$.

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::PositiveNumbers, E::EuclideanMetric, p, X)

    Given a tangent vector $X ∈ T_p\mathcal M$ representing a linear function with respect to the EuclideanMetric g_E, this function changes the representer into the one with respect to the positivity metric representation of PositiveNumbers M.

    For all tangent vectors $Y$ the result $Z$ has to fulfill

    \[ ⟨X,Y⟩ = XY = \frac{ZY}{p^2} = g_p(YZ)\]

    and hence $Z = p^2X$

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::PositiveNumbers, p, X; kwargs...)

    Check whether X is a tangent vector in the tangent space of p on the PositiveNumbers M. For the real-valued case represented by positive numbers, all X are valid, since the tangent space is the whole real line. For the complex-valued case X [...]

    source
    ManifoldsBase.innerMethod
    inner(M::PositiveNumbers, p, X, Y)

    Compute the inner product of the two tangent vectors X,Y from the tangent plane at p on the PositiveNumbers M, i.e.

    \[g_p(X,Y) = \frac{XY}{p^2}.\]

    source
    diff --git a/previews/PR644/manifolds/power.html b/previews/PR644/manifolds/power.html new file mode 100644 index 0000000000..839dac4198 --- /dev/null +++ b/previews/PR644/manifolds/power.html @@ -0,0 +1,54 @@ + +Power manifold · Manifolds.jl

    Power manifold

    A power manifold is based on a AbstractManifold $\mathcal M$ to build a $\mathcal M^{n_1 \times n_2 \times \cdots \times n_m}$. In the case where $m=1$ we can represent a manifold-valued vector of data of length $n_1$, for example a time series. The case where $m=2$ is useful for representing manifold-valued matrices of data of size $n_1 \times n_2$, for example certain types of images.

    There are three available representations for points and vectors on a power manifold:

    • ArrayPowerRepresentation (the default one), very efficient but only applicable when points on the underlying manifold are represented using plain AbstractArrays.
    • NestedPowerRepresentation, applicable to any manifold. It assumes that points on the underlying manifold are represented using mutable data types.
    • NestedReplacingPowerRepresentation, applicable to any manifold. It does not mutate points on the underlying manifold, replacing them instead when appropriate.

    Below are some examples of usage of these representations.

    Example

    There are two ways to store the data: in a multidimensional array or in a nested array.

    Let's look at an example for both. Let $\mathcal M$ be Sphere(2) the 2-sphere and we want to look at vectors of length 4.

    ArrayPowerRepresentation

    For the default, the ArrayPowerRepresentation, we store the data in a multidimensional array,

    using Manifolds
    +M = PowerManifold(Sphere(2), 4)
    +p = cat([1.0, 0.0, 0.0],
    +        [1/sqrt(2.0), 1/sqrt(2.0), 0.0],
    +        [1/sqrt(2.0), 0.0, 1/sqrt(2.0)],
    +        [0.0, 1.0, 0.0]
    +    ,dims=2)
    3×4 Matrix{Float64}:
    + 1.0  0.707107  0.707107  0.0
    + 0.0  0.707107  0.0       1.0
    + 0.0  0.0       0.707107  0.0

    which is a valid point i.e.

    is_point(M, p)
    true

    This can also be used in combination with HybridArrays.jl and StaticArrays.jl, by setting

    using HybridArrays, StaticArrays
    +q = HybridArray{Tuple{3,StaticArrays.Dynamic()},Float64,2}(p)
    3×4 HybridArrays.HybridMatrix{3, StaticArraysCore.Dynamic(), Float64, 2, Matrix{Float64}} with indices SOneTo(3)×Base.OneTo(4):
    + 1.0  0.707107  0.707107  0.0
    + 0.0  0.707107  0.0       1.0
    + 0.0  0.0       0.707107  0.0

    which is still a valid point on M and PowerManifold works with these, too.

    An advantage of this representation is that it is quite efficient, especially when a HybridArray (from the HybridArrays.jl package) is used to represent a point on the power manifold. A disadvantage is not being able to easily identify parts of the multidimensional array that correspond to a single point on the base manifold. Another problem is, that accessing a single point is p[:, 1] which might be unintuitive.

    NestedPowerRepresentation

    For the NestedPowerRepresentation we can now do

    using Manifolds
    +M = PowerManifold(Sphere(2), NestedPowerRepresentation(), 4)
    +p = [ [1.0, 0.0, 0.0],
    +      [1/sqrt(2.0), 1/sqrt(2.0), 0.0],
    +      [1/sqrt(2.0), 0.0, 1/sqrt(2.0)],
    +      [0.0, 1.0, 0.0],
    +    ]
    4-element Vector{Vector{Float64}}:
    + [1.0, 0.0, 0.0]
    + [0.7071067811865475, 0.7071067811865475, 0.0]
    + [0.7071067811865475, 0.0, 0.7071067811865475]
    + [0.0, 1.0, 0.0]

    which is again a valid point so is_point(M, p) here also yields true. A disadvantage might be that with nested arrays one loses a little bit of performance. The data however is nicely encapsulated. Accessing the first data item is just p[1].

    For accessing points on power manifolds in both representations you can use get_component and set_component! functions. They work work both point representations.

    using Manifolds
    +M = PowerManifold(Sphere(2), NestedPowerRepresentation(), 4)
    +p = [ [1.0, 0.0, 0.0],
    +      [1/sqrt(2.0), 1/sqrt(2.0), 0.0],
    +      [1/sqrt(2.0), 0.0, 1/sqrt(2.0)],
    +      [0.0, 1.0, 0.0],
    +    ]
    +set_component!(M, p, [0.0, 0.0, 1.0], 4)
    +get_component(M, p, 4)
    3-element Vector{Float64}:
    + 0.0
    + 0.0
    + 1.0

    NestedReplacingPowerRepresentation

    The final representation is the NestedReplacingPowerRepresentation. It is similar to the NestedPowerRepresentation but it does not perform in-place operations on the points on the underlying manifold. The example below uses this representation to store points on a power manifold of the SpecialEuclidean group in-line in an Vector for improved efficiency. When having a mixture of both, i.e. an array structure that is nested (like ´NestedPowerRepresentation) in the sense that the elements of the main vector are immutable, then changing the elements can not be done in an in-place way and hence NestedReplacingPowerRepresentation has to be used.

    using Manifolds, StaticArrays
    +R2 = Rotations(2)
    +
    +G = SpecialEuclidean(2)
    +N = 5
    +GN = PowerManifold(G, NestedReplacingPowerRepresentation(), N)
    +
    +q = [1.0 0.0; 0.0 1.0]
    +p1 = [ProductRepr(SVector{2,Float64}([i - 0.1, -i]), SMatrix{2,2,Float64}(exp(R2, q, hat(R2, q, i)))) for i in 1:N]
    +p2 = [ProductRepr(SVector{2,Float64}([i - 0.1, -i]), SMatrix{2,2,Float64}(exp(R2, q, hat(R2, q, -i)))) for i in 1:N]
    +
    +X = similar(p1);
    +
    +log!(GN, X, p1, p2)
    5-element Vector{ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}}:
    + ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 2.0; -2.0 0.0]))
    + ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 -2.2831853071795862; 2.2831853071795862 0.0]))
    + ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 -0.28318530717958645; 0.28318530717958645 0.0]))
    + ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 1.7168146928204135; -1.7168146928204135 0.0]))
    + ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 -2.566370614359173; 2.566370614359173 0.0]))

    Types and Functions

    Manifolds.ArrayPowerRepresentationType
    ArrayPowerRepresentation

    Representation of points and tangent vectors on a power manifold using multidimensional arrays where first dimensions are equal to representation_size of the wrapped manifold and the following ones are equal to the number of elements in each direction.

    Torus uses this representation.

    source
    Manifolds.PowerFVectorDistributionType
    PowerFVectorDistribution([type::VectorBundleFibers], [x], distr)

    Generates a random vector at a point from vector space (a fiber of a tangent bundle) of type type using the power distribution of distr.

    Vector space type and point can be automatically inferred from distribution distr.

    source
    Manifolds.PowerMetricType
    PowerMetric <: AbstractMetric

    Represent the AbstractMetric on an AbstractPowerManifold, i.e. the inner product on the tangent space is the sum of the inner product of each elements tangent space of the power manifold.

    source
    Manifolds.flatMethod
    flat(M::AbstractPowerManifold, p, X)

    use the musical isomorphism to transform the tangent vector X from the tangent space at p on an AbstractPowerManifold M to a cotangent vector. This can be done elementwise for each entry of X (and p).

    source
    Manifolds.sharpMethod
    sharp(M::AbstractPowerManifold, p, ξ::RieszRepresenterCotangentVector)

    Use the musical isomorphism to transform the cotangent vector ξ from the tangent space at p on an AbstractPowerManifold M to a tangent vector. This can be done elementwise for every entry of ξ (and p).

    source
    ManifoldsBase.change_metricMethod
    change_metric(M::AbstractPowerManifold, ::AbstractMetric, p, X)

    Since the metric on a power manifold decouples, the change of metric can be done elementwise.

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::AbstractPowerManifold, ::AbstractMetric, p, X)

    Since the metric on a power manifold decouples, the change of a representer can be done elementwise

    source
    diff --git a/previews/PR644/manifolds/probabilitysimplex.html b/previews/PR644/manifolds/probabilitysimplex.html new file mode 100644 index 0000000000..f0cfb68e42 --- /dev/null +++ b/previews/PR644/manifolds/probabilitysimplex.html @@ -0,0 +1,13 @@ + +Probability simplex · Manifolds.jl

    The probability simplex

    Manifolds.FisherRaoMetricType
    FisherRaoMetric <: AbstractMetric

    The Fisher-Rao metric or Fisher information metric is a particular Riemannian metric which can be defined on a smooth statistical manifold, i.e., a smooth manifold whose points are probability measures defined on a common probability space.

    See for example the ProbabilitySimplex.

    source
    Manifolds.ProbabilitySimplexType
    ProbabilitySimplex{n,boundary} <: AbstractDecoratorManifold{𝔽}

    The (relative interior of) the probability simplex is the set

    \[Δ^n := \biggl\{ p ∈ ℝ^{n+1}\ \big|\ p_i > 0 \text{ for all } i=1,…,n+1, +\text{ and } ⟨\mathbb{1},p⟩ = \sum_{i=1}^{n+1} p_i = 1\biggr\},\]

    where $\mathbb{1}=(1,…,1)^{\mathrm{T}}∈ ℝ^{n+1}$ denotes the vector containing only ones.

    If boundary is set to :open, then the object represents an open simplex. Otherwise, that is when boundary is set to :closed, the boundary is also included:

    \[\hat{Δ}^n := \biggl\{ p ∈ ℝ^{n+1}\ \big|\ p_i \geq 0 \text{ for all } i=1,…,n+1, +\text{ and } ⟨\mathbb{1},p⟩ = \sum_{i=1}^{n+1} p_i = 1\biggr\},\]

    This set is also called the unit simplex or standard simplex.

    The tangent space is given by

    \[T_pΔ^n = \biggl\{ X ∈ ℝ^{n+1}\ \big|\ ⟨\mathbb{1},X⟩ = \sum_{i=1}^{n+1} X_i = 0 \biggr\}\]

    The manifold is implemented assuming the Fisher-Rao metric for the multinomial distribution, which is equivalent to the induced metric from isometrically embedding the probability simplex in the $n$-sphere of radius 2. The corresponding diffeomorphism $\varphi: \mathbb Δ^n → \mathcal N$, where $\mathcal N \subset 2𝕊^n$ is given by $\varphi(p) = 2\sqrt{p}$.

    This implementation follows the notation in [ÅströmPetraSchmitzerSchnörr2017].

    Constructor

    ProbabilitySimplex(n::Int; boundary::Symbol=:open)
    source
    Base.expMethod
    exp(M::ProbabilitySimplex, p, X)

    Compute the exponential map on the probability simplex.

    \[\exp_pX = \frac{1}{2}\Bigl(p+\frac{X_p^2}{\lVert X_p \rVert^2}\Bigr) ++ \frac{1}{2}\Bigl(p - \frac{X_p^2}{\lVert X_p \rVert^2}\Bigr)\cos(\lVert X_p\rVert) ++ \frac{1}{\lVert X_p \rVert}\sqrt{p}\sin(\lVert X_p\rVert),\]

    where $X_p = \frac{X}{\sqrt{p}}$, with its division meant elementwise, as well as for the operations $X_p^2$ and $\sqrt{p}$.

    source
    Base.logMethod
    log(M::ProbabilitySimplex, p, q)

    Compute the logarithmic map of p and q on the ProbabilitySimplex M.

    \[\log_pq = \frac{d_{Δ^n}(p,q)}{\sqrt{1-⟨\sqrt{p},\sqrt{q}⟩}}(\sqrt{pq} - ⟨\sqrt{p},\sqrt{q}⟩p),\]

    where $pq$ and $\sqrt{p}$ is meant elementwise.

    source
    Base.randMethod
    rand(::ProbabilitySimplex; vector_at=nothing, σ::Real=1.0)

    When vector_at is nothing, return a random (uniform over the Fisher-Rao metric; that is, uniform with respect to the n-sphere whose positive orthant is mapped to the simplex). point x on the ProbabilitySimplex manifold M according to the isometric embedding into the n-sphere by normalizing the vector length of a sample from a multivariate Gaussian. See [Marsaglia1972].

    When vector_at is not nothing, return a (Gaussian) random vector from the tangent space $T_{p}\mathrm{\Delta}^n$by shifting a multivariate Gaussian with standard deviation σ to have a zero component sum.

    source
    ManifoldDiff.riemannian_gradientMethod
    X = riemannian_gradient(M::ProbabilitySimplex{n}, p, Y)
    +riemannian_gradient!(M::ProbabilitySimplex{n}, X, p, Y)

    Given a gradient $Y = \operatorname{grad} \tilde f(p)$ in the embedding $ℝ^{n+1}$ of the ProbabilitySimplex $Δ^n$, this function computes the Riemannian gradient $X = \operatorname{grad} f(p)$ where $f$ is the function $\tilde f$ restricted to the manifold.

    The formula reads

    \[ X = p ⊙ Y - ⟨p, Y⟩p,\]

    where $⊙$ denotes the emelementwise product.

    source
    ManifoldsBase.change_metricMethod
    change_metric(M::ProbabilitySimplex, ::EuclideanMetric, p, X)

    To change the metric, we are looking for a function $c\colon T_pΔ^n \to T_pΔ^n$ such that for all $X,Y ∈ T_pΔ^n$ This can be achieved by rewriting representer change in matrix form as (Diagonal(p) - p * p') * X and taking square root of the matrix

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::ProbabilitySimplex, ::EuclideanMetric, p, X)

    Given a tangent vector with respect to the metric from the embedding, the EuclideanMetric, the representer of a linear functional on the tangent space is adapted as $Z = p .* X .- p .* dot(p, X)$. The first part “compensates” for the divsion by $p$ in the Riemannian metric on the ProbabilitySimplex and the second part performs appropriate projection to keep the vector tangent.

    For details see Proposition 2.3 in [ÅströmPetraSchmitzerSchnörr2017].

    source
    ManifoldsBase.check_pointMethod
    check_point(M::ProbabilitySimplex, p; kwargs...)

    Check whether p is a valid point on the ProbabilitySimplex M, i.e. is a point in the embedding with positive entries that sum to one The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::ProbabilitySimplex, p, X; kwargs... )

    Check whether X is a tangent vector to p on the ProbabilitySimplex M, i.e. after check_point(M,p), X has to be of same dimension as p and its elements have to sum to one. The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.innerMethod
    inner(M::ProbabilitySimplex, p, X, Y)

    Compute the inner product of two tangent vectors X, Y from the tangent space $T_pΔ^n$ at p. The formula reads

    \[g_p(X,Y) = \sum_{i=1}^{n+1}\frac{X_iY_i}{p_i}\]

    When M includes boundary, we can just skip coordinates where $p_i$ is equal to 0, see Proposition 2.1 in [AyJostLeSchwachhöfer2017].

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::ProbabilitySimplex, p, q, ::SoftmaxInverseRetraction)

    Compute a first order approximation by projection. The formula reads

    \[\operatorname{retr}^{-1}_p q = \bigl( I_{n+1} - \frac{1}{n}\mathbb{1}^{n+1,n+1} \bigr)(\log(q)-\log(p))\]

    where $\mathbb{1}^{m,n}$ is the size (m,n) matrix containing ones, and $\log$ is applied elementwise.

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::ProbabilitySimplex{n})

    Returns the manifold dimension of the probability simplex in $ℝ^{n+1}$, i.e.

    \[ \dim_{Δ^n} = n.\]

    source
    ManifoldsBase.projectMethod
    project(M::ProbabilitySimplex, p, Y)

    Project Y from the embedding onto the tangent space at p on the ProbabilitySimplex M. The formula reads

    `math \operatorname{proj}_{Δ^n}(p,Y) = Y - \bar{Y} where $\bar{Y}$ denotes mean of $Y$.

    source
    ManifoldsBase.projectMethod
    project(M::ProbabilitySimplex, p)

    project p from the embedding onto the ProbabilitySimplex M. The formula reads

    \[\operatorname{proj}_{Δ^n}(p) = \frac{1}{⟨\mathbb 1,p⟩}p,\]

    where $\mathbb 1 ∈ ℝ$ denotes the vector of ones. Not that this projection is only well-defined if $p$ has positive entries.

    source
    ManifoldsBase.representation_sizeMethod
    representation_size(::ProbabilitySimplex{n})

    Return the representation size of points in the $n$-dimensional probability simplex, i.e. an array size of (n+1,).

    source
    ManifoldsBase.retractMethod
    retract(M::ProbabilitySimplex, p, X, ::SoftmaxRetraction)

    Compute a first order approximation by applying the softmax function. The formula reads

    \[\operatorname{retr}_p X = \frac{p\mathrm{e}^X}{⟨p,\mathrm{e}^X⟩},\]

    where multiplication, exponentiation and division are meant elementwise.

    source

    Real probability amplitudes

    An isometric embedding of interior of ProbabilitySimplex in positive orthant of the Sphere is established through functions simplex_to_amplitude and amplitude_to_simplex. Some properties extend to the boundary but not all.

    This embedding isometrically maps the Fisher-Rao metric on the open probability simplex to the sphere of radius 1 with Euclidean metric. More details can be found in Section 2.2 of [AyJostLeSchwachhöfer2017].

    The name derives from the notion of probability amplitudes in quantum mechanics. They are complex-valued and their squared norm corresponds to probability. This construction restricted to real valued amplitudes results in this embedding.

    Manifolds.amplitude_to_simplexMethod
    amplitude_to_simplex(M::ProbabilitySimplex{N}, p) where {N}

    Convert point (real) probability amplitude p on to a point on ProbabilitySimplex. The formula reads $(p_1^2, p_2^2, …, p_{N+1}^2)$. This is an isometry from the interior of the positive orthant of a sphere to interior of the probability simplex.

    source
    Manifolds.simplex_to_amplitudeMethod
    simplex_to_amplitude(M::ProbabilitySimplex, p)

    Convert point p on ProbabilitySimplex to (real) probability amplitude. The formula reads $(\sqrt{p_1}, \sqrt{p_2}, …, \sqrt{p_{N+1}})$. This is an isometry from the interior of the probability simplex to the interior of the positive orthant of a sphere.

    source

    Literature

    diff --git a/previews/PR644/manifolds/product.html b/previews/PR644/manifolds/product.html new file mode 100644 index 0000000000..54e818cea5 --- /dev/null +++ b/previews/PR644/manifolds/product.html @@ -0,0 +1,8 @@ + +Product manifold · Manifolds.jl

    Product manifold

    Product manifold $\mathcal M = \mathcal{M}_1 × \mathcal{M}_2 × … × \mathcal{M}_n$ of manifolds $\mathcal{M}_1, \mathcal{M}_2, …, \mathcal{M}_n$. Points on the product manifold can be constructed using ProductRepr with canonical projections $Π_i : \mathcal{M} → \mathcal{M}_i$ for $i ∈ 1, 2, …, n$ provided by submanifold_component.

    Manifolds.ProductFVectorDistributionType
    ProductFVectorDistribution([type::VectorBundleFibers], [x], distrs...)

    Generates a random vector at point x from vector space (a fiber of a tangent bundle) of type type using the product distribution of given distributions.

    Vector space type and x can be automatically inferred from distributions distrs.

    source
    Manifolds.ProductManifoldType
    ProductManifold{𝔽,TM<:Tuple} <: AbstractManifold{𝔽}

    Product manifold $M_1 × M_2 × … × M_n$ with product geometry.

    Constructor

    ProductManifold(M_1, M_2, ..., M_n)

    generates the product manifold $M_1 × M_2 × … × M_n$. Alternatively, the same manifold can be contructed using the × operator: M_1 × M_2 × M_3.

    source
    Base.expMethod
    exp(M::ProductManifold, p, X)

    compute the exponential map from p in the direction of X on the ProductManifold M, which is the elementwise exponential map on the internal manifolds that build M.

    source
    Base.getindexMethod
    getindex(p, M::ProductManifold, i::Union{Integer,Colon,AbstractVector})
    +p[M::ProductManifold, i]

    Access the element(s) at index i of a point p on a ProductManifold M by linear indexing. See also Array Indexing in Julia.

    source
    Base.logMethod
    log(M::ProductManifold, p, q)

    Compute the logarithmic map from p to q on the ProductManifold M, which can be computed using the logarithmic maps of the manifolds elementwise.

    source
    Base.randMethod
    rand(M::ProductManifold; parts_kwargs = map(_ -> (;), M.manifolds))

    Return a random point on ProductManifold M. parts_kwargs is a tuple of keyword arguments for rand on each manifold in M.manifolds.

    source
    Base.setindex!Method
    setindex!(q, p, M::ProductManifold, i::Union{Integer,Colon,AbstractVector})
    +q[M::ProductManifold,i...] = p

    set the element [i...] of a point q on a ProductManifold by linear indexing to q. See also Array Indexing in Julia.

    source
    LinearAlgebra.crossMethod
    cross(M, N)
    +cross(M1, M2, M3,...)

    Return the ProductManifold For two AbstractManifolds M and N, where for the case that one of them is a ProductManifold itself, the other is either prepended (if N is a product) or appenden (if M) is. If both are product manifold, they are combined into one product manifold, keeping the order.

    For the case that more than one is a product manifold of these is build with the same approach as above

    source
    LinearAlgebra.normMethod
    norm(M::ProductManifold, p, X)

    Compute the norm of X from the tangent space of p on the ProductManifold, i.e. from the element wise norms the 2-norm is computed.

    source
    Manifolds.flatMethod
    flat(M::ProductManifold, p, X::FVector{TangentSpaceType})

    use the musical isomorphism to transform the tangent vector X from the tangent space at p on the ProductManifold M to a cotangent vector. This can be done elementwise for every entry of X (with respect to the corresponding entry in p) separately.

    source
    Manifolds.sharpMethod
    sharp(M::ProductManifold, p, ξ::FVector{CotangentSpaceType})

    Use the musical isomorphism to transform the cotangent vector ξ from the tangent space at p on the ProductManifold M to a tangent vector. This can be done elementwise for every entry of ξ (and p) separately

    source
    Manifolds.submanifoldMethod
    submanifold(M::ProductManifold, i::Val)
    +submanifold(M::ProductManifold, i::AbstractVector)

    Extract the factor of the product manifold M indicated by indices in i. For example, for i equal to Val((1, 3)) the product manifold constructed from the first and the third factor is returned.

    The version with AbstractVector is not type-stable, for better preformance use Val.

    source
    ManifoldsBase.change_metricMethod
    change_metric(M::ProductManifold, ::AbstractMetric, p, X)

    Since the metric on a product manifold decouples, the change of metric can be done elementwise.

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::ProductManifold, ::AbstractMetric, p, X)

    Since the metric on a product manifold decouples, the change of a representer can be done elementwise

    source
    ManifoldsBase.check_pointMethod
    check_point(M::ProductManifold, p; kwargs...)

    Check whether p is a valid point on the ProductManifold M. If p is not a point on M a CompositeManifoldError.consisting of all error messages of the components, for which the tests fail is returned.

    The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.check_sizeMethod
    check_size(M::ProductManifold, p; kwargs...)

    Check whether p is of valid size on the ProductManifold M. If p has components of wrong size a CompositeManifoldError.consisting of all error messages of the components, for which the tests fail is returned.

    The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::ProductManifold, p, X; kwargs... )

    Check whether X is a tangent vector to p on the ProductManifold M, i.e. all projections to base manifolds must be respective tangent vectors. If X is not a tangent vector to p on M a CompositeManifoldError.consisting of all error messages of the components, for which the tests fail is returned.

    The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.distanceMethod
    distance(M::ProductManifold, p, q)

    Compute the distance between two points p and q on the ProductManifold M, which is the 2-norm of the elementwise distances on the internal manifolds that build M.

    source
    ManifoldsBase.innerMethod
    inner(M::ProductManifold, p, X, Y)

    compute the inner product of two tangent vectors X, Y from the tangent space at p on the ProductManifold M, which is just the sum of the internal manifolds that build M.

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::ProductManifold, p, q, m::InverseProductRetraction)

    Compute the inverse retraction from p with respect to q on the ProductManifold M using an InverseProductRetraction, which by default encapsulates a inverse retraction for each manifold of the product. Then this method is performed elementwise, so the encapsulated inverse retraction methods have to be available per factor.

    source
    ManifoldsBase.retractMethod
    retract(M::ProductManifold, p, X, m::ProductRetraction)

    Compute the retraction from p with tangent vector X on the ProductManifold M using an ProductRetraction, which by default encapsulates retractions of the base manifolds. Then this method is performed elementwise, so the encapsulated retractions method has to be one that is available on the manifolds.

    source
    diff --git a/previews/PR644/manifolds/projectivespace.html b/previews/PR644/manifolds/projectivespace.html new file mode 100644 index 0000000000..687d4668fc --- /dev/null +++ b/previews/PR644/manifolds/projectivespace.html @@ -0,0 +1,12 @@ + +Projective space · Manifolds.jl

    Projective space

    Manifolds.AbstractProjectiveSpaceType
    AbstractProjectiveSpace{𝔽} <: AbstractDecoratorManifold{𝔽}

    An abstract type to represent a projective space over 𝔽 that is represented isometrically in the embedding.

    source
    Manifolds.ArrayProjectiveSpaceType
    ArrayProjectiveSpace{T<:Tuple,𝔽} <: AbstractProjectiveSpace{𝔽}

    The projective space $𝔽ℙ^{n₁,n₂,…,nᵢ}$ is the manifold of all lines in $𝔽^{n₁,n₂,…,nᵢ}$. The default representation is in the embedding, i.e. as unit (Frobenius) norm matrices in $𝔽^{n₁,n₂,…,nᵢ}$:

    \[𝔽ℙ^{n_1, n_2, …, n_i} := \bigl\{ [p] ⊂ 𝔽^{n_1, n_2, …, n_i} \ \big|\ \lVert p \rVert_{\mathrm{F}} = 1, λ ∈ 𝔽, |λ| = 1, p ∼ p λ \bigr\}.\]

    where $[p]$ is an equivalence class of points $p$, $\sim$ indicates equivalence, and $\lVert ⋅ \rVert_{\mathrm{F}}$ is the Frobenius norm. Note that unlike ProjectiveSpace, the argument for ArrayProjectiveSpace is given by the size of the embedding. This means that ProjectiveSpace(2) and ArrayProjectiveSpace(3) are the same manifold. Additionally, ArrayProjectiveSpace(n,1;field=𝔽) and Grassmann(n,1;field=𝔽) are the same.

    The tangent space at point $p$ is given by

    \[T_p 𝔽ℙ^{n_1, n_2, …, n_i} := \bigl\{ X ∈ 𝔽^{n_1, n_2, …, n_i}\ |\ ⟨p,X⟩_{\mathrm{F}} = 0 \bigr \},\]

    where $⟨⋅,⋅⟩_{\mathrm{F}}$ denotes the (Frobenius) inner product in the embedding $𝔽^{n_1, n_2, …, n_i}$.

    Constructor

    ArrayProjectiveSpace(n₁,n₂,...,nᵢ; field=ℝ)

    Generate the projective space $𝔽ℙ^{n_1, n_2, …, n_i}$, defaulting to the real projective space, where field can also be used to generate the complex- and right-quaternionic projective spaces.

    source
    Manifolds.ProjectiveSpaceType
    ProjectiveSpace{n,𝔽} <: AbstractProjectiveSpace{𝔽}

    The projective space $𝔽ℙ^n$ is the manifold of all lines in $𝔽^{n+1}$. The default representation is in the embedding, i.e. as unit norm vectors in $𝔽^{n+1}$:

    \[𝔽ℙ^n := \bigl\{ [p] ⊂ 𝔽^{n+1} \ \big|\ \lVert p \rVert = 1, λ ∈ 𝔽, |λ| = 1, p ∼ p λ \bigr\},\]

    where $[p]$ is an equivalence class of points $p$, and $∼$ indicates equivalence. For example, the real projective space $ℝℙ^n$ is represented as the unit sphere $𝕊^n$, where antipodal points are considered equivalent.

    The tangent space at point $p$ is given by

    \[T_p 𝔽ℙ^{n} := \bigl\{ X ∈ 𝔽^{n+1}\ \big|\ ⟨p,X⟩ = 0 \bigr \},\]

    where $⟨⋅,⋅⟩$ denotes the inner product in the embedding $𝔽^{n+1}$.

    When $𝔽 = ℍ$, this implementation of $ℍℙ^n$ is the right-quaternionic projective space.

    Constructor

    ProjectiveSpace(n[, field=ℝ])

    Generate the projective space $𝔽ℙ^{n} ⊂ 𝔽^{n+1}$, defaulting to the real projective space $ℝℙ^n$, where field can also be used to generate the complex- and right-quaternionic projective spaces.

    source
    Base.logMethod
    log(M::AbstractProjectiveSpace, p, q)

    Compute the logarithmic map on AbstractProjectiveSpace M$ = 𝔽ℙ^n$, i.e. the tangent vector whose corresponding geodesic starting from p reaches q after time 1 on M. The formula reads

    \[\log_p q = (q λ - \cos θ p) \frac{θ}{\sin θ},\]

    where $θ = \arccos|⟨q, p⟩_{\mathrm{F}}|$ is the distance between $p$ and $q$, $⟨⋅, ⋅⟩_{\mathrm{F}}$ is the Frobenius inner product, and $λ = \frac{⟨q, p⟩_{\mathrm{F}}}{|⟨q, p⟩_{\mathrm{F}}|} ∈ 𝔽$ is the unit scalar that minimizes $d_{𝔽^{n+1}}(p - q λ)$. That is, $q λ$ is the member of the equivalence class $[q]$ that is closest to $p$ in the embedding. As a result, $\exp_p \circ \log_p \colon q ↦ q λ$.

    The logarithmic maps for the real AbstractSphere $𝕊^n$ and the real projective space $ℝℙ^n$ are identical when $p$ and $q$ are in the same hemisphere.

    source
    ManifoldsBase._isapproxMethod
    isapprox(M::AbstractProjectiveSpace, p, q; kwargs...)

    Check that points p and q on the AbstractProjectiveSpace M$=𝔽ℙ^n$ are members of the same equivalence class, i.e. that $p = q λ$ for some element $λ ∈ 𝔽$ with unit absolute value, that is, $|λ| = 1$. This is equivalent to the Riemannian distance being 0.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::AbstractProjectiveSpace, p; kwargs...)

    Check whether p is a valid point on the AbstractProjectiveSpace M, i.e. that it has the same size as elements of the embedding and has unit Frobenius norm. The tolerance for the norm check can be set using the kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::AbstractProjectiveSpace, p, X; kwargs... )

    Check whether X is a tangent vector in the tangent space of p on the AbstractProjectiveSpace M, i.e. that X has the same size as elements of the tangent space of the embedding and that the Frobenius inner product $⟨p, X⟩_{\mathrm{F}} = 0$.

    source
    ManifoldsBase.distanceMethod
    distance(M::AbstractProjectiveSpace, p, q)

    Compute the Riemannian distance on AbstractProjectiveSpace M$=𝔽ℙ^n$ between points p and q, i.e.

    \[d_{𝔽ℙ^n}(p, q) = \arccos\bigl| ⟨p, q⟩_{\mathrm{F}} \bigr|.\]

    Note that this definition is similar to that of the AbstractSphere. However, the absolute value ensures that all equivalent p and q have the same pairwise distance.

    source
    ManifoldsBase.get_coordinatesMethod
    get_coordinates(M::AbstractProjectiveSpace, p, X, B::DefaultOrthonormalBasis{ℝ})

    Represent the tangent vector $X$ at point $p$ from the AbstractProjectiveSpace $M = 𝔽ℙ^n$ in an orthonormal basis by unitarily transforming the hyperplane containing $X$, whose normal is $p$, to the hyperplane whose normal is the $x$-axis.

    Given $q = p \overline{λ} + x$, where $λ = \frac{⟨x, p⟩_{\mathrm{F}}}{|⟨x, p⟩_{\mathrm{F}}|}$, $⟨⋅, ⋅⟩_{\mathrm{F}}$ denotes the Frobenius inner product, and $\overline{⋅}$ denotes complex or quaternionic conjugation, the formula for $Y$ is

    \[\begin{pmatrix}0 \\ Y\end{pmatrix} = \left(X - q\frac{2 ⟨q, X⟩_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}\right)\overline{λ}.\]

    source
    ManifoldsBase.get_vectorMethod
    get_vector(M::AbstractProjectiveSpace, p, X, B::DefaultOrthonormalBasis{ℝ})

    Convert a one-dimensional vector of coefficients $X$ in the basis B of the tangent space at $p$ on the AbstractProjectiveSpace $M=𝔽ℙ^n$ to a tangent vector $Y$ at $p$ by unitarily transforming the hyperplane containing $X$, whose normal is the $x$-axis, to the hyperplane whose normal is $p$.

    Given $q = p \overline{λ} + x$, where $λ = \frac{⟨x, p⟩_{\mathrm{F}}}{|⟨x, p⟩_{\mathrm{F}}|}$, $⟨⋅, ⋅⟩_{\mathrm{F}}$ denotes the Frobenius inner product, and $\overline{⋅}$ denotes complex or quaternionic conjugation, the formula for $Y$ is

    \[Y = \left(X - q\frac{2 \left\langle q, \begin{pmatrix}0 \\ X\end{pmatrix}\right\rangle_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}\right) λ.\]

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::AbstractProjectiveSpace, p, q, method::ProjectionInverseRetraction)
    +inverse_retract(M::AbstractProjectiveSpace, p, q, method::PolarInverseRetraction)
    +inverse_retract(M::AbstractProjectiveSpace, p, q, method::QRInverseRetraction)

    Compute the equivalent inverse retraction ProjectionInverseRetraction, PolarInverseRetraction, and QRInverseRetraction on the AbstractProjectiveSpace manifold M$=𝔽ℙ^n$, i.e.

    \[\operatorname{retr}_p^{-1} q = q \frac{1}{⟨p, q⟩_{\mathrm{F}}} - p,\]

    where $⟨⋅, ⋅⟩_{\mathrm{F}}$ is the Frobenius inner product.

    Note that this inverse retraction is equivalent to the three corresponding inverse retractions on Grassmann(n+1,1,𝔽), where the three inverse retractions in this case coincide. For $ℝℙ^n$, it is the same as the ProjectionInverseRetraction on the real Sphere.

    source
    ManifoldsBase.parallel_transport_directionMethod
    parallel_transport_direction(M::AbstractProjectiveSpace, p, X, d)

    Parallel transport a vector X from the tangent space at a point p on the AbstractProjectiveSpace M along the geodesic in the direction indicated by the tangent vector d, i.e.

    \[\mathcal{P}_{\exp_p (d) ← p}(X) = X - \left(p \frac{\sin θ}{θ} + d \frac{1 - \cos θ}{θ^2}\right) ⟨d, X⟩_p,\]

    where $θ = \lVert d \rVert$, and $⟨⋅, ⋅⟩_p$ is the inner product at the point $p$. For the real projective space, this is equivalent to the same vector transport on the real AbstractSphere.

    source
    ManifoldsBase.parallel_transport_toMethod
    parallel_transport_to(M::AbstractProjectiveSpace, p, X, q)

    Parallel transport a vector X from the tangent space at a point p on the AbstractProjectiveSpace M$=𝔽ℙ^n$ to the tangent space at another point q.

    This implementation proceeds by transporting $X$ to $T_{q λ} M$ using the same approach as parallel_transport_direction, where $λ = \frac{⟨q, p⟩_{\mathrm{F}}}{|⟨q, p⟩_{\mathrm{F}}|} ∈ 𝔽$ is the unit scalar that takes $q$ to the member $q λ$ of its equivalence class $[q]$ closest to $p$ in the embedding. It then maps the transported vector from $T_{q λ} M$ to $T_{q} M$. The resulting transport to $T_{q} M$ is

    \[\mathcal{P}_{q ← p}(X) = \left(X - \left(p \frac{\sin θ}{θ} + d \frac{1 - \cos θ}{θ^2}\right) ⟨d, X⟩_p\right) \overline{λ},\]

    where $d = \log_p q$ is the direction of the transport, $θ = \lVert d \rVert_p$ is the distance between $p$ and $q$, and $\overline{⋅}$ denotes complex or quaternionic conjugation.

    source
    ManifoldsBase.projectMethod
    project(M::AbstractProjectiveSpace, p, X)

    Orthogonally project the point X onto the tangent space at p on the AbstractProjectiveSpace M:

    \[\operatorname{proj}_p (X) = X - p⟨p, X⟩_{\mathrm{F}},\]

    where $⟨⋅, ⋅⟩_{\mathrm{F}}$ denotes the Frobenius inner product. For the real AbstractSphere and AbstractProjectiveSpace, this projection is the same.

    source
    ManifoldsBase.projectMethod
    project(M::AbstractProjectiveSpace, p)

    Orthogonally project the point p from the embedding onto the AbstractProjectiveSpace M:

    \[\operatorname{proj}(p) = \frac{p}{\lVert p \rVert}_{\mathrm{F}},\]

    where $\lVert ⋅ \rVert_{\mathrm{F}}$ denotes the Frobenius norm. This is identical to projection onto the AbstractSphere.

    source
    ManifoldsBase.retractMethod
    retract(M::AbstractProjectiveSpace, p, X, method::ProjectionRetraction)
    +retract(M::AbstractProjectiveSpace, p, X, method::PolarRetraction)
    +retract(M::AbstractProjectiveSpace, p, X, method::QRRetraction)

    Compute the equivalent retraction ProjectionRetraction, PolarRetraction, and QRRetraction on the AbstractProjectiveSpace manifold M$=𝔽ℙ^n$, i.e.

    \[\operatorname{retr}_p X = \operatorname{proj}_p(p + X).\]

    Note that this retraction is equivalent to the three corresponding retractions on Grassmann(n+1,1,𝔽), where in this case they coincide. For $ℝℙ^n$, it is the same as the ProjectionRetraction on the real Sphere.

    source
    diff --git a/previews/PR644/manifolds/quotient.html b/previews/PR644/manifolds/quotient.html new file mode 100644 index 0000000000..6b49904a0e --- /dev/null +++ b/previews/PR644/manifolds/quotient.html @@ -0,0 +1,4 @@ + +Quotient manifold · Manifolds.jl

    Quotient manifold

    Manifolds.QuotientManifoldType
    QuotientManifold{M <: AbstractManifold{𝔽}, N} <: AbstractManifold{𝔽}

    Equip a manifold $\mathcal M$ explicitly with the property of being a quotient manifold.

    A manifold $\mathcal M$ is then a a quotient manifold of another manifold $\mathcal N$, i.e. for an equivalence relation $∼$ on $\mathcal N$ we have

    \[ \mathcal M = \mathcal N / ∼ = \bigl\{ [p] : p ∈ \mathcal N \bigr\},\]

    where $[p] ≔ \{ q ∈ \mathcal N : q ∼ p\}$ denotes the equivalence class containing $p$. For more details see Subsection 3.4.1[AbsilMahonySepulchre2008].

    This manifold type models an explicit quotient structure. This should be done if either the default implementation of $\mathcal M$ uses another representation different from the quotient structure or if it provides a (default) quotient structure that is different from the one introduced here.

    Fields

    • manifold – the manifold $\mathcal M$ in the introduction above.
    • total_space – the manifold $\mathcal N$ in the introduction above.

    Constructor

    QuotientManifold(M,N)

    Create a manifold where M is the quotient manifold and Nis its total space.

    source

    Provided functions

    Manifolds.canonical_projectMethod
    canonical_project(M, p)

    Compute the canonical projection $π$ on a manifold $\mathcal M$ that IsQuotientManifold, e.g. a QuotientManifold. The canonical (or natural) projection $π$ from the total space $\mathcal N$ onto $\mathcal M$ given by

    \[ π = π_{\mathcal N, \mathcal M} : \mathcal N → \mathcal M, p ↦ π_{\mathcal N, \mathcal M}(p) = [p].\]

    in other words, this function implicitly assumes, that the total space $\mathcal N$ is given, for example explicitly when M is a QuotientManifold and p is a point on N.

    source
    Manifolds.differential_canonical_projectMethod
    differential_canonical_project(M, p, X)

    Compute the differential of the canonical projection $π$ on a manifold $\mathcal M$ that IsQuotientManifold, e.g. a QuotientManifold. The canonical (or natural) projection $π$ from the total space $\mathcal N$ onto $\mathcal M$, such that its differential

    \[ Dπ(p) : T_p\mathcal N → T_{π(p)}\mathcal M\]

    where again the total space might be implicitly assumed, or explicitly when using a QuotientManifold M. So here p is a point on N and X is from $T_p\mathcal N$.

    source
    Manifolds.get_orbit_actionMethod
    get_orbit_action(M::AbstractDecoratorManifold)

    Return the group action that generates the orbit of an equivalence class of the quotient manifold M for which equivalence classes are orbits of an action of a Lie group. For the case that

    \[\mathcal M = \mathcal N / \mathcal O,\]

    where $\mathcal O$ is a Lie group with its group action generating the orbit.

    source
    Manifolds.horizontal_componentMethod
    horizontal_component(N::AbstractManifold, p, X)

    Compute the horizontal component of tangent vector X at point p in the total space of quotient manifold N.

    source
    Manifolds.horizontal_liftMethod
    horizontal_lift(N::AbstractManifold, q, X)
    +horizontal_lift(::QuotientManifold{𝔽,MT<:AbstractManifold{𝔽},NT<:AbstractManifold}, p, X) where {𝔽}

    Given a point q in total space of quotient manifold N such that $p=π(q)$ is a point on a quotient manifold M (implicitly given for the first case) and a tangent vector X this method computes a tangent vector Y on the horizontal space of $T_q\mathcal N$, i.e. the subspace that is orthogonal to the kernel of $Dπ(q)$.

    source
    Manifolds.vertical_componentMethod
    vertical_component(N::AbstractManifold, p, X)

    Compute the vertical component of tangent vector X at point p in the total space of quotient manifold N.

    source
    diff --git a/previews/PR644/manifolds/rotations.html b/previews/PR644/manifolds/rotations.html new file mode 100644 index 0000000000..e67fc7bdf5 --- /dev/null +++ b/previews/PR644/manifolds/rotations.html @@ -0,0 +1,12 @@ + +Rotations · Manifolds.jl

    Rotations

    The manifold $\mathrm{SO}(n)$ of orthogonal matrices with determinant $+1$ in $ℝ^{n × n}$, i.e.

    \[\mathrm{SO}(n) = \bigl\{R ∈ ℝ^{n × n} \big| R R^{\mathrm{T}} = +R^{\mathrm{T}}R = I_n, \det(R) = 1 \bigr\}\]

    The Lie group $\mathrm{SO}(n)$ is a subgroup of the orthogonal group $\mathrm{O}(n)$ and also known as the special orthogonal group or the set of rotations group. See also SpecialOrthogonal, which is this manifold equipped with the group operation.

    The tangent space to a point $p ∈ \mathrm{SO}(n)$ is given by

    \[T_p\mathrm{SO}(n) = \{X : X=pY,\qquad Y=-Y^{\mathrm{T}}\},\]

    i.e. all vectors that are a product of a skew symmetric matrix multiplied with $p$.

    Since the orthogonal matrices $\mathrm{SO}(n)$ are a Lie group, tangent vectors can also be represented by elements of the corresponding Lie algebra, which is the tangent space at the identity element. In the notation above, this means we just store the component $Y$ of $X$.

    This convention allows for more efficient operations on tangent vectors. Tangent spaces at different points are different vector spaces.

    Let $L_R: \mathrm{SO}(n) → \mathrm{SO}(n)$ where $R ∈ \mathrm{SO}(n)$ be the left-multiplication by $R$, that is $L_R(S) = RS$. The tangent space at rotation $R$, $T_R \mathrm{SO}(n)$, is related to the tangent space at the identity rotation $I_n$ by the differential of $L_R$ at identity, $(\mathrm{d}L_R)_{I_n} : T_{I_n} \mathrm{SO}(n) → T_R \mathrm{SO}(n)$. To convert the tangent vector representation at the identity rotation $X ∈ T_{I_n} \mathrm{SO}(n)$ (i.e., the default) to the matrix representation of the corresponding tangent vector $Y$ at a rotation $R$ use the embed which implements the following multiplication: $Y = RX ∈ T_R \mathrm{SO}(n)$. You can compare the functions log and exp to see how it works in practice.

    Several common functions are also implemented together with orthogonal and unitary matrices.

    Manifolds.RotationsType
    Rotations{N} <: AbstractManifold{ℝ}

    The manifold of rotation matrices of sice $n × n$, i.e. real-valued orthogonal matrices with determinant $+1$.

    Constructor

    Rotations(n)

    Generate the manifold of $n × n$ rotation matrices.

    source
    ManifoldDiff.riemannian_HessianMethod

    riemannian_Hessian(M::Rotations, p, G, H, X)

    The Riemannian Hessian can be computed by adopting Eq. (5.6) [Ngu23], so very similar to the Stiefel manifold. The only difference is, that here the tangent vectors are stored in the Lie algebra, u.e. the update direction is actually $pX$ instead of jst $X$ (in Stiefel). and that means the inverse has to be appliead to the (Euclidean) Hessian to map it into the Lie algebra.

    source
    Manifolds.angles_4d_skew_sym_matrixMethod
    angles_4d_skew_sym_matrix(A)

    The Lie algebra of Rotations(4) in $ℝ^{4 × 4}$, $𝔰𝔬(4)$, consists of $4 × 4$ skew-symmetric matrices. The unique imaginary components of their eigenvalues are the angles of the two plane rotations. This function computes these more efficiently than eigvals.

    By convention, the returned values are sorted in decreasing order (corresponding to the same ordering of angles as cos_angles_4d_rotation_matrix).

    source
    Manifolds.normal_rotation_distributionMethod
    normal_rotation_distribution(M::Rotations, p, σ::Real)

    Return a random point on the manifold Rotations M by generating a (Gaussian) random orthogonal matrix with determinant $+1$. Let

    \[QR = A\]

    be the QR decomposition of a random matrix $A$, then the formula reads

    \[p = QD\]

    where $D$ is a diagonal matrix with the signs of the diagonal entries of $R$, i.e.

    \[D_{ij}=\begin{cases} \operatorname{sgn}(R_{ij}) & \text{if} \; i=j \\ 0 & \, \text{otherwise} \end{cases}.\]

    It can happen that the matrix gets -1 as a determinant. In this case, the first and second columns are swapped.

    The argument p is used to determine the type of returned points.

    source
    ManifoldsBase.WeingartenMethod
    Weingarten(M::Rotations, p, X, V)

    Compute the Weingarten map $\mathcal W_p$ at p on the Stiefel M with respect to the tangent vector $X \in T_p\mathcal M$ and the normal vector $V \in N_p\mathcal M$.

    The formula is due to [AMT13] given by

    \[\mathcal W_p(X,V) = -\frac{1}{2}p\bigl(V^{\mathrm{T}}X - X^\mathrm{T}V\bigr)\]

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M, p, q, ::PolarInverseRetraction)

    Compute a vector from the tangent space $T_p\mathrm{SO}(n)$ of the point p on the Rotations manifold M with which the point q can be reached by the PolarRetraction from the point p after time 1.

    The formula reads

    \[\operatorname{retr}^{-1}_p(q) += -\frac{1}{2}(p^{\mathrm{T}}qs - (p^{\mathrm{T}}qs)^{\mathrm{T}})\]

    where $s$ is the solution to the Sylvester equation

    \[p^{\mathrm{T}}qs + s(p^{\mathrm{T}}q)^{\mathrm{T}} + 2I_n = 0.\]

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::Rotations, p, q, ::QRInverseRetraction)

    Compute a vector from the tangent space $T_p\mathrm{SO}(n)$ of the point p on the Rotations manifold M with which the point q can be reached by the QRRetraction from the point q after time 1.

    source
    ManifoldsBase.parallel_transport_directionMethod
    parallel_transport_direction(M::Rotations, p, X, d)

    Compute parallel transport of vector X tangent at p on the Rotations manifold in the direction d. The formula, provided in [Rentmeesters2011], reads:

    \[\mathcal P_{q\gets p}X = q^\mathrm{T}p \operatorname{Exp}(d/2) X \operatorname{Exp}(d/2)\]

    where $q=\exp_p d$.

    The formula simplifies to identity for 2-D rotations.

    source
    ManifoldsBase.projectMethod
    project(M::Rotations, p; check_det = true)

    Project p to the nearest point on manifold M.

    Given the singular value decomposition $p = U Σ V^\mathrm{T}$, with the singular values sorted in descending order, the projection is

    \[\operatorname{proj}_{\mathrm{SO}(n)}(p) = +U\operatorname{diag}\left[1,1,…,\det(U V^\mathrm{T})\right] V^\mathrm{T}\]

    The diagonal matrix ensures that the determinant of the result is $+1$. If p is expected to be almost special orthogonal, then you may avoid this check with check_det = false.

    source
    ManifoldsBase.zero_vectorMethod
    zero_vector(M::Rotations, p)

    Return the zero tangent vector from the tangent space art p on the Rotations as an element of the Lie group, i.e. the zero matrix.

    source

    Literature

    [AMT13]
    +
    + +
    [Ngu23]
    +
    +
    D. Nguyen. Operator-Valued Formulas for Riemannian Gradient and Hessian and Families of Tractable Metrics in Riemannian Optimization. Journal of Optimization Theory and Applications 198, 135–164 (2023).
    +
    +
    • Rentmeesters2011

      Rentmeesters Q., “A gradient method for geodesic data fitting on some symmetric Riemannian manifolds,” in 2011 50th IEEE Conference on Decision and Control and European Control Conference, Dec. 2011, pp. 7141–7146. doi: 10.1109/CDC.2011.6161280.

    diff --git a/previews/PR644/manifolds/shapespace.html b/previews/PR644/manifolds/shapespace.html new file mode 100644 index 0000000000..37444b545b --- /dev/null +++ b/previews/PR644/manifolds/shapespace.html @@ -0,0 +1,78 @@ + +Shape spaces · Manifolds.jl

    Shape spaces

    Shape spaces are spaces of $k$ points in $\mathbb{R}^n$ up to simultaneous action of a group on all points. The most commonly encountered are Kendall's pre-shape and shape spaces. In the case of the Kendall's pre-shape spaces the action is translation and scaling. In the case of the Kendall's shape spaces the action is translation, scaling and rotation.

    using Manifolds, Plots
    +
    +M = KendallsShapeSpace(2, 3)
    +# two random point on the shape space
    +p = [
    +    0.4385117672460505 -0.6877826444042382 0.24927087715818771
    +    -0.3830259932279294 0.35347460720654283 0.029551386021386548
    +]
    +q = [
    +    -0.42693314765896473 -0.3268567431952937 0.7537898908542584
    +    0.3054740561061169 -0.18962848284149897 -0.11584557326461796
    +]
    +# let's plot them as triples of points on a plane
    +fig = scatter(p[1,:], p[2,:], label="p", aspect_ratio=:equal)
    +scatter!(fig, q[1,:], q[2,:], label="q")
    +
    +# aligning q to p
    +A = get_orbit_action(M)
    +a = optimal_alignment(A, p, q)
    +rot_q = apply(A, a, q)
    +scatter!(fig, rot_q[1,:], rot_q[2,:], label="q aligned to p")
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    A more extensive usage example is available in the hand_gestures.jl tutorial.

    Manifolds.KendallsPreShapeSpaceType
    KendallsPreShapeSpace{n,k} <: AbstractSphere{ℝ}

    Kendall's pre-shape space of $k$ landmarks in $ℝ^n$ represented by n×k matrices. In each row the sum of elements of a matrix is equal to 0. The Frobenius norm of the matrix is equal to 1 [Kendall1984][Kendall1989].

    The space can be interpreted as tuples of $k$ points in $ℝ^n$ up to simultaneous translation and scaling of all points, so this can be thought of as a quotient manifold.

    Constructor

    KendallsPreShapeSpace(n::Int, k::Int)

    See also

    KendallsShapeSpace, esp. for the references

    source
    Manifolds.KendallsShapeSpaceType
    KendallsShapeSpace{n,k} <: AbstractDecoratorManifold{ℝ}

    Kendall's shape space, defined as quotient of a KendallsPreShapeSpace (represented by n×k matrices) by the action ColumnwiseMultiplicationAction.

    The space can be interpreted as tuples of $k$ points in $ℝ^n$ up to simultaneous translation and scaling and rotation of all points [Kendall1984][Kendall1989].

    This manifold possesses the IsQuotientManifold trait.

    Constructor

    KendallsShapeSpace(n::Int, k::Int)

    References

    source

    Provided functions

    ManifoldsBase.projectMethod
    project(M::KendallsPreShapeSpace, p, X)

    Project tangent vector X at point p from the embedding to KendallsPreShapeSpace by selecting the right element from the tangent space to orthogonal section representing the quotient manifold M. See Section 3.7 of [Srivastava2016] for details.

    References

    source
    ManifoldsBase.projectMethod
    project(M::KendallsPreShapeSpace, p)

    Project point p from the embedding to KendallsPreShapeSpace by selecting the right element from the orthogonal section representing the quotient manifold M. See Section 3.7 of [Srivastava2016] for details.

    The method computes the mean of the landmarks and moves them to make their mean zero; afterwards the Frobenius norm of the landmarks (as a matrix) is normalised to fix the scaling.

    source
    Base.logMethod
    log(M::KendallsShapeSpace, p, q)

    Compute the logarithmic map on KendallsShapeSpace M. See the [exp](@ref exp(::KendallsShapeSpace, ::Any, ::Any)onential map for more details

    source
    Base.randMethod
    rand(::KendallsShapeSpace; vector_at=nothing)

    When vector_at is nothing, return a random point x on the KendallsShapeSpace manifold M by generating a random point in the embedding.

    When vector_at is not nothing, return a random vector from the tangent space with mean zero and standard deviation σ.

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::KendallsShapeSpace)

    Return the dimension of the KendallsShapeSpace manifold M. The dimension is given by $n(k - 1) - 1 - n(n - 1)/2$ in the typical case where $k \geq n+1$, and $(k + 1)(k - 2) / 2$ otherwise, unless $k$ is equal to 1, in which case the dimension is 0. See [Kendall1984] for a discussion of the over-dimensioned case.

    source
    • Kendall1989

      D. G. Kendall, “A Survey of the Statistical Theory of Shape,” Statist. Sci., vol. 4, no. 2, pp. 87–99, May 1989 doi: 10.1214/ss/1177012582.

    • Kendall1984

      D. G. Kendall, “Shape Manifolds, Procrustean Metrics, and Complex Projective Spaces,” Bull. London Math. Soc., vol. 16, no. 2, pp. 81–121, Mar. 1984 doi: 10.1112/blms/16.2.81.

    • Srivastava2016

      A. Srivastava and E. P. Klassen, Functional and Shape Data Analysis. Springer New York, 2016. ISBN: 978-1-4939-4018-9. doi: 10.1007/978-1-4939-4020-2.

    • Guigui2021

      N. Guigui, E. Maignant, A. Trouvé, and X. Pennec, “Parallel Transport on Kendall Shape Spaces,” in Geometric Science of Information, Cham, 2021, pp. 103–110. doi: 10.1007/978-3-030-80209-7_12.

    diff --git a/previews/PR644/manifolds/skewhermitian.html b/previews/PR644/manifolds/skewhermitian.html new file mode 100644 index 0000000000..a13a1491d2 --- /dev/null +++ b/previews/PR644/manifolds/skewhermitian.html @@ -0,0 +1,2 @@ + +Skew-Hermitian matrices · Manifolds.jl

    Skew-hermitian matrices

    Manifolds.SkewHermitianMatricesType
    SkewHermitianMatrices{n,𝔽} <: AbstractDecoratorManifold{𝔽}

    The AbstractManifold $ \operatorname{SkewHerm}(n)$ consisting of the real- or complex-valued skew-hermitian matrices of size $n × n$, i.e. the set

    \[\operatorname{SkewHerm}(n) = \bigl\{p ∈ 𝔽^{n × n}\ \big|\ p^{\mathrm{H}} = -p \bigr\},\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, and the field $𝔽 ∈ \{ ℝ, ℂ, ℍ\}$.

    Though it is slightly redundant, usually the matrices are stored as $n × n$ arrays.

    Note that in this representation, the real-valued part of the diagonal must be zero, which is also reflected in the manifold_dimension.

    Constructor

    SkewHermitianMatrices(n::Int, field::AbstractNumbers=ℝ)

    Generate the manifold of $n × n$ skew-hermitian matrices.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::SkewHermitianMatrices{n,𝔽}, p; kwargs...)

    Check whether p is a valid manifold point on the SkewHermitianMatrices M, i.e. whether p is a skew-hermitian matrix of size (n,n) with values from the corresponding AbstractNumbers 𝔽.

    The tolerance for the skew-symmetry of p can be set using kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::SkewHermitianMatrices{n}, p, X; kwargs... )

    Check whether X is a tangent vector to manifold point p on the SkewHermitianMatrices M, i.e. X must be a skew-hermitian matrix of size (n,n) and its values have to be from the correct AbstractNumbers. The tolerance for the skew-symmetry of p and X can be set using kwargs....

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::SkewHermitianMatrices{n,𝔽})

    Return the dimension of the SkewHermitianMatrices matrix M over the number system 𝔽, i.e.

    \[\dim \mathrm{SkewHerm}(n,ℝ) = \frac{n(n+1)}{2} \dim_ℝ 𝔽 - n,\]

    where $\dim_ℝ 𝔽$ is the real_dimension of $𝔽$. The first term corresponds to only the upper triangular elements of the matrix being unique, and the second term corresponds to the constraint that the real part of the diagonal be zero.

    source
    ManifoldsBase.projectMethod
    project(M::SkewHermitianMatrices, p, X)

    Project the matrix X onto the tangent space at p on the SkewHermitianMatrices M,

    \[\operatorname{proj}_p(X) = \frac{1}{2} \bigl( X - X^{\mathrm{H}} \bigr),\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed.

    source
    ManifoldsBase.projectMethod
    project(M::SkewHermitianMatrices, p)

    Projects p from the embedding onto the SkewHermitianMatrices M, i.e.

    \[\operatorname{proj}_{\operatorname{SkewHerm}(n)}(p) = \frac{1}{2} \bigl( p - p^{\mathrm{H}} \bigr),\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed.

    source
    diff --git a/previews/PR644/manifolds/spdfixeddeterminant.html b/previews/PR644/manifolds/spdfixeddeterminant.html new file mode 100644 index 0000000000..16e6abd730 --- /dev/null +++ b/previews/PR644/manifolds/spdfixeddeterminant.html @@ -0,0 +1,11 @@ + +SPD, fixed determinant · Manifolds.jl

    Symmetric positive definite matrices of fixed determinant

    Manifolds.SPDFixedDeterminantType
    SPDFixedDeterminant{N,D} <: AbstractDecoratorManifold{ℝ}

    The manifold of symmetric positive definite matrices of fixed determinant $d > 0$, i.e.

    \[\mathcal P_d(n) = +\bigl\{ +p ∈ ℝ^{n × n} \ \big|\ a^\mathrm{T}pa > 0 \text{ for all } a ∈ ℝ^{n}\backslash\{0\} + \text{ and } \det(p) = d +\bigr\}.\]

    This manifold is modelled as a submanifold of SymmetricPositiveDefinite(n).

    These matrices are sometimes also called isochoric, which refers to the interpretation of the matrix representing an ellipsoid. All ellipsoids that represent points on this manifold have the same volume.

    The tangent space is modelled the same as for SymmetricPositiveDefinite(n) and consists of all symmetric matrices with zero trace

    \[ T_p\mathcal P_d(n) = + \bigl\{ + X \in \mathbb R^{n×n} \big|\ X=X^\mathrm{T} \text{ and } \operatorname{tr}(p) = 0 + \bigr\},\]

    since for a constant determinant we require that 0 = D\det(p)[Z] = \det(p)\operatorname{tr}(p^{-1}Z) for all tangent vectors $Z$. Additionally we store the tangent vectors as X=p^{-1}Z, i.e. symmetric matrices.

    Constructor

    SPDFixedDeterminant(n::Int, d::Real=1.0)

    generates the manifold $\mathcal P_d(n) \subset \mathcal P(n)$ of determinant $d$, which defaults to 1.

    source

    This manifold can is a submanifold of the symmetric positive definite matrices and hence inherits most properties therefrom.

    The differences are the functions

    ManifoldsBase.check_vectorMethod
    check_vector(M::SPDFixedDeterminant, p, X; kwargs... )

    Check whether X is a tangent vector to manifold point p on the SPDFixedDeterminant M, i.e. X has to be a tangent vector on SymmetricPositiveDefinite, so a symmetric matrix, and additionally fulfill $\operatorname{tr}(X) = 0$.

    The tolerance for the trace check of X can be set using kwargs..., which influences the isapprox-check.

    source
    ManifoldsBase.projectMethod
    Y = project(M::SPDFixedDeterminant{n}, p, X)
    +project!(M::SPDFixedDeterminant{n}, Y, p, X)

    Project the symmetric matrix X onto the tangent space at p of the (sub-)manifold of s.p.d. matrices of determinant M.d (in place of Y), by setting its diagonal (and hence its trace) to zero.

    source
    ManifoldsBase.projectMethod
    q = project(M::SPDFixedDeterminant{n}, p)
    +project!(M::SPDFixedDeterminant{n}, q, p)

    Project the symmetric positive definite (s.p.d.) matrix p from the embedding onto the (sub-)manifold of s.p.d. matrices of determinant M.d (in place of q).

    The formula reads

    \[q = \Bigl(\frac{d}{\det(p)}\Bigr)^{\frac{1}{n}}p\]

    source
    diff --git a/previews/PR644/manifolds/spectrahedron.html b/previews/PR644/manifolds/spectrahedron.html new file mode 100644 index 0000000000..98590642fd --- /dev/null +++ b/previews/PR644/manifolds/spectrahedron.html @@ -0,0 +1,12 @@ + +Spectrahedron · Manifolds.jl

    Spectrahedron

    Manifolds.SpectrahedronType
    Spectrahedron{N,K} <: AbstractDecoratorManifold{ℝ}

    The Spectrahedron manifold, also known as the set of correlation matrices (symmetric positive semidefinite matrices) of rank $k$ with unit trace.

    \[\begin{aligned} +\mathcal S(n,k) = +\bigl\{p ∈ ℝ^{n × n}\ \big|\ &a^\mathrm{T}pa \geq 0 \text{ for all } a ∈ ℝ^{n},\\ +&\operatorname{tr}(p) = \sum_{i=1}^n p_{ii} = 1,\\ +&\text{and } p = qq^{\mathrm{T}} \text{ for } q \in ℝ^{n × k} +\text{ with } \operatorname{rank}(p) = \operatorname{rank}(q) = k +\bigr\}. +\end{aligned}\]

    This manifold is working solely on the matrices $q$. Note that this $q$ is not unique, indeed for any orthogonal matrix $A$ we have $(qA)(qA)^{\mathrm{T}} = qq^{\mathrm{T}} = p$, so the manifold implemented here is the quotient manifold. The unit trace translates to unit frobenius norm of $q$.

    The tangent space at $p$, denoted $T_p\mathcal E(n,k)$, is also represented by matrices $Y\in ℝ^{n × k}$ and reads as

    \[T_p\mathcal S(n,k) = \bigl\{ +X ∈ ℝ^{n × n}\,|\,X = qY^{\mathrm{T}} + Yq^{\mathrm{T}} +\text{ with } \operatorname{tr}(X) = \sum_{i=1}^{n}X_{ii} = 0 +\bigr\}\]

    endowed with the Euclidean metric from the embedding, i.e. from the $ℝ^{n × k}$

    This manifold was for example investigated in[JourneeBachAbsilSepulchre2010].

    Constructor

    Spectrahedron(n,k)

    generates the manifold $\mathcal S(n,k) \subset ℝ^{n × n}$.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::Spectrahedron, q; kwargs...)

    checks, whether q is a valid reprsentation of a point $p=qq^{\mathrm{T}}$ on the Spectrahedron M, i.e. is a matrix of size (N,K), such that $p$ is symmetric positive semidefinite and has unit trace, i.e. $q$ has to have unit frobenius norm. Since by construction $p$ is symmetric, this is not explicitly checked. Since $p$ is by construction positive semidefinite, this is not checked. The tolerances for positive semidefiniteness and unit trace can be set using the kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::Spectrahedron, q, Y; kwargs...)

    Check whether $X = qY^{\mathrm{T}} + Yq^{\mathrm{T}}$ is a tangent vector to $p=qq^{\mathrm{T}}$ on the Spectrahedron M, i.e. atfer check_point of q, Y has to be of same dimension as q and a $X$ has to be a symmetric matrix with trace. The tolerance for the base point check and zero diagonal can be set using the kwargs.... Note that symmetry of $X$ holds by construction and is not explicitly checked.

    source
    ManifoldsBase.projectMethod
    project(M::Spectrahedron, q, Y)

    Project Y onto the tangent space at q, i.e. row-wise onto the Spectrahedron manifold.

    source
    ManifoldsBase.representation_sizeMethod
    representation_size(M::Spectrahedron)

    Return the size of an array representing an element on the Spectrahedron manifold M, i.e. $n × k$, the size of such factor of $p=qq^{\mathrm{T}}$ on $\mathcal M = \mathcal S(n,k)$.

    source
    ManifoldsBase.retractMethod
    retract(M::Spectrahedron, q, Y, ::ProjectionRetraction)

    compute a projection based retraction by projecting $q+Y$ back onto the manifold.

    source

    Literature

    diff --git a/previews/PR644/manifolds/sphere.html b/previews/PR644/manifolds/sphere.html new file mode 100644 index 0000000000..36d8f308c4 --- /dev/null +++ b/previews/PR644/manifolds/sphere.html @@ -0,0 +1,8394 @@ + +Sphere · Manifolds.jl

    Sphere and unit norm arrays

    Manifolds.AbstractSphereType
    AbstractSphere{𝔽} <: AbstractDecoratorManifold{𝔽}

    An abstract type to represent a unit sphere that is represented isometrically in the embedding.

    source

    The classical sphere, i.e. unit norm (real- or complex-valued) vectors can be generated as usual: to create the 2-dimensional sphere (in $ℝ^3$), use Sphere(2) and Sphere(2,ℂ), respectively.

    Manifolds.SphereType
    Sphere{n,𝔽} <: AbstractSphere{𝔽}

    The (unit) sphere manifold $𝕊^{n}$ is the set of all unit norm vectors in $𝔽^{n+1}$. The sphere is represented in the embedding, i.e.

    \[𝕊^{n} := \bigl\{ p \in 𝔽^{n+1}\ \big|\ \lVert p \rVert = 1 \bigr\}\]

    where $𝔽\in\{ℝ,ℂ,ℍ\}$. Note that compared to the ArraySphere, here the argument n of the manifold is the dimension of the manifold, i.e. $𝕊^{n} ⊂ 𝔽^{n+1}$, $n\in ℕ$.

    The tangent space at point $p$ is given by

    \[T_p𝕊^{n} := \bigl\{ X ∈ 𝔽^{n+1}\ |\ \Re(⟨p,X⟩) = 0 \bigr \},\]

    where $𝔽\in\{ℝ,ℂ,ℍ\}$ and $⟨\cdot,\cdot⟩$ denotes the inner product in the embedding $𝔽^{n+1}$.

    For $𝔽=ℂ$, the manifold is the complex sphere, written $ℂ𝕊^n$, embedded in $ℂ^{n+1}$. $ℂ𝕊^n$ is the complexification of the real sphere $𝕊^{2n+1}$. Likewise, the quaternionic sphere $ℍ𝕊^n$ is the quaternionification of the real sphere $𝕊^{4n+3}$. Consequently, $ℂ𝕊^0$ is equivalent to $𝕊^1$ and Circle, while $ℂ𝕊^1$ and $ℍ𝕊^0$ are equivalent to $𝕊^3$, though with different default representations.

    This manifold is modeled as a special case of the more general case, i.e. as an embedded manifold to the Euclidean, and several functions like the inner product and the zero_vector are inherited from the embedding.

    Constructor

    Sphere(n[, field=ℝ])

    Generate the (real-valued) sphere $𝕊^{n} ⊂ ℝ^{n+1}$, where field can also be used to generate the complex- and quaternionic-valued sphere.

    source

    For the higher-dimensional arrays, for example unit (Frobenius) norm matrices, the manifold is generated using the size of the matrix. To create the unit sphere of $3×2$ real-valued matrices, write ArraySphere(3,2) and the complex case is done – as for the Euclidean case – with an keyword argument ArraySphere(3,2; field = ℂ). This case also covers the classical sphere as a special case, but you specify the size of the vectors/embedding instead: The 2-sphere can here be generated ArraySphere(3).

    Manifolds.ArraySphereType
    ArraySphere{T<:Tuple,𝔽} <: AbstractSphere{𝔽}

    The (unit) sphere manifold $𝕊^{n₁,n₂,...,nᵢ}$ is the set of all unit (Frobenius) norm elements of $𝔽^{n₁,n₂,...,nᵢ}$, where 𝔽\in{ℝ,ℂ,ℍ}. The generalized sphere is represented in the embedding, and supports arbitrary sized arrays or in other words arbitrary tensors of unit norm. The set formally reads

    \[𝕊^{n_1, n_2, …, n_i} := \bigl\{ p \in 𝔽^{n_1, n_2, …, n_i}\ \big|\ \lVert p \rVert = 1 \bigr\}\]

    where $𝔽\in\{ℝ,ℂ,ℍ\}$. Setting $i=1$ and $𝔽=ℝ$ this simplifies to unit vectors in $ℝ^n$, see Sphere for this special case. Note that compared to this classical case, the argument for the generalized case here is given by the dimension of the embedding. This means that Sphere(2) and ArraySphere(3) are the same manifold.

    The tangent space at point $p$ is given by

    \[T_p 𝕊^{n_1, n_2, …, n_i} := \bigl\{ X ∈ 𝔽^{n_1, n_2, …, n_i}\ |\ \Re(⟨p,X⟩) = 0 \bigr \},\]

    where $𝔽\in\{ℝ,ℂ,ℍ\}$ and $⟨\cdot,\cdot⟩$ denotes the (Frobenius) inner product in the embedding $𝔽^{n_1, n_2, …, n_i}$.

    This manifold is modeled as an embedded manifold to the Euclidean, i.e. several functions like the inner product and the zero_vector are inherited from the embedding.

    Constructor

    ArraySphere(n₁,n₂,...,nᵢ; field=ℝ)

    Generate sphere in $𝔽^{n_1, n_2, …, n_i}$, where $𝔽$ defaults to the real-valued case $ℝ$.

    source

    There is also one atlas available on the sphere.

    Manifolds.StereographicAtlasType
    StereographicAtlas()

    The stereographic atlas of $S^n$ with two charts: one with the singular point (-1, 0, ..., 0) (called :north) and one with the singular point (1, 0, ..., 0) (called :south).

    source

    Functions on unit spheres

    Base.expMethod
    exp(M::AbstractSphere, p, X)

    Compute the exponential map from p in the tangent direction X on the AbstractSphere M by following the great arc eminating from p in direction X.

    \[\exp_p X = \cos(\lVert X \rVert_p)p + \sin(\lVert X \rVert_p)\frac{X}{\lVert X \rVert_p},\]

    where $\lVert X \rVert_p$ is the norm on the tangent space at p of the AbstractSphere M.

    source
    Base.logMethod
    log(M::AbstractSphere, p, q)

    Compute the logarithmic map on the AbstractSphere M, i.e. the tangent vector, whose geodesic starting from p reaches q after time 1. The formula reads for $x ≠ -y$

    \[\log_p q = d_{𝕊}(p,q) \frac{q-\Re(⟨p,q⟩) p}{\lVert q-\Re(⟨p,q⟩) p \rVert_2},\]

    and a deterministic choice from the set of tangent vectors is returned if $x=-y$, i.e. for opposite points.

    source
    Manifolds.local_metricMethod
    local_metric(M::Sphere{n}, p, ::DefaultOrthonormalBasis)

    return the local representation of the metric in a DefaultOrthonormalBasis, namely the diagonal matrix of size $n×n$ with ones on the diagonal, since the metric is obtained from the embedding by restriction to the tangent space $T_p\mathcal M$ at $p$.

    source
    ManifoldsBase.WeingartenMethod
    Weingarten(M::Sphere, p, X, V)

    Compute the Weingarten map $\mathcal W_p$ at p on the Sphere M with respect to the tangent vector $X \in T_p\mathcal M$ and the normal vector $V \in N_p\mathcal M$.

    The formula is due to [AMT13] given by

    \mathcal W_p(X,V) = -Xp^{\mathrm{T}}V
    source
    ManifoldsBase.check_pointMethod
    check_point(M::AbstractSphere, p; kwargs...)

    Check whether p is a valid point on the AbstractSphere M, i.e. is a point in the embedding of unit length. The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::AbstractSphere, p, X; kwargs... )

    Check whether X is a tangent vector to p on the AbstractSphere M, i.e. after check_point(M,p), X has to be of same dimension as p and orthogonal to p. The tolerance for the last test can be set using the kwargs....

    source
    ManifoldsBase.distanceMethod
    distance(M::AbstractSphere, p, q)

    Compute the geodesic distance betweeen p and q on the AbstractSphere M. The formula is given by the (shorter) great arc length on the (or a) great circle both p and q lie on.

    \[d_{𝕊}(p,q) = \arccos(\Re(⟨p,q⟩)).\]

    source
    ManifoldsBase.get_coordinatesMethod
    get_coordinates(M::AbstractSphere{ℝ}, p, X, B::DefaultOrthonormalBasis)

    Represent the tangent vector X at point p from the AbstractSphere M in an orthonormal basis by rotating the hyperplane containing X to a hyperplane whose normal is the $x$-axis.

    Given $q = p λ + x$, where $λ = \operatorname{sgn}(⟨x, p⟩)$, and $⟨⋅, ⋅⟩_{\mathrm{F}}$ denotes the Frobenius inner product, the formula for $Y$ is

    \[\begin{pmatrix}0 \\ Y\end{pmatrix} = X - q\frac{2 ⟨q, X⟩_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}.\]

    source
    ManifoldsBase.get_vectorMethod
    get_vector(M::AbstractSphere{ℝ}, p, X, B::DefaultOrthonormalBasis)

    Convert a one-dimensional vector of coefficients X in the basis B of the tangent space at p on the AbstractSphere M to a tangent vector Y at p by rotating the hyperplane containing X, whose normal is the $x$-axis, to the hyperplane whose normal is p.

    Given $q = p λ + x$, where $λ = \operatorname{sgn}(⟨x, p⟩)$, and $⟨⋅, ⋅⟩_{\mathrm{F}}$ denotes the Frobenius inner product, the formula for $Y$ is

    \[Y = X - q\frac{2 \left\langle q, \begin{pmatrix}0 \\ X\end{pmatrix}\right\rangle_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}.\]

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::AbstractSphere, p, q, ::ProjectionInverseRetraction)

    Compute the inverse of the projection based retraction on the AbstractSphere M, i.e. rearranging $p+X = q\lVert p+X\rVert_2$ yields since $\Re(⟨p,X⟩) = 0$ and when $d_{𝕊^2}(p,q) ≤ \frac{π}{2}$ that

    \[\operatorname{retr}_p^{-1}(q) = \frac{q}{\Re(⟨p, q⟩)} - p.\]

    source
    ManifoldsBase.parallel_transport_toMethod
    parallel_transport_to(M::AbstractSphere, p, X, q)

    Compute the parallel transport on the Sphere of the tangent vector X at p to q, provided, the geodesic between p and q is unique. The formula reads

    \[P_{p←q}(X) = X - \frac{\Re(⟨\log_p q,X⟩_p)}{d^2_𝕊(p,q)} +\bigl(\log_p q + \log_q p \bigr).\]

    source
    ManifoldsBase.projectMethod
    project(M::AbstractSphere, p, X)

    Project the point X onto the tangent space at p on the Sphere M.

    \[\operatorname{proj}_{p}(X) = X - \Re(⟨p, X⟩)p\]

    source
    ManifoldsBase.projectMethod
    project(M::AbstractSphere, p)

    Project the point p from the embedding onto the Sphere M.

    \[\operatorname{proj}(p) = \frac{p}{\lVert p \rVert},\]

    where $\lVert\cdot\rVert$ denotes the usual 2-norm for vectors if $m=1$ and the Frobenius norm for the case $m>1$.

    source
    ManifoldsBase.retractMethod
    retract(M::AbstractSphere, p, X, ::ProjectionRetraction)

    Compute the retraction that is based on projection, i.e.

    \[\operatorname{retr}_p(X) = \frac{p+X}{\lVert p+X \rVert_2}\]

    source

    Visualization on Sphere{2,ℝ}

    You can visualize both points and tangent vectors on the sphere.

    Note

    There seems to be no unified way to draw spheres in the backends of Plots.jl. This recipe currently uses the seriestype wireframe and surface, which does not yet work with the default backend GR.

    In general you can plot the surface of the hyperboloid either as wireframe (wireframe=true) additionally specifying wires (or wires_x and wires_y) to change the density of the wires and a wireframe_color for their color. The same holds for the plot as a surface (which is false by default) and its surface_resolution (or surface_resolution_lat or surface_resolution_lon) and a surface_color.

    using Manifolds, Plots
    +pythonplot()
    +M = Sphere(2)
    +pts = [ [1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0] ]
    +scene = plot(M, pts; wireframe_color=colorant"#CCCCCC", markersize=10)
    + + + + + + + 2023-08-20T11:42:27.940990 + image/svg+xml + + + Matplotlib v3.7.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    which scatters our points. We can also draw connecting geodesics, which here is a geodesic triangle. Here we discretize each geodesic with 100 points along the geodesic. The default value is geodesic_interpolation=-1 which switches to scatter plot of the data.

    plot!(scene, M, pts; wireframe=false, geodesic_interpolation=100, linewidth=2)
    + + + + + + + 2023-08-20T11:42:29.405724 + image/svg+xml + + + Matplotlib v3.7.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    And we can also add tangent vectors, for example tangents pointing towards the geometric center of given points.

    pts2 =  [ [1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0] ]
    +p3 = 1/sqrt(3) .* [1.0, -1.0, 1.0]
    +vecs = log.(Ref(M), pts2, Ref(p3))
    +plot!(scene, M, pts2, vecs; wireframe = false, linewidth=1.5)
    + + + + + + + 2023-08-20T11:42:30.477874 + image/svg+xml + + + Matplotlib v3.7.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Literature

    [AMT13]
    +
    + +
    +
    • MuralidharanFletcher2021

      P. Muralidharan and P. T. Fletcher, “Sasaki Metrics for Analysis of Longitudinal Data on Manifolds,” Proc IEEE Comput Soc Conf Comput Vis Pattern Recognit, vol. 2012, pp. 1027–1034, Jun. 2012, doi: 10.1109/CVPR.2012.6247780.

    diff --git a/previews/PR644/manifolds/spheresymmetricmatrices.html b/previews/PR644/manifolds/spheresymmetricmatrices.html new file mode 100644 index 0000000000..587065c41c --- /dev/null +++ b/previews/PR644/manifolds/spheresymmetricmatrices.html @@ -0,0 +1,5 @@ + +Unit-norm symmetric matrices · Manifolds.jl

    Unit-norm symmetric matrices

    Manifolds.SphereSymmetricMatricesType
    SphereSymmetricMatrices{n,𝔽} <: AbstractEmbeddedManifold{ℝ,TransparentIsometricEmbedding}

    The AbstractManifold consisting of the $n × n$ symmetric matrices of unit Frobenius norm, i.e.

    \[\mathcal{S}_{\text{sym}} :=\bigl\{p ∈ 𝔽^{n × n}\ \big|\ p^{\mathrm{H}} = p, \lVert p \rVert = 1 \bigr\},\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, and the field $𝔽 ∈ \{ ℝ, ℂ\}$.

    Constructor

    SphereSymmetricMatrices(n[, field=ℝ])

    Generate the manifold of n-by-n symmetric matrices of unit Frobenius norm.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::SphereSymmetricMatrices{n,𝔽}, p; kwargs...)

    Check whether the matrix is a valid point on the SphereSymmetricMatrices M, i.e. is an n-by-n symmetric matrix of unit Frobenius norm.

    The tolerance for the symmetry of p can be set using kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::SphereSymmetricMatrices{n,𝔽}, p, X; kwargs... )

    Check whether X is a tangent vector to manifold point p on the SphereSymmetricMatrices M, i.e. X has to be a symmetric matrix of size (n,n) of unit Frobenius norm.

    The tolerance for the symmetry of p and X can be set using kwargs....

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::SphereSymmetricMatrices{n,𝔽})

    Return the manifold dimension of the SphereSymmetricMatrices n-by-n symmetric matrix M of unit Frobenius norm over the number system 𝔽, i.e.

    \[\begin{aligned} +\dim(\mathcal{S}_{\text{sym}})(n,ℝ) &= \frac{n(n+1)}{2} - 1,\\ +\dim(\mathcal{S}_{\text{sym}})(n,ℂ) &= 2\frac{n(n+1)}{2} - n -1. +\end{aligned}\]

    source
    ManifoldsBase.projectMethod
    project(M::SphereSymmetricMatrices, p, X)

    Project the matrix X onto the tangent space at p on the SphereSymmetricMatrices M, i.e.

    \[\operatorname{proj}_p(X) = \frac{X + X^{\mathrm{H}}}{2} - ⟨p, \frac{X + X^{\mathrm{H}}}{2}⟩p,\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed.

    source
    ManifoldsBase.projectMethod
    project(M::SphereSymmetricMatrices, p)

    Projects p from the embedding onto the SphereSymmetricMatrices M, i.e.

    \[\operatorname{proj}_{\mathcal{S}_{\text{sym}}}(p) = \frac{1}{2} \bigl( p + p^{\mathrm{H}} \bigr),\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed.

    source
    diff --git a/previews/PR644/manifolds/stiefel.html b/previews/PR644/manifolds/stiefel.html new file mode 100644 index 0000000000..edaadeb77b --- /dev/null +++ b/previews/PR644/manifolds/stiefel.html @@ -0,0 +1,85 @@ + +Stiefel · Manifolds.jl

    Stiefel

    Common and metric independent functions

    Manifolds.StiefelType
    Stiefel{n,k,𝔽} <: AbstractDecoratorManifold{𝔽}

    The Stiefel manifold consists of all $n × k$, $n ≥ k$ unitary matrices, i.e.

    \[\operatorname{St}(n,k) = \bigl\{ p ∈ 𝔽^{n × k}\ \big|\ p^{\mathrm{H}}p = I_k \bigr\},\]

    where $𝔽 ∈ \{ℝ, ℂ\}$, $\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and $I_k ∈ ℝ^{k × k}$ denotes the $k × k$ identity matrix.

    The tangent space at a point $p ∈ \mathcal M$ is given by

    \[T_p \mathcal M = \{ X ∈ 𝔽^{n × k} : p^{\mathrm{H}}X + \overline{X^{\mathrm{H}}p} = 0_k\},\]

    where $0_k$ is the $k × k$ zero matrix and $\overline{\cdot}$ the (elementwise) complex conjugate.

    This manifold is modeled as an embedded manifold to the Euclidean, i.e. several functions like the inner product and the zero_vector are inherited from the embedding.

    The manifold is named after Eduard L. Stiefel (1909–1978).

    Constructor

    Stiefel(n, k, field = ℝ)

    Generate the (real-valued) Stiefel manifold of $n × k$ dimensional orthonormal matrices.

    source
    Base.randMethod
    rand(::Stiefel; vector_at=nothing, σ::Real=1.0)

    When vector_at is nothing, return a random (Gaussian) point x on the Stiefel manifold M by generating a (Gaussian) matrix with standard deviation σ and return the orthogonalized version, i.e. return the Q component of the QR decomposition of the random matrix of size $n×k$.

    When vector_at is not nothing, return a (Gaussian) random vector from the tangent space $T_{vector\_at}\mathrm{St}(n,k)$ with mean zero and standard deviation σ by projecting a random Matrix onto the tangent vector at vector_at.

    source
    Manifolds.uniform_distributionMethod
    uniform_distribution(M::Stiefel{n,k,ℝ}, p)

    Uniform distribution on given (real-valued) Stiefel M. Specifically, this is the normalized Haar and Hausdorff measure on M. Generated points will be of similar type as p.

    The implementation is based on Section 2.5.1 in [Chikuse2003]; see also Theorem 2.2.1(iii) in [Chikuse2003].

    source
    ManifoldsBase.change_metricMethod
    change_metric(M::Stiefel, ::EuclideanMetric, p X)

    Change X to the corresponding vector with respect to the metric of the Stiefel M, which is just the identity, since the manifold is isometrically embedded.

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::Stiefel, ::EuclideanMetric, p, X)

    Change X to the corresponding representer of a cotangent vector at p. Since the Stiefel manifold M, is isometrically embedded, this is the identity

    source
    ManifoldsBase.check_pointMethod
    check_point(M::Stiefel, p; kwargs...)

    Check whether p is a valid point on the Stiefel M=$\operatorname{St}(n,k)$, i.e. that it has the right AbstractNumbers type and $p^{\mathrm{H}}p$ is (approximately) the identity, where $\cdot^{\mathrm{H}}$ is the complex conjugate transpose. The settings for approximately can be set with kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::Stiefel, p, X; kwargs...)

    Checks whether X is a valid tangent vector at p on the Stiefel M=$\operatorname{St}(n,k)$, i.e. the AbstractNumbers fits and it (approximately) holds that $p^{\mathrm{H}}X + \overline{X^{\mathrm{H}}p} = 0$, where $\cdot^{\mathrm{H}}$ denotes the Hermitian and $\overline{\cdot}$ the (elementwise) complex conjugate. The settings for approximately can be set with kwargs....

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::Stiefel, p, q, ::PolarInverseRetraction)

    Compute the inverse retraction based on a singular value decomposition for two points p, q on the Stiefel manifold M. This follows the folloing approach: From the Polar retraction we know that

    \[\operatorname{retr}_p^{-1}q = qs - t\]

    if such a symmetric positive definite $k × k$ matrix exists. Since $qs - t$ is also a tangent vector at $p$ we obtain

    \[p^{\mathrm{H}}qs + s(p^{\mathrm{H}}q)^{\mathrm{H}} + 2I_k = 0,\]

    which can either be solved by a Lyapunov approach or a continuous-time algebraic Riccati equation.

    This implementation follows the Lyapunov approach.

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::Stiefel)

    Return the dimension of the Stiefel manifold M=$\operatorname{St}(n,k,𝔽)$. The dimension is given by

    \[\begin{aligned} +\dim \mathrm{St}(n, k, ℝ) &= nk - \frac{1}{2}k(k+1)\\ +\dim \mathrm{St}(n, k, ℂ) &= 2nk - k^2\\ +\dim \mathrm{St}(n, k, ℍ) &= 4nk - k(2k-1) +\end{aligned}\]

    source
    ManifoldsBase.retractMethod
    retract(::Stiefel, p, X, ::CayleyRetraction)

    Compute the retraction on the Stiefel that is based on the Cayley transform[Zhu2017]. Using

    \[ W_{p,X} = \operatorname{P}_pXp^{\mathrm{H}} - pX^{\mathrm{H}}\operatorname{P_p} + \quad\text{where} + \operatorname{P}_p = I - \frac{1}{2}pp^{\mathrm{H}}\]

    the formula reads

    \[ \operatorname{retr}_pX = \Bigl(I - \frac{1}{2}W_{p,X}\Bigr)^{-1}\Bigl(I + \frac{1}{2}W_{p,X}\Bigr)p.\]

    It is implemented as the case $m=1$ of the PadeRetraction.

    source
    ManifoldsBase.retractMethod
    retract(M::Stiefel, p, X, ::PadeRetraction{m})

    Compute the retraction on the Stiefel manifold M based on the Padé approximation of order $m$[ZhuDuan2018]. Let $p_m$ and $q_m$ be defined for any matrix $A ∈ ℝ^{n×x}$ as

    \[ p_m(A) = \sum_{k=0}^m \frac{(2m-k)!m!}{(2m)!(m-k)!}\frac{A^k}{k!}\]

    and

    \[ q_m(A) = \sum_{k=0}^m \frac{(2m-k)!m!}{(2m)!(m-k)!}\frac{(-A)^k}{k!}\]

    respectively. Then the Padé approximation (of the matrix exponential $\exp(A)$) reads

    \[ r_m(A) = q_m(A)^{-1}p_m(A)\]

    Defining further

    \[ W_{p,X} = \operatorname{P}_pXp^{\mathrm{H}} - pX^{\mathrm{H}}\operatorname{P_p} + \quad\text{where } + \operatorname{P}_p = I - \frac{1}{2}pp^{\mathrm{H}}\]

    the retraction reads

    \[ \operatorname{retr}_pX = r_m(W_{p,X})p\]

    source
    ManifoldsBase.retractMethod
    retract(M::Stiefel, p, X, ::PolarRetraction)

    Compute the SVD-based retraction PolarRetraction on the Stiefel manifold M. With $USV = p + X$ the retraction reads

    \[\operatorname{retr}_p X = U\bar{V}^\mathrm{H}.\]

    source
    ManifoldsBase.retractMethod
    retract(M::Stiefel, p, X, ::QRRetraction)

    Compute the QR-based retraction QRRetraction on the Stiefel manifold M. With $QR = p + X$ the retraction reads

    \[\operatorname{retr}_p X = QD,\]

    where $D$ is a $n × k$ matrix with

    \[D = \operatorname{diag}\bigl(\operatorname{sgn}(R_{ii}+0,5)_{i=1}^k \bigr),\]

    where $\operatorname{sgn}(p) = \begin{cases} 1 & \text{ for } p > 0,\\ +0 & \text{ for } p = 0,\\ +-1& \text{ for } p < 0. \end{cases}$

    source
    ManifoldsBase.vector_transport_directionMethod
    vector_transport_direction(::Stiefel, p, X, d, ::DifferentiatedRetractionVectorTransport{CayleyRetraction})

    Compute the vector transport given by the differentiated retraction of the CayleyRetraction, cf. [Zhu2017] Equation (17).

    The formula reads

    \[\operatorname{T}_{p,d}(X) = +\Bigl(I - \frac{1}{2}W_{p,d}\Bigr)^{-1}W_{p,X}\Bigl(I - \frac{1}{2}W_{p,d}\Bigr)^{-1}p,\]

    with

    \[ W_{p,X} = \operatorname{P}_pXp^{\mathrm{H}} - pX^{\mathrm{H}}\operatorname{P_p} + \quad\text{where } + \operatorname{P}_p = I - \frac{1}{2}pp^{\mathrm{H}}\]

    Since this is the differentiated retraction as a vector transport, the result will be in the tangent space at $q=\operatorname{retr}_p(d)$ using the CayleyRetraction.

    source
    ManifoldsBase.vector_transport_directionMethod
    vector_transport_direction(M::Stiefel, p, X, d, DifferentiatedRetractionVectorTransport{PolarRetraction})

    Compute the vector transport by computing the push forward of retract(::Stiefel, ::Any, ::Any, ::PolarRetraction) Section 3.5 of [Zhu2017]:

    \[T_{p,d}^{\text{Pol}}(X) = q*Λ + (I-qq^{\mathrm{T}})X(1+d^\mathrm{T}d)^{-\frac{1}{2}},\]

    where $q = \operatorname{retr}^{\mathrm{Pol}}_p(d)$, and $Λ$ is the unique solution of the Sylvester equation

    \[ Λ(I+d^\mathrm{T}d)^{\frac{1}{2}} + (I + d^\mathrm{T}d)^{\frac{1}{2}} = q^\mathrm{T}X - X^\mathrm{T}q\]

    source
    ManifoldsBase.vector_transport_directionMethod
    vector_transport_direction(M::Stiefel, p, X, d, DifferentiatedRetractionVectorTransport{QRRetraction})

    Compute the vector transport by computing the push forward of the retract(::Stiefel, ::Any, ::Any, ::QRRetraction), See [AbsilMahonySepulchre2008], p. 173, or Section 3.5 of [Zhu2017].

    \[T_{p,d}^{\text{QR}}(X) = q*\rho_{\mathrm{s}}(q^\mathrm{T}XR^{-1}) + (I-qq^{\mathrm{T}})XR^{-1},\]

    where $q = \operatorname{retr}^{\mathrm{QR}}_p(d)$, $R$ is the $R$ factor of the QR decomposition of $p + d$, and

    \[\bigl( \rho_{\mathrm{s}}(A) \bigr)_{ij} += \begin{cases} +A_{ij}&\text{ if } i > j\\ +0 \text{ if } i = j\\ +-A_{ji} \text{ if } i < j.\\ +\end{cases}\]

    source
    ManifoldsBase.vector_transport_toMethod
    vector_transport_to(M::Stiefel, p, X, q, DifferentiatedRetractionVectorTransport{PolarRetraction})

    Compute the vector transport by computing the push forward of the retract(M::Stiefel, ::Any, ::Any, ::PolarRetraction), see Section 4 of [HuangGallivanAbsil2015] or Section 3.5 of [Zhu2017]:

    \[T_{q\gets p}^{\text{Pol}}(X) = q*Λ + (I-qq^{\mathrm{T}})X(1+d^\mathrm{T}d)^{-\frac{1}{2}},\]

    where $d = \bigl( \operatorname{retr}^{\mathrm{Pol}}_p\bigr)^{-1}(q)$, and $Λ$ is the unique solution of the Sylvester equation

    \[ Λ(I+d^\mathrm{T}d)^{\frac{1}{2}} + (I + d^\mathrm{T}d)^{\frac{1}{2}} = q^\mathrm{T}X - X^\mathrm{T}q\]

    source
    ManifoldsBase.vector_transport_toMethod
    vector_transport_to(M::Stiefel, p, X, q, DifferentiatedRetractionVectorTransport{QRRetraction})

    Compute the vector transport by computing the push forward of the retract(M::Stiefel, ::Any, ::Any, ::QRRetraction), see [AbsilMahonySepulchre2008], p. 173, or Section 3.5 of [Zhu2017].

    \[T_{q \gets p}^{\text{QR}}(X) = q*\rho_{\mathrm{s}}(q^\mathrm{T}XR^{-1}) + (I-qq^{\mathrm{T}})XR^{-1},\]

    where $d = \bigl(\operatorname{retr}^{\mathrm{QR}}\bigr)^{-1}_p(q)$, $R$ is the $R$ factor of the QR decomposition of $p+X$, and

    \[\bigl( \rho_{\mathrm{s}}(A) \bigr)_{ij} += \begin{cases} +A_{ij}&\text{ if } i > j\\ +0 \text{ if } i = j\\ +-A_{ji} \text{ if } i < j.\\ +\end{cases}\]

    source
    ManifoldsBase.vector_transport_toMethod
    vector_transport_to(M::Stiefel, p, X, q, ::ProjectionTransport)

    Compute a vector transport by projection, i.e. project X from the tangent space at p by projection it onto the tangent space at q.

    source

    Default metric: the Euclidean metric

    The EuclideanMetric is obtained from the embedding of the Stiefel manifold in $ℝ^{n,k}$.

    Base.expMethod
    exp(M::Stiefel, p, X)

    Compute the exponential map on the Stiefel{n,k,𝔽}() manifold M emanating from p in tangent direction X.

    \[\exp_p X = \begin{pmatrix} + p\\X + \end{pmatrix} + \operatorname{Exp} + \left( + \begin{pmatrix} p^{\mathrm{H}}X & - X^{\mathrm{H}}X\\ + I_n & p^{\mathrm{H}}X\end{pmatrix} + \right) +\begin{pmatrix} \exp( -p^{\mathrm{H}}X) \\ 0_n\end{pmatrix},\]

    where $\operatorname{Exp}$ denotes matrix exponential, $\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and $I_k$ and $0_k$ are the identity matrix and the zero matrix of dimension $k × k$, respectively.

    source
    ManifoldDiff.riemannian_HessianMethod
    riemannian_Hessian(M::Stiefel, p, G, H, X)

    The Riemannian Hessian can be computed by adopting Eq. (5.6) [Ngu23], where we use for the EuclideanMetric $α_0=α_1=1$ in their formula. Let $\nabla f(p)$ denote the Euclidean gradient G, $\nabla^2 f(p)[X]$ the Euclidean Hessian H. Then the formula reads

    \[ \operatorname{Hess}f(p)[X] + = + \operatorname{proj}_{T_p\mathcal M}\Bigl( + ∇^2f(p)[X] - \frac{1}{2} X \bigl((∇f(p))^{\mathrm{H}p + p^{\mathrm{H}}∇f(p)\bigr) + \Bigr).\]

    Compared to Eq. (5.6) also the metric conversion simplifies to the identity.

    source
    ManifoldsBase.WeingartenMethod
    Weingarten(M::Stiefel, p, X, V)

    Compute the Weingarten map $\mathcal W_p$ at p on the Stiefel M with respect to the tangent vector $X \in T_p\mathcal M$ and the normal vector $V \in N_p\mathcal M$.

    The formula is due to [AMT13] given by

    \[\mathcal W_p(X,V) = -Xp^{\mathrm{T}}V - \frac{1}{2}p\bigl(X^\mathrm{T}V + V^{\mathrm{T}}X\bigr)\]

    source
    ManifoldsBase.get_basisMethod
    get_basis(M::Stiefel{n,k,ℝ}, p, B::DefaultOrthonormalBasis) where {n,k}

    Create the default basis using the parametrization for any $X ∈ T_p\mathcal M$. Set $p_\bot \in ℝ^{n\times(n-k)}$ the matrix such that the $n\times n$ matrix of the common columns $[p\ p_\bot]$ is an ONB. For any skew symmetric matrix $a ∈ ℝ^{k\times k}$ and any $b ∈ ℝ^{(n-k)\times k}$ the matrix

    \[X = pa + p_\bot b ∈ T_p\mathcal M\]

    and we can use the $\frac{1}{2}k(k-1) + (n-k)k = nk-\frac{1}{2}k(k+1)$ entries of $a$ and $b$ to specify a basis for the tangent space. using unit vectors for constructing both the upper matrix of $a$ to build a skew symmetric matrix and the matrix b, the default basis is constructed.

    Since $[p\ p_\bot]$ is an automorphism on $ℝ^{n\times p}$ the elements of $a$ and $b$ are orthonormal coordinates for the tangent space. To be precise exactly one element in the upper trangular entries of $a$ is set to $1$ its symmetric entry to $-1$ and we normalize with the factor $\frac{1}{\sqrt{2}}$ and for $b$ one can just use unit vectors reshaped to a matrix to obtain orthonormal set of parameters.

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::Stiefel, p, q, method::ProjectionInverseRetraction)

    Compute a projection-based inverse retraction.

    The inverse retraction is computed by projecting the logarithm map in the embedding to the tangent space at $p$.

    source
    ManifoldsBase.projectMethod
    project(M::Stiefel,p)

    Projects p from the embedding onto the Stiefel M, i.e. compute q as the polar decomposition of $p$ such that $q^{\mathrm{H}}q$ is the identity, where $\cdot^{\mathrm{H}}$ denotes the hermitian, i.e. complex conjugate transposed.

    source
    ManifoldsBase.projectMethod
    project(M::Stiefel, p, X)

    Project X onto the tangent space of p to the Stiefel manifold M. The formula reads

    \[\operatorname{proj}_{T_p\mathcal M}(X) = X - p \operatorname{Sym}(p^{\mathrm{H}}X),\]

    where $\operatorname{Sym}(q)$ is the symmetrization of $q$, e.g. by $\operatorname{Sym}(q) = \frac{q^{\mathrm{H}}+q}{2}$.

    source
    ManifoldsBase.retractMethod
    retract(M::Stiefel, p, X, method::ProjectionRetraction)

    Compute a projection-based retraction.

    The retraction is computed by projecting the exponential map in the embedding to M.

    source

    The canonical metric

    Any $X∈T_p\mathcal M$, $p∈\mathcal M$, can be written as

    \[X = pA + (I_n-pp^{\mathrm{T}})B, +\quad +A ∈ ℝ^{p×p} \text{ skew-symmetric}, +\quad +B ∈ ℝ^{n×p} \text{ arbitrary.}\]

    In the EuclideanMetric, the elements from $A$ are counted twice (i.e. weighted with a factor of 2). The canonical metric avoids this.

    Base.expMethod
    q = exp(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, CanonicalMetric}, p, X)
    +exp!(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, q, CanonicalMetric}, p, X)

    Compute the exponential map on the Stiefel(n,k) manifold with respect to the CanonicalMetric.

    First, decompose The tangent vector $X$ into its horizontal and vertical component with respect to $p$, i.e.

    \[X = pp^{\mathrm{T}}X + (I_n-pp^{\mathrm{T}})X,\]

    where $I_n$ is the $n\times n$ identity matrix. We introduce $A=p^{\mathrm{T}}X$ and $QR = (I_n-pp^{\mathrm{T}})X$ the qr decomposition of the vertical component. Then using the matrix exponential $\operatorname{Exp}$ we introduce $B$ and $C$ as

    \[\begin{pmatrix} +B\\C +\end{pmatrix} +\coloneqq +\operatorname{Exp}\left( +\begin{pmatrix} +A & -R^{\mathrm{T}}\\ R & 0 +\end{pmatrix} +\right) +\begin{pmatrix}I_k\\0\end{pmatrix}\]

    the exponential map reads

    \[q = \exp_p X = pC + QB.\]

    For more details, see [EdelmanAriasSmith1998][Zimmermann2017].

    source
    ManifoldsBase.innerMethod
    inner(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, X, CanonicalMetric}, p, X, Y)

    Compute the inner product on the Stiefel manifold with respect to the CanonicalMetric. The formula reads

    \[g_p(X,Y) = \operatorname{tr}\bigl( X^{\mathrm{T}}(I_n - \frac{1}{2}pp^{\mathrm{T}})Y \bigr).\]

    source
    ManifoldsBase.inverse_retractMethod
    X = inverse_retract(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, CanonicalMetric}, p, q, a::ApproximateLogarithmicMap)
    +inverse_retract!(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, X, CanonicalMetric}, p, q, a::ApproximateLogarithmicMap)

    Compute an approximation to the logarithmic map on the Stiefel(n,k) manifold with respect to the CanonicalMetric using a matrix-algebraic based approach to an iterative inversion of the formula of the exp.

    The algorithm is derived in[Zimmermann2017] and it uses the max_iterations and the tolerance field from the ApproximateLogarithmicMap.

    source

    The submersion or normal metric

    Manifolds.StiefelSubmersionMetricType
    StiefelSubmersionMetric{T<:Real} <: RiemannianMetric

    The submersion (or normal) metric family on the Stiefel manifold.

    The family, with a single real parameter $α>-1$, has two special cases:

    The family was described in [HüperMarkinaLeite2021]. This implementation follows the description in [ZimmermanHüper2022].

    Constructor

    StiefelSubmersionMetric(α)

    Construct the submersion metric on the Stiefel manifold with the parameter $α$.

    source
    Base.expMethod
    q = exp(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, <:StiefelSubmersionMetric}, p, X)
    +exp!(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, q, <:StiefelSubmersionMetric}, p, X)

    Compute the exponential map on the Stiefel(n,k) manifold with respect to the StiefelSubmersionMetric.

    The exponential map is given by

    \[\exp_p X = \operatorname{Exp}\bigl( + -\frac{2α+1}{α+1} p p^\mathrm{T} X p^\mathrm{T} + + X p^\mathrm{T} - p X^\mathrm{T} +\bigr) p \operatorname{Exp}\bigl(\frac{\alpha}{\alpha+1} p^\mathrm{T} X\bigr)\]

    This implementation is based on [ZimmermanHüper2022].

    For $k < \frac{n}{2}$ the exponential is computed more efficiently using StiefelFactorization.

    source
    Base.logMethod
    log(M::MetricManifold{ℝ,Stiefel{n,k,ℝ},<:StiefelSubmersionMetric}, p, q; kwargs...)

    Compute the logarithmic map on the Stiefel(n,k) manifold with respect to the StiefelSubmersionMetric.

    The logarithmic map is computed using ShootingInverseRetraction. For $k ≤ \lfloor\frac{n}{2}\rfloor$, this is sped up using the $k$-shooting method of [ZimmermanHüper2022]. Keyword arguments are forwarded to ShootingInverseRetraction; see that documentation for details. Their defaults are:

    • num_transport_points=4
    • tolerance=sqrt(eps())
    • max_iterations=1_000
    source
    ManifoldsBase.innerMethod
    inner(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, X, <:StiefelSubmersionMetric}, p, X, Y)

    Compute the inner product on the Stiefel manifold with respect to the StiefelSubmersionMetric. The formula reads

    \[g_p(X,Y) = \operatorname{tr}\bigl( X^{\mathrm{T}}(I_n - \frac{2α+1}{2(α+1)}pp^{\mathrm{T}})Y \bigr),\]

    where $α$ is the parameter of the metric.

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(
    +    M::MetricManifold{ℝ,Stiefel{n,k,ℝ},<:StiefelSubmersionMetric},
    +    p,
    +    q,
    +    method::ShootingInverseRetraction,
    +)

    Compute the inverse retraction using ShootingInverseRetraction.

    In general the retraction is computed using the generic shooting method.

    inverse_retract(
    +    M::MetricManifold{ℝ,Stiefel{n,k,ℝ},<:StiefelSubmersionMetric},
    +    p,
    +    q,
    +    method::ShootingInverseRetraction{
    +        ExponentialRetraction,
    +        ProjectionInverseRetraction,
    +        <:Union{ProjectionTransport,ScaledVectorTransport{ProjectionTransport}},
    +    },
    +)

    Compute the inverse retraction using ShootingInverseRetraction more efficiently.

    For $k < \frac{n}{2}$ the retraction is computed more efficiently using StiefelFactorization.

    source

    Internal types and functions

    Manifolds.StiefelFactorizationType
    StiefelFactorization{UT,XT} <: AbstractManifoldPoint

    Represent points (and vectors) on Stiefel(n, k) with $2k × k$ factors.[ZimmermanHüper2022]

    Given a point $p ∈ \mathrm{St}(n, k)$ and another matrix $B ∈ ℝ^{n × k}$ for $k ≤ \lfloor\frac{n}{2}\rfloor$ the factorization is

    \[\begin{aligned} +B &= UZ\\ +U &= \begin{bmatrix}p & Q\end{bmatrix} ∈ \mathrm{St}(n, 2k)\\ +Z &= \begin{bmatrix}Z_1 \\ Z_2\end{bmatrix}, \quad Z_1,Z_2 ∈ ℝ^{k × k}. +\end{aligned}\]

    If $B ∈ \mathrm{St}(n, k)$, then $Z ∈ \mathrm{St}(2k, k)$. Note that not every matrix $B$ can be factorized in this way.

    For a fixed $U$, if $r ∈ \mathrm{St}(n, k)$ has the factor $Z_r ∈ \mathrm{St}(2k, k)$, then $X_r ∈ T_r \mathrm{St}(n, k)$ has the factor $Z_{X_r} ∈ T_{Z_r} \mathrm{St}(2k, k)$.

    $Q$ is determined by choice of a second matrix $A ∈ ℝ^{n × k}$ with the decomposition

    \[\begin{aligned} +A &= UZ\\ +Z_1 &= p^\mathrm{T} A \\ +Q Z_2 &= (I - p p^\mathrm{T}) A, +\end{aligned}\]

    where here $Q Z_2$ is the any decomposition that produces $Q ∈ \mathrm{St}(n, k)$, for which we choose the QR decomposition.

    This factorization is useful because it is closed under addition, subtraction, scaling, projection, and the Riemannian exponential and logarithm under the StiefelSubmersionMetric. That is, if all matrices involved are factorized to have the same $U$, then all of these operations and any algorithm that depends only on them can be performed in terms of the $2k × k$ matrices $Z$. For $n ≫ k$, this can be much more efficient than working with the full matrices.

    Warning

    This type is intended strictly for internal use and should not be directly used.

    source

    Literature

    [AMT13]
    +
    + +
    [Ngu23]
    +
    +
    D. Nguyen. Operator-Valued Formulas for Riemannian Gradient and Hessian and Families of Tractable Metrics in Riemannian Optimization. Journal of Optimization Theory and Applications 198, 135–164 (2023).
    +
    +
    diff --git a/previews/PR644/manifolds/symmetric.html b/previews/PR644/manifolds/symmetric.html new file mode 100644 index 0000000000..5c61d99439 --- /dev/null +++ b/previews/PR644/manifolds/symmetric.html @@ -0,0 +1,5 @@ + +Symmetric matrices · Manifolds.jl

    Symmetric matrices

    Manifolds.SymmetricMatricesType
    SymmetricMatrices{n,𝔽} <: AbstractDecoratorManifold{𝔽}

    The AbstractManifold $ \operatorname{Sym}(n)$ consisting of the real- or complex-valued symmetric matrices of size $n × n$, i.e. the set

    \[\operatorname{Sym}(n) = \bigl\{p ∈ 𝔽^{n × n}\ \big|\ p^{\mathrm{H}} = p \bigr\},\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, and the field $𝔽 ∈ \{ ℝ, ℂ\}$.

    Though it is slightly redundant, usually the matrices are stored as $n × n$ arrays.

    Note that in this representation, the complex valued case has to have a real-valued diagonal, which is also reflected in the manifold_dimension.

    Constructor

    SymmetricMatrices(n::Int, field::AbstractNumbers=ℝ)

    Generate the manifold of $n × n$ symmetric matrices.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::SymmetricMatrices{n,𝔽}, p; kwargs...)

    Check whether p is a valid manifold point on the SymmetricMatrices M, i.e. whether p is a symmetric matrix of size (n,n) with values from the corresponding AbstractNumbers 𝔽.

    The tolerance for the symmetry of p can be set using kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::SymmetricMatrices{n,𝔽}, p, X; kwargs... )

    Check whether X is a tangent vector to manifold point p on the SymmetricMatrices M, i.e. X has to be a symmetric matrix of size (n,n) and its values have to be from the correct AbstractNumbers.

    The tolerance for the symmetry of X can be set using kwargs....

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::SymmetricMatrices{n,𝔽})

    Return the dimension of the SymmetricMatrices matrix M over the number system 𝔽, i.e.

    \[\begin{aligned} +\dim \mathrm{Sym}(n,ℝ) &= \frac{n(n+1)}{2},\\ +\dim \mathrm{Sym}(n,ℂ) &= 2\frac{n(n+1)}{2} - n = n^2, +\end{aligned}\]

    where the last $-n$ is due to the zero imaginary part for Hermitian matrices

    source
    ManifoldsBase.projectMethod
    project(M::SymmetricMatrices, p, X)

    Project the matrix X onto the tangent space at p on the SymmetricMatrices M,

    \[\operatorname{proj}_p(X) = \frac{1}{2} \bigl( X + X^{\mathrm{H}} \bigr),\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed.

    source
    ManifoldsBase.projectMethod
    project(M::SymmetricMatrices, p)

    Projects p from the embedding onto the SymmetricMatrices M, i.e.

    \[\operatorname{proj}_{\operatorname{Sym}(n)}(p) = \frac{1}{2} \bigl( p + p^{\mathrm{H}} \bigr),\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed.

    source
    diff --git a/previews/PR644/manifolds/symmetricpositivedefinite.html b/previews/PR644/manifolds/symmetricpositivedefinite.html new file mode 100644 index 0000000000..75c87e67da --- /dev/null +++ b/previews/PR644/manifolds/symmetricpositivedefinite.html @@ -0,0 +1,54 @@ + +Symmetric positive definite · Manifolds.jl

    Symmetric positive definite matrices

    Manifolds.SymmetricPositiveDefiniteType
    SymmetricPositiveDefinite{N} <: AbstractDecoratorManifold{ℝ}

    The manifold of symmetric positive definite matrices, i.e.

    \[\mathcal P(n) = +\bigl\{ +p ∈ ℝ^{n × n}\ \big|\ a^\mathrm{T}pa > 0 \text{ for all } a ∈ ℝ^{n}\backslash\{0\} +\bigr\}\]

    The tangent space at $T_p\mathcal P(n)$ reads

    \[ T_p\mathcal P(n) = + \bigl\{ + X \in \mathbb R^{n×n} \big|\ X=X^\mathrm{T} + \bigr\},\]

    i.e. the set of symmetric matrices,

    Constructor

    SymmetricPositiveDefinite(n)

    generates the manifold $\mathcal P(n) \subset ℝ^{n × n}$

    source

    This manifold can – for example – be illustrated as ellipsoids: since the eigenvalues are all positive they can be taken as lengths of the axes of an ellipsoids while the directions are given by the eigenvectors.

    An example set of data

    The manifold can be equipped with different metrics

    Common and metric independent functions

    Base.convertMethod
    convert(::Type{AbstractMatrix}, p::SPDPoint)

    return the point p as a matrix. The matrix is either stored within the SPDPoint or reconstructed from p.eigen.

    source
    Base.randMethod
    rand(M::SymmetricPositiveDefinite; σ::Real=1)

    Generate a random symmetric positive definite matrix on the SymmetricPositiveDefinite manifold M.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::SymmetricPositiveDefinite, p; kwargs...)

    checks, whether p is a valid point on the SymmetricPositiveDefinite M, i.e. is a matrix of size (N,N), symmetric and positive definite. The tolerance for the second to last test can be set using the kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::SymmetricPositiveDefinite, p, X; kwargs... )

    Check whether X is a tangent vector to p on the SymmetricPositiveDefinite M, i.e. atfer check_point(M,p), X has to be of same dimension as p and a symmetric matrix, i.e. this stores tangent vetors as elements of the corresponding Lie group. The tolerance for the last test can be set using the kwargs....

    source

    Default metric: the affine invariant metric

    Manifolds.AffineInvariantMetricType
    AffineInvariantMetric <: AbstractMetric

    The linear affine metric is the metric for symmetric positive definite matrices, that employs matrix logarithms and exponentials, which yields a linear and affine metric.

    source

    This metric is also the default metric, i.e. any call of the following functions with P=SymmetricPositiveDefinite(3) will result in MetricManifold(P,AffineInvariantMetric())and hence yield the formulae described in this seciton.

    Base.expMethod
    exp(M::SymmetricPositiveDefinite, p, X)
    +exp(M::MetricManifold{SymmetricPositiveDefinite{N},AffineInvariantMetric}, p, X)

    Compute the exponential map from p with tangent vector X on the SymmetricPositiveDefinite M with its default MetricManifold having the AffineInvariantMetric. The formula reads

    \[\exp_p X = p^{\frac{1}{2}}\operatorname{Exp}(p^{-\frac{1}{2}} X p^{-\frac{1}{2}})p^{\frac{1}{2}},\]

    where $\operatorname{Exp}$ denotes to the matrix exponential.

    source
    Base.logMethod
    log(M::SymmetricPositiveDefinite, p, q)
    +log(M::MetricManifold{SymmetricPositiveDefinite,AffineInvariantMetric}, p, q)

    Compute the logarithmic map from p to q on the SymmetricPositiveDefinite as a MetricManifold with AffineInvariantMetric. The formula reads

    \[\log_p q = +p^{\frac{1}{2}}\operatorname{Log}(p^{-\frac{1}{2}}qp^{-\frac{1}{2}})p^{\frac{1}{2}},\]

    where $\operatorname{Log}$ denotes to the matrix logarithm.

    source
    ManifoldDiff.riemannian_HessianMethod
    riemannian_Hessian(M::SymmetricPositiveDefinite, p, g, H, X)

    The Riemannian Hessian can be computed as stated in Eq. (7.3) [Ngu23]. Let $\nabla f(p)$ denote the Euclidean gradient G, $\nabla^2 f(p)[X]$ the Euclidean Hessian H, and $\operatorname{sym}(X) = \frac{1}{2}\bigl(X^{\mathrm{T}+X\bigr)$` the symmetrization operator. Then the formula reads

    \[ \operatorname{Hess}f(p)[X] + = + p\operatorname{sym}(∇^2 f(p)[X])p + + \operatorname{sym}\Bigl( X\operatorname{sym}\bigl(∇ f(p)\bigr)p)\]

    source
    ManifoldsBase.change_metricMethod
    change_metric(M::SymmetricPositiveDefinite{n}, E::EuclideanMetric, p, X)

    Given a tangent vector $X ∈ T_p\mathcal P(n)$ with respect to the EuclideanMetric g_E, this function changes into the AffineInvariantMetric (default) metric on the SymmetricPositiveDefinite M.

    To be precise we are looking for $c\colon T_p\mathcal P(n) \to T_p\mathcal P(n)$ such that for all $Y,Z ∈ T_p\mathcal P(n)$` it holds

    \[⟨Y,Z⟩ = \operatorname{tr}(YZ) = \operatorname{tr}(p^{-1}c(Y)p^{-1}c(Z)) = g_p(c(Z),c(Y))\]

    and hence $c(X) = pX$ is computed.

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::SymmetricPositiveDefinite, E::EuclideanMetric, p, X)

    Given a tangent vector $X ∈ T_p\mathcal M$ representing a linear function on the tangent space at p with respect to the EuclideanMetric g_E, this is turned into the representer with respect to the (default) metric, the AffineInvariantMetric on the SymmetricPositiveDefinite M.

    To be precise we are looking for $Z∈T_p\mathcal P(n)$ such that for all $Y∈T_p\mathcal P(n)$` it holds

    \[⟨X,Y⟩ = \operatorname{tr}(XY) = \operatorname{tr}(p^{-1}Zp^{-1}Y) = g_p(Z,Y)\]

    and hence $Z = pXp$.

    source
    ManifoldsBase.distanceMethod
    distance(M::SymmetricPositiveDefinite, p, q)
    +distance(M::MetricManifold{SymmetricPositiveDefinite,AffineInvariantMetric}, p, q)

    Compute the distance on the SymmetricPositiveDefinite manifold between p and q, as a MetricManifold with AffineInvariantMetric. The formula reads

    \[d_{\mathcal P(n)}(p,q) += \lVert \operatorname{Log}(p^{-\frac{1}{2}}qp^{-\frac{1}{2}})\rVert_{\mathrm{F}}.,\]

    where $\operatorname{Log}$ denotes the matrix logarithm and $\lVert\cdot\rVert_{\mathrm{F}}$ denotes the matrix Frobenius norm.

    source
    ManifoldsBase.get_basisMethod
    [Ξ,κ] = get_basis(M::SymmetricPositiveDefinite, p, B::DefaultOrthonormalBasis)
    +[Ξ,κ] = get_basis(M::MetricManifold{SymmetricPositiveDefinite{N},AffineInvariantMetric}, p, B::DefaultOrthonormalBasis)

    Return a default ONB for the tangent space $T_p\mathcal P(n)$ of the SymmetricPositiveDefinite with respect to the AffineInvariantMetric.

    \[ g_p(X,Y) = \operatorname{tr}(p^{-1} X p^{-1} Y),\]

    The basis constructed here is based on the ONB for symmetric matrices constructed as follows. Let

    \[\Delta_{i,j} = (a_{k,l})_{k,l=1}^n \quad \text{ with } +a_{k,l} = +\begin{cases} + 1 & \mbox{ for } k=l \text{ if } i=j\\ + \frac{1}{\sqrt{2}} & \mbox{ for } k=i, l=j \text{ or } k=j, l=i\\ + 0 & \text{ else.} +\end{cases}\]

    which forms an ONB for the space of symmetric matrices.

    We then form the ONB by

    \[ \Xi_{i,j} = p^{\frac{1}{2}}\Delta_{i,j}p^{\frac{1}{2}},\qquad i=1,\ldots,n, j=i,\ldots,n.\]

    source
    ManifoldsBase.get_basis_diagonalizingMethod
    [Ξ,κ] = get_basis_diagonalizing(M::SymmetricPositiveDefinite, p, B::DiagonalizingOrthonormalBasis)
    +[Ξ,κ] = get_basis_diagonalizing(M::MetricManifold{SymmetricPositiveDefinite{N},AffineInvariantMetric}, p, B::DiagonalizingOrthonormalBasis)

    Return a orthonormal basis Ξ as a vector of tangent vectors (of length manifold_dimension of M) in the tangent space of p on the MetricManifold of SymmetricPositiveDefinite manifold M with AffineInvariantMetric that diagonalizes the curvature tensor $R(u,v)w$ with eigenvalues κ and where the direction B.frame_direction $V$ has curvature 0.

    The construction is based on an ONB for the symmetric matrices similar to get_basis(::SymmetricPositiveDefinite, p, ::DefaultOrthonormalBasis just that the ONB here is build from the eigen vectors of $p^{\frac{1}{2}}Vp^{\frac{1}{2}}$.

    source
    ManifoldsBase.get_coordinatesMethod
    get_coordinates(::SymmetricPositiveDefinite, p, X, ::DefaultOrthonormalBasis)

    Using the basis from get_basis the coordinates with respect to this ONB can be simplified to

    \[ c_k = \mathrm{tr}(p^{-\frac{1}{2}}\Delta_{i,j} X)\]

    where $k$ is trhe linearized index of the $i=1,\ldots,n, j=i,\ldots,n$.

    source
    ManifoldsBase.get_vectorMethod
    get_vector(::SymmetricPositiveDefinite, p, c, ::DefaultOrthonormalBasis)

    Using the basis from get_basis the vector reconstruction with respect to this ONB can be simplified to

    \[ X = p^{\frac{1}{2}} \Biggl( \sum_{i=1,j=i}^n c_k \Delta_{i,j} \Biggr) p^{\frac{1}{2}}\]

    where $k$ is the linearized index of the $i=1,\ldots,n, j=i,\ldots,n$.

    source
    ManifoldsBase.parallel_transport_toMethod
    parallel_transport_to(M::SymmetricPositiveDefinite, p, X, q)
    +parallel_transport_to(M::MetricManifold{SymmetricPositiveDefinite,AffineInvariantMetric}, p, X, y)

    Compute the parallel transport of X from the tangent space at p to the tangent space at q on the SymmetricPositiveDefinite as a MetricManifold with the AffineInvariantMetric. The formula reads

    \[\mathcal P_{q←p}X = p^{\frac{1}{2}} +\operatorname{Exp}\bigl( +\frac{1}{2}p^{-\frac{1}{2}}\log_p(q)p^{-\frac{1}{2}} +\bigr) +p^{-\frac{1}{2}}X p^{-\frac{1}{2}} +\operatorname{Exp}\bigl( +\frac{1}{2}p^{-\frac{1}{2}}\log_p(q)p^{-\frac{1}{2}} +\bigr) +p^{\frac{1}{2}},\]

    where $\operatorname{Exp}$ denotes the matrix exponential and log the logarithmic map on SymmetricPositiveDefinite (again with respect to the AffineInvariantMetric).

    source
    ManifoldsBase.riemann_tensorMethod
    riemann_tensor(::SymmetricPositiveDefinite, p, X, Y, Z)

    Compute the value of Riemann tensor on the SymmetricPositiveDefinite manifold. The formula reads[Rentmeesters2011] $R(X,Y)Z=p^{1/2}R(X_I, Y_I)Z_Ip^{1/2}$, where $R_I(X_I, Y_I)Z_I=\frac{1}{4}[Z_I, [X_I, Y_I]]$, $X_I=p^{-1/2}Xp^{-1/2}$, $Y_I=p^{-1/2}Yp^{-1/2}$ and $Z_I=p^{-1/2}Zp^{-1/2}$.

    source

    Bures-Wasserstein metric

    Base.expMethod
    exp(::MatricManifold{ℝ,SymmetricPositiveDefinite,BuresWassersteinMetric}, p, X)

    Compute the exponential map on SymmetricPositiveDefinite with respect to the BuresWassersteinMetric given by

    \[ \exp_p(X) = p+X+L_p(X)pL_p(X)\]

    where $q=L_p(X)$ denotes the Lyapunov operator, i.e. it solves $pq + qp = X$.

    source
    Base.logMethod
    log(::MatricManifold{SymmetricPositiveDefinite,BuresWassersteinMetric}, p, q)

    Compute the logarithmic map on SymmetricPositiveDefinite with respect to the BuresWassersteinMetric given by

    \[ \log_p(q) = (pq)^{\frac{1}{2}} + (qp)^{\frac{1}{2}} - 2 p\]

    where $q=L_p(X)$ denotes the Lyapunov operator, i.e. it solves $pq + qp = X$.

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::MetricManifold{ℝ,SymmetricPositiveDefinite,BuresWassersteinMetric}, E::EuclideanMetric, p, X)

    Given a tangent vector $X ∈ T_p\mathcal M$ representing a linear function on the tangent space at p with respect to the EuclideanMetric g_E, this is turned into the representer with respect to the (default) metric, the BuresWassersteinMetric on the SymmetricPositiveDefinite M.

    To be precise we are looking for $Z∈T_p\mathcal P(n)$ such that for all $Y∈T_p\mathcal P(n)$` it holds

    \[⟨X,Y⟩ = \operatorname{tr}(XY) = ⟨Z,Y⟩_{\mathrm{BW}}\]

    for all $Y$ and hence we get $Z$= 2(A+A^{\mathrm{T}})$with$A=Xp``.

    source
    ManifoldsBase.distanceMethod
    distance(::MatricManifold{SymmetricPositiveDefinite,BuresWassersteinMetric}, p, q)

    Compute the distance with respect to the BuresWassersteinMetric on SymmetricPositiveDefinite matrices, i.e.

    \[d(p,q) = + \operatorname{tr}(p) + \operatorname{tr}(q) - 2\operatorname{tr}\Bigl( (p^{\frac{1}{2}}qp^{\frac{1}{2}} \bigr)^\frac{1}{2} \Bigr),\]

    where the last trace can be simplified (by rotating the matrix products in the trace) to $\operatorname{tr}(pq)$.

    source

    Generalized Bures-Wasserstein metric

    Manifolds.GeneralizedBuresWassersteinMetricType
    GeneralizedBurresWassertseinMetric{T<:AbstractMatrix} <: AbstractMetric

    The generalized Bures Wasserstein metric for symmetric positive definite matrices, see[HanMishraJawanpuriaGao2021].

    This metric internally stores the symmetric positive definite matrix $M$ to generalise the metric, where the name also follows the mentioned preprint.

    source
    Base.expMethod
    exp(::MatricManifold{ℝ,SymmetricPositiveDefinite,GeneralizedBuresWassersteinMetric}, p, X)

    Compute the exponential map on SymmetricPositiveDefinite with respect to the GeneralizedBuresWassersteinMetric given by

    \[ \exp_p(X) = p+X+\mathcal ML_{p,M}(X)pML_{p,M}(X)\]

    where $q=L_{M,p}(X)$ denotes the generalized Lyapunov operator, i.e. it solves $pqM + Mqp = X$.

    source
    Base.logMethod
    log(::MatricManifold{SymmetricPositiveDefinite,GeneralizedBuresWassersteinMetric}, p, q)

    Compute the logarithmic map on SymmetricPositiveDefinite with respect to the BuresWassersteinMetric given by

    \[ \log_p(q) = M(M^{-1}pM^{-1}q)^{\frac{1}{2}} + (qM^{-1}pM^{-1})^{\frac{1}{2}}M - 2 p.\]

    source
    ManifoldsBase.change_representerMethod
    change_representer(M::MetricManifold{ℝ,SymmetricPositiveDefinite,GeneralizedBuresWassersteinMetric}, E::EuclideanMetric, p, X)

    Given a tangent vector $X ∈ T_p\mathcal M$ representing a linear function on the tangent space at p with respect to the EuclideanMetric g_E, this is turned into the representer with respect to the (default) metric, the GeneralizedBuresWassersteinMetric on the SymmetricPositiveDefinite M.

    To be precise we are looking for $Z∈T_p\mathcal P(n)$ such that for all $Y∈T_p\mathcal P(n)$ it holds

    \[⟨X,Y⟩ = \operatorname{tr}(XY) = ⟨Z,Y⟩_{\mathrm{BW}}\]

    for all $Y$ and hence we get $Z = 2pXM + 2MXp$.

    source
    ManifoldsBase.distanceMethod
    distance(::MatricManifold{SymmetricPositiveDefinite,GeneralizedBuresWassersteinMetric}, p, q)

    Compute the distance with respect to the BuresWassersteinMetric on SymmetricPositiveDefinite matrices, i.e.

    \[d(p,q) = \operatorname{tr}(M^{-1}p) + \operatorname{tr}(M^{-1}q) + - 2\operatorname{tr}\bigl( (p^{\frac{1}{2}}M^{-1}qM^{-1}p^{\frac{1}{2}} \bigr)^{\frac{1}{2}},\]

    source

    Log-Euclidean metric

    Manifolds.LogEuclideanMetricType
    LogEuclideanMetric <: RiemannianMetric

    The LogEuclidean Metric consists of the Euclidean metric applied to all elements after mapping them into the Lie Algebra, i.e. performing a matrix logarithm beforehand.

    source
    ManifoldsBase.distanceMethod
    distance(M::MetricManifold{SymmetricPositiveDefinite{N},LogEuclideanMetric}, p, q)

    Compute the distance on the SymmetricPositiveDefinite manifold between p and q as a MetricManifold with LogEuclideanMetric. The formula reads

    \[ d_{\mathcal P(n)}(p,q) = \lVert \operatorname{Log} p - \operatorname{Log} q \rVert_{\mathrm{F}}\]

    where $\operatorname{Log}$ denotes the matrix logarithm and $\lVert\cdot\rVert_{\mathrm{F}}$ denotes the matrix Frobenius norm.

    source

    Log-Cholesky metric

    Base.expMethod
    exp(M::MetricManifold{SymmetricPositiveDefinite,LogCholeskyMetric}, p, X)

    Compute the exponential map on the SymmetricPositiveDefinite M with LogCholeskyMetric from p into direction X. The formula reads

    \[\exp_p X = (\exp_y W)(\exp_y W)^\mathrm{T}\]

    where $\exp_xW$ is the exponential map on CholeskySpace, $y$ is the cholesky decomposition of $p$, $W = y(y^{-1}Xy^{-\mathrm{T}})_\frac{1}{2}$, and $(\cdot)_\frac{1}{2}$ denotes the lower triangular matrix with the diagonal multiplied by $\frac{1}{2}$.

    source
    Base.logMethod
    log(M::MetricManifold{SymmetricPositiveDefinite,LogCholeskyMetric}, p, q)

    Compute the logarithmic map on SymmetricPositiveDefinite M with respect to the LogCholeskyMetric emanating from p to q. The formula can be adapted from the CholeskySpace as

    \[\log_p q = xW^{\mathrm{T}} + Wx^{\mathrm{T}},\]

    where $x$ is the cholesky factor of $p$ and $W=\log_x y$ for $y$ the cholesky factor of $q$ and the just mentioned logarithmic map is the one on CholeskySpace.

    source
    ManifoldsBase.distanceMethod
    distance(M::MetricManifold{SymmetricPositiveDefinite,LogCholeskyMetric}, p, q)

    Compute the distance on the manifold of SymmetricPositiveDefinite nmatrices, i.e. between two symmetric positive definite matrices p and q with respect to the LogCholeskyMetric. The formula reads

    \[d_{\mathcal P(n)}(p,q) = \sqrt{ + \lVert ⌊ x ⌋ - ⌊ y ⌋ \rVert_{\mathrm{F}}^2 + + \lVert \log(\operatorname{diag}(x)) - \log(\operatorname{diag}(y))\rVert_{\mathrm{F}}^2 }\ \ ,\]

    where $x$ and $y$ are the cholesky factors of $p$ and $q$, respectively, $⌊\cdot⌋$ denbotes the strictly lower triangular matrix of its argument, and $\lVert\cdot\rVert_{\mathrm{F}}$ the Frobenius norm.

    source
    ManifoldsBase.innerMethod
    inner(M::MetricManifold{LogCholeskyMetric,ℝ,SymmetricPositiveDefinite}, p, X, Y)

    Compute the inner product of two matrices X, Y in the tangent space of p on the SymmetricPositiveDefinite manifold M, as a MetricManifold with LogCholeskyMetric. The formula reads

    \[ g_p(X,Y) = ⟨a_z(X),a_z(Y)⟩_z,\]

    where $⟨\cdot,\cdot⟩_x$ denotes inner product on the CholeskySpace, $z$ is the cholesky factor of $p$, $a_z(W) = z (z^{-1}Wz^{-\mathrm{T}})_{\frac{1}{2}}$, and $(\cdot)_\frac{1}{2}$ denotes the lower triangular matrix with the diagonal multiplied by $\frac{1}{2}$

    source
    ManifoldsBase.parallel_transport_toMethod
    vector_transport_to(
    +    M::MetricManifold{SymmetricPositiveDefinite,LogCholeskyMetric},
    +    p,
    +    X,
    +    q,
    +    ::ParallelTransport,
    +)

    Parallel transport the tangent vector X at p along the geodesic to q with respect to the SymmetricPositiveDefinite manifold M and LogCholeskyMetric. The parallel transport is based on the parallel transport on CholeskySpace: Let $x$ and $y$ denote the cholesky factors of p and q, respectively and $W = x(x^{-1}Xx^{-\mathrm{T}})_\frac{1}{2}$, where $(\cdot)_\frac{1}{2}$ denotes the lower triangular matrix with the diagonal multiplied by $\frac{1}{2}$. With $V$ the parallel transport on CholeskySpace from $x$ to $y$. The formula hear reads

    \[\mathcal P_{q←p}X = yV^{\mathrm{T}} + Vy^{\mathrm{T}}.\]

    source

    Statistics

    Efficient representation

    When a point p is used in several occasions, it might be beneficial to store the eigenvalues and vectors of p and optionally its square root and the inverse of the square root. The SPDPoint can be used for exactly that.

    Manifolds.SPDPointType
    SPDPoint <: AbstractManifoldsPoint

    Store the result of eigen(p) of an SPD matrix and (optionally) $p^{1/2}$ and $p^{-1/2}$ to avoid their repeated computations.

    This result only has the result of eigen as a mandatory storage, the other three can be stored. If they are not stored they are computed and returned (but then still not stored) when required.

    Constructor

    SPDPoint(p::AbstractMatrix; store_p=true, store_sqrt=true, store_sqrt_inv=true)

    Create an SPD point using an symmetric positive defincite matrix p, where you can optionally store p, sqrt and sqrt_inv

    source

    and there are three internal functions to be able to use SPDPoint interchangeably with the default representation as a matrix.

    Manifolds.spd_sqrtFunction
    spd_sqrt(p::AbstractMatrix)
    +spd_sqrt(p::SPDPoint)

    return $p^{\frac{1}{2}}$ by either computing it (if it is missing or for the AbstractMatrix) or returning the stored value from within the SPDPoint.

    This method assumes that p represents an spd matrix.

    source
    Manifolds.spd_sqrt_invFunction
    spd_sqrt_inv(p::SPDPoint)

    return $p^{-\frac{1}{2}}$ by either computing it (if it is missing or for the AbstractMatrix) or returning the stored value from within the SPDPoint.

    This method assumes that p represents an spd matrix.

    source
    Manifolds.spd_sqrt_and_sqrt_invFunction
    spd_sqrt_and_sqrt_inv(p::AbstractMatrix)
    +spd_sqrt_and_sqrt_inv(p::SPDPoint)

    return $p^{\frac{1}{2}}$ and $p^{-\frac{1}{2}}$ by either computing them (if they are missing or for the AbstractMatrix) or returning their stored value from within the SPDPoint.

    Compared to calling single methods spd_sqrt and spd_sqrt_inv this method only computes the eigenvectors once for the case of the AbstractMatrix or if both are missing.

    This method assumes that p represents an spd matrix.

    source

    Literature

    • Rentmeesters2011

      Q. Rentmeesters, “A gradient method for geodesic data fitting on some symmetric Riemannian manifolds,” in 2011 50th IEEE Conference on Decision and Control and European Control Conference, Dec. 2011, pp. 7141–7146. doi: 10.1109/CDC.2011.6161280.

    • MalagoMontruccioPistone2018

      Malagò, L., Montrucchio, L., Pistone, G.: Wasserstein Riemannian geometry of Gaussian densities. Information Geometry, 1, pp. 137–179, 2018. doi: 10.1007/s41884-018-0014-4

    • HanMishraJawanpuriaGao2021

      Han, A., Mishra, B., Jawanpuria, P., Gao, J.: Generalized Bures-Wasserstein geometry for positive definite matrices. arXiv: 2110.10464.

    • Lin2019

      Lin, Zenhua: "Riemannian Geometry of Symmetric Positive Definite Matrices via Cholesky Decomposition", arXiv: 1908.09326.

    diff --git a/previews/PR644/manifolds/symmetricpsdfixedrank.html b/previews/PR644/manifolds/symmetricpsdfixedrank.html new file mode 100644 index 0000000000..e95eeeba43 --- /dev/null +++ b/previews/PR644/manifolds/symmetricpsdfixedrank.html @@ -0,0 +1,11 @@ + +Symmetric positive semidefinite fixed rank · Manifolds.jl

    Symmetric Positive Semidefinite Matrices of Fixed Rank

    Manifolds.SymmetricPositiveSemidefiniteFixedRankType
    SymmetricPositiveSemidefiniteFixedRank{n,k,𝔽} <: AbstractDecoratorManifold{𝔽}

    The AbstractManifold $ \operatorname{SPS}_k(n)$ consisting of the real- or complex-valued symmetric positive semidefinite matrices of size $n × n$ and rank $k$, i.e. the set

    \[\operatorname{SPS}_k(n) = \bigl\{ +p ∈ 𝔽^{n × n}\ \big|\ p^{\mathrm{H}} = p, +apa^{\mathrm{H}} \geq 0 \text{ for all } a ∈ 𝔽 +\text{ and } \operatorname{rank}(p) = k\bigr\},\]

    where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, and the field $𝔽 ∈ \{ ℝ, ℂ\}$. We sometimes $\operatorname{SPS}_{k,𝔽}(n)$, when distinguishing the real- and complex-valued manifold is important.

    An element is represented by $q ∈ 𝔽^{n × k}$ from the factorization $p = qq^{\mathrm{H}}$. Note that since for any unitary (orthogonal) $A ∈ 𝔽^{n × n}$ we have $(Aq)(Aq)^{\mathrm{H}} = qq^{\mathrm{H}} = p$, the representation is not unique, or in other words, the manifold is a quotient manifold of $𝔽^{n × k}$.

    The tangent space at $p$, $T_p\operatorname{SPS}_k(n)$, is also represented by matrices $Y ∈ 𝔽^{n × k}$ and reads as

    \[T_p\operatorname{SPS}_k(n) = \bigl\{ +X ∈ 𝔽^{n × n}\,|\,X = qY^{\mathrm{H}} + Yq^{\mathrm{H}} +\text{ i.e. } X = X^{\mathrm{H}} +\bigr\}.\]

    Note that the metric used yields a non-complete manifold. The metric was used in[JourneeBachAbsilSepulchre2010][MassartAbsil2020].

    Constructor

    SymmetricPositiveSemidefiniteFixedRank(n::Int, k::Int, field::AbstractNumbers=ℝ)

    Generate the manifold of $n × n$ symmetric positive semidefinite matrices of rank $k$ over the field of real numbers or complex numbers .

    source
    Base.expMethod
    exp(M::SymmetricPositiveSemidefiniteFixedRank, q, Y)

    Compute the exponential map on the SymmetricPositiveSemidefiniteFixedRank, which just reads

    \[ \exp_q Y = q+Y.\]

    Note

    Since the manifold is represented in the embedding and is a quotient manifold, the exponential and logarithmic map are a bijection only with respect to the equivalence classes. Computing

    \[ q_2 = \exp_p(\log_pq)\]

    might yield a matrix $q_2\neq q$, but they represent the same point on the quotient manifold, i.e. $d_{\operatorname{SPS}_k(n)}(q_2,q) = 0$.

    source
    Base.logMethod
    log(M::SymmetricPositiveSemidefiniteFixedRank, q, p)

    Compute the logarithmic map on the SymmetricPositiveSemidefiniteFixedRank manifold by minimizing $\lVert p - qY\rVert$ with respect to $Y$.

    Note

    Since the manifold is represented in the embedding and is a quotient manifold, the exponential and logarithmic map are a bijection only with respect to the equivalence classes. Computing

    \[ q_2 = \exp_p(\log_pq)\]

    might yield a matrix $q_2\neq q$, but they represent the same point on the quotient manifold, i.e. $d_{\operatorname{SPS}_k(n)}(q_2,q) = 0$.

    source
    ManifoldsBase._isapproxMethod
    isapprox(M::SymmetricPositiveSemidefiniteFixedRank, p, q; kwargs...)

    test, whether two points p, q are (approximately) nearly the same. Since this is a quotient manifold in the embedding, the test is performed by checking their distance, if they are not the same, i.e. that $d_{\mathcal M}(p,q) \approx 0$, where the comparison is performed with the classical isapprox. The kwargs... are passed on to this accordingly.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::SymmetricPositiveSemidefiniteFixedRank{n,𝔽}, q; kwargs...)

    Check whether q is a valid manifold point on the SymmetricPositiveSemidefiniteFixedRank M, i.e. whether p=q*q' is a symmetric matrix of size (n,n) with values from the corresponding AbstractNumbers 𝔽. The symmetry of p is not explicitly checked since by using q p is symmetric by construction. The tolerance for the symmetry of p can and the rank of q*q' be set using kwargs....

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::SymmetricPositiveSemidefiniteFixedRank{n,k,𝔽}, p, X; kwargs... )

    Check whether X is a tangent vector to manifold point p on the SymmetricPositiveSemidefiniteFixedRank M, i.e. X has to be a symmetric matrix of size (n,n) and its values have to be from the correct AbstractNumbers.

    Due to the reduced representation this is fulfilled as soon as the matrix is of correct size.

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(M::SymmetricPositiveSemidefiniteFixedRank{n,k,𝔽})

    Return the dimension of the SymmetricPositiveSemidefiniteFixedRank matrix M over the number system 𝔽, i.e.

    \[\begin{aligned} +\dim \operatorname{SPS}_{k,ℝ}(n) &= kn - \frac{k(k-1)}{2},\\ +\dim \operatorname{SPS}_{k,ℂ}(n) &= 2kn - k^2, +\end{aligned}\]

    where the last $k^2$ is due to the zero imaginary part for Hermitian matrices diagonal

    source
    ManifoldsBase.vector_transport_toMethod
    vector_transport_to(M::SymmetricPositiveSemidefiniteFixedRank, p, X, q)

    transport the tangent vector X at p to q by projecting it onto the tangent space at q.

    source
    diff --git a/previews/PR644/manifolds/symplectic.html b/previews/PR644/manifolds/symplectic.html new file mode 100644 index 0000000000..0f25b21823 --- /dev/null +++ b/previews/PR644/manifolds/symplectic.html @@ -0,0 +1,95 @@ + +Symplectic · Manifolds.jl

    Symplectic

    The Symplectic manifold, denoted $\operatorname{Sp}(2n, \mathbb{F})$, is a closed, embedded, submanifold of $\mathbb{F}^{2n \times 2n}$ that represents transformations into symplectic subspaces which keep the canonical symplectic form over $\mathbb{F}^{2n \times 2n }$ invariant under the standard embedding inner product. The canonical symplectic form is a non-degenerate bilinear and skew symmetric map $\omega\colon \mathbb{F}^{2n} \times \mathbb{F}^{2n} \rightarrow \mathbb{F}$, given by $\omega(x, y) = x^T Q_{2n} y$ for elements $x, y \in \mathbb{F}^{2n}$, with

    \[ Q_{2n} = + \begin{bmatrix} + 0_n & I_n \\ + -I_n & 0_n + \end{bmatrix}.\]

    That means that an element $p \in \operatorname{Sp}(2n)$ must fulfill the requirement that

    \[ \omega (p x, p y) = x^T(p^TQp)y = x^TQy = \omega(x, y),\]

    leading to the requirement on $p$ that $p^TQp = Q$.

    The symplectic manifold also forms a group under matrix multiplication, called the $\textit{symplectic group}$. Since all the symplectic matrices necessarily have determinant one, the symplectic group $\operatorname{Sp}(2n, \mathbb{F})$ is a subgroup of the special linear group, $\operatorname{SL}(2n, \mathbb{F})$. When the underlying field is either $\mathbb{R}$ or $\mathbb{C}$ the symplectic group with a manifold structure constitutes a Lie group, with the Lie Algebra

    \[ \mathfrak{sp}(2n,F) = \{H \in \mathbb{F}^{2n \times 2n} \;|\; Q H + H^{T} Q = 0\}.\]

    This set is also known as the Hamiltonian matrices, which have the property that $(QH)^T = QH$ and are commonly used in physics.

    Manifolds.ExtendedSymplecticMetricType
    ExtendedSymplecticMetric <: AbstractMetric

    The extension of the RealSymplecticMetric at a point p \in \operatorname{Sp}(2n) as an inner product over the embedding space $ℝ^{2n \times 2n}$, i.e.

    \[ \langle x, y \rangle_{p} = \langle p^{-1}x, p^{-1}\rangle_{\operatorname{Fr}} + = \operatorname{tr}(x^{\mathrm{T}}(pp^{\mathrm{T}})^{-1}y), \;\forall\; x, y \in ℝ^{2n \times 2n}.\]

    source
    Manifolds.RealSymplecticMetricType
    RealSymplecticMetric <: RiemannianMetric

    The canonical Riemannian metric on the symplectic manifold, defined pointwise for $p \in \operatorname{Sp}(2n)$ by [Fiori2011]

    \[\begin{align*} + & g_p \colon T_p\operatorname{Sp}(2n) \times T_p\operatorname{Sp}(2n) \rightarrow ℝ, \\ + & g_p(Z_1, Z_2) = \operatorname{tr}((p^{-1}Z_1)^{\mathrm{T}} (p^{-1}Z_2)). +\end{align*}\]

    This metric is also the default metric for the Symplectic manifold.

    source
    Manifolds.SymplecticType
    Symplectic{n, 𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType}

    The symplectic manifold consists of all $2n \times 2n$ matrices which preserve the canonical symplectic form over $𝔽^{2n × 2n} \times 𝔽^{2n × 2n}$,

    \[ \omega\colon 𝔽^{2n × 2n} \times 𝔽^{2n × 2n} \rightarrow 𝔽, + \quad \omega(x, y) = p^{\mathrm{T}} Q_{2n} q, \; x, y \in 𝔽^{2n × 2n},\]

    where

    \[Q_{2n} = +\begin{bmatrix} + 0_n & I_n \\ + -I_n & 0_n +\end{bmatrix}.\]

    That is, the symplectic manifold consists of

    \[\operatorname{Sp}(2n, ℝ) = \bigl\{ p ∈ ℝ^{2n × 2n} \, \big| \, p^{\mathrm{T}}Q_{2n}p = Q_{2n} \bigr\},\]

    with $0_n$ and $I_n$ denoting the $n × n$ zero-matrix and indentity matrix in $ℝ^{n \times n}$ respectively.

    The tangent space at a point $p$ is given by [BendokatZimmermann2021]

    \[\begin{align*} + T_p\operatorname{Sp}(2n) + &= \{X \in \mathbb{R}^{2n \times 2n} \;|\; p^{T}Q_{2n}X + X^{T}Q_{2n}p = 0 \}, \\ + &= \{X = pQS \;|\; S ∈ R^{2n × 2n}, S^{\mathrm{T}} = S \}. +\end{align*}\]

    Constructor

    Symplectic(2n, field=ℝ) -> Symplectic{div(2n, 2), field}()

    Generate the (real-valued) symplectic manifold of $2n \times 2n$ symplectic matrices. The constructor for the Symplectic manifold accepts the even column/row embedding dimension $2n$ for the real symplectic manifold, $ℝ^{2n × 2n}$.

    source
    Manifolds.SymplecticMatrixType
    SymplecticMatrix{T}

    A lightweight structure to represent the action of the matrix representation of the canonical symplectic form,

    \[Q_{2n}(λ) = λ +\begin{bmatrix} +0_n & I_n \\ + -I_n & 0_n +\end{bmatrix} \quad \in ℝ^{2n \times 2n},\]

    such that the canonical symplectic form is represented by

    \[\omega_{2n}(x, y) = x^{\mathrm{T}}Q_{2n}(1)y, \quad x, y \in ℝ^{2n}.\]

    The entire matrix is however not instantiated in memory, instead a scalar $λ$ of type T is stored, which is used to keep track of scaling and transpose operations applied to each SymplecticMatrix. For example, given Q = SymplecticMatrix(1.0) represented as 1.0*[0 I; -I 0], the adjoint Q' returns SymplecticMatrix(-1.0) = (-1.0)*[0 I; -I 0].

    source
    Base.expMethod
    exp(M::Symplectic, p, X)
    +exp!(M::Symplectic, q, p, X)

    The Exponential mapping on the Symplectic manifold with the RealSymplecticMetric Riemannian metric.

    For the point $p \in \operatorname{Sp}(2n)$ the exponential mapping along the tangent vector $X \in T_p\operatorname{Sp}(2n)$ is computed as [WangSunFiori2018]

    \[ \operatorname{exp}_p(X) = p \operatorname{Exp}((p^{-1}X)^{\mathrm{T}}) + \operatorname{Exp}(p^{-1}X - (p^{-1}X)^{\mathrm{T}}),\]

    where $\operatorname{Exp}(\cdot)$ denotes the matrix exponential.

    source
    Base.invMethod
    inv(::Symplectic, A)
    +inv!(::Symplectic, A)

    Compute the symplectic inverse $A^+$ of matrix $A ∈ ℝ^{2n × 2n}$. Given a matrix

    \[A ∈ ℝ^{2n × 2n},\quad +A = +\begin{bmatrix} +A_{1,1} & A_{1,2} \\ +A_{2,1} & A_{2, 2} +\end{bmatrix}\]

    the symplectic inverse is defined as:

    \[A^{+} := Q_{2n}^{\mathrm{T}} A^{\mathrm{T}} Q_{2n},\]

    where

    \[Q_{2n} = +\begin{bmatrix} +0_n & I_n \\ + -I_n & 0_n +\end{bmatrix}.\]

    The symplectic inverse of A can be expressed explicitly as:

    \[A^{+} = +\begin{bmatrix} + A_{2, 2}^{\mathrm{T}} & -A_{1, 2}^{\mathrm{T}} \\[1.2mm] + -A_{2, 1}^{\mathrm{T}} & A_{1, 1}^{\mathrm{T}} +\end{bmatrix}.\]

    source
    Base.randMethod
    rand(::SymplecticStiefel; vector_at=nothing,
    +    hamiltonian_norm = (vector_at === nothing ? 1/2 : 1.0))

    Generate a random point on $\operatorname{Sp}(2n)$ or a random tangent vector $X \in T_p\operatorname{Sp}(2n)$ if vector_at is set to a point $p \in \operatorname{Sp}(2n)$.

    A random point on $\operatorname{Sp}(2n)$ is constructed by generating a random Hamiltonian matrix $Ω \in \mathfrak{sp}(2n,F)$ with norm hamiltonian_norm, and then transforming it to a symplectic matrix by applying the Cayley transform

    \[ \operatorname{cay}\colon \mathfrak{sp}(2n,F) \rightarrow \operatorname{Sp}(2n), + \; \Omega \mapsto (I - \Omega)^{-1}(I + \Omega).\]

    To generate a random tangent vector in $T_p\operatorname{Sp}(2n)$, this code employs the second tangent vector space parametrization of Symplectic. It first generates a random symmetric matrix $S$ by S = randn(2n, 2n) and then symmetrizes it as S = S + S'. Then $S$ is normalized to have Frobenius norm of hamiltonian_norm and X = pQS is returned, where Q is the SymplecticMatrix.

    source
    ManifoldDiff.gradientMethod
    gradient(M::Symplectic, f, p, backend::RiemannianProjectionBackend;
    +         extended_metric=true)
    +gradient!(M::Symplectic, f, p, backend::RiemannianProjectionBackend;
    +         extended_metric=true)

    Compute the manifold gradient $\text{grad}f(p)$ of a scalar function $f \colon \operatorname{Sp}(2n) \rightarrow ℝ$ at $p \in \operatorname{Sp}(2n)$.

    The element $\text{grad}f(p)$ is found as the Riesz representer of the differential $\text{D}f(p) \colon T_p\operatorname{Sp}(2n) \rightarrow ℝ$ w.r.t. the Riemannian metric inner product at $p$ [Fiori2011]. That is, $\text{grad}f(p) \in T_p\operatorname{Sp}(2n)$ solves the relation

    \[ g_p(\text{grad}f(p), X) = \text{D}f(p) \quad\forall\; X \in T_p\operatorname{Sp}(2n).\]

    The default behaviour is to first change the representation of the Euclidean gradient from the Euclidean metric to the RealSymplecticMetric at $p$, and then we projecting the result onto the correct tangent tangent space $T_p\operatorname{Sp}(2n, ℝ)$ w.r.t the Riemannian metric $g_p$ extended to the entire embedding space.

    Arguments:

    • extended_metric = true: If true, compute the gradient $\text{grad}f(p)$ by first changing the representer of the Euclidean gradient of a smooth extension of $f$, $∇f(p)$, w.r.t. the RealSymplecticMetric at $p$ extended to the entire embedding space, before projecting onto the correct tangent vector space w.r.t. the same extended metric $g_p$. If false, compute the gradient by first projecting $∇f(p)$ onto the tangent vector space, before changing the representer in the tangent vector space to comply with the RealSymplecticMetric.
    source
    Manifolds.project_normal!Method
    project_normal!(::MetricManifold{𝔽,Euclidean,ExtendedSymplecticMetric}, Y, p, X)

    Project onto the normal of the tangent space $(T_p\operatorname{Sp}(2n))^{\perp_g}$ at a point $p ∈ \operatorname{Sp}(2n)$, relative to the riemannian metric $g$ RealSymplecticMetric. That is,

    \[(T_p\operatorname{Sp}(2n))^{\perp_g} = \{Y \in \mathbb{R}^{2n \times 2n} : + g_p(Y, X) = 0 \;\forall\; X \in T_p\operatorname{Sp}(2n)\}.\]

    The closed form projection operator onto the normal space is given by [GaoSonAbsilStykel2021]

    \[\operatorname{P}^{(T_p\operatorname{Sp}(2n))\perp}_{g_p}(X) = pQ\operatorname{skew}(p^{\mathrm{T}}Q^{\mathrm{T}}X),\]

    where $\operatorname{skew}(A) = \frac{1}{2}(A - A^{\mathrm{T}})$. This function is not exported.

    source
    Manifolds.symplectic_inverse_timesMethod
    symplectic_inverse_times(::Symplectic, p, q)
    +symplectic_inverse_times!(::Symplectic, A, p, q)

    Directly compute the symplectic inverse of $p \in \operatorname{Sp}(2n)$, multiplied with $q \in \operatorname{Sp}(2n)$. That is, this function efficiently computes $p^+q = (Q_{2n}p^{\mathrm{T}}Q_{2n})q \in ℝ^{2n \times 2n}$, where $Q_{2n}$ is the SymplecticMatrix of size $2n \times 2n$.

    source
    ManifoldsBase.change_representerMethod
    change_representer(::Symplectic, ::EuclideanMetric, p, X)
    +change_representer!(::Symplectic, Y, ::EuclideanMetric, p, X)

    Compute the representation of a tangent vector $ξ ∈ T_p\operatorname{Sp}(2n, ℝ)$ s.t.

    \[ g_p(c_p(ξ), η) = ⟨ξ, η⟩^{\text{Euc}} \;∀\; η ∈ T_p\operatorname{Sp}(2n, ℝ).\]

    with the conversion function

    \[ c_p : T_p\operatorname{Sp}(2n, ℝ) \rightarrow T_p\operatorname{Sp}(2n, ℝ), \quad + c_p(ξ) = \frac{1}{2} pp^{\mathrm{T}} ξ + \frac{1}{2} pQ ξ^{\mathrm{T}} pQ.\]

    Each of the terms $c_p^1(ξ) = p p^{\mathrm{T}} ξ$ and $c_p^2(ξ) = pQ ξ^{\mathrm{T}} pQ$ from the above definition of $c_p(η)$ are themselves metric compatible in the sense that

    \[ c_p^i : T_p\operatorname{Sp}(2n, ℝ) \rightarrow \mathbb{R}^{2n \times 2n}\quad + g_p^i(c_p(ξ), η) = ⟨ξ, η⟩^{\text{Euc}} \;∀\; η ∈ T_p\operatorname{Sp}(2n, ℝ),\]

    for $i \in {1, 2}$. However the range of each function alone is not confined to $T_p\operatorname{Sp}(2n, ℝ)$, but the convex combination

    \[ c_p(ξ) = \frac{1}{2}c_p^1(ξ) + \frac{1}{2}c_p^2(ξ)\]

    does have the correct range $T_p\operatorname{Sp}(2n, ℝ)$.

    source
    ManifoldsBase.change_representerMethod
    change_representer(MetMan::MetricManifold{𝔽, Euclidean{Tuple{m, n}, 𝔽}, ExtendedSymplecticMetric},
    +                   EucMet::EuclideanMetric, p, X)
    +change_representer!(MetMan::MetricManifold{𝔽, Euclidean{Tuple{m, n}, 𝔽}, ExtendedSymplecticMetric},
    +                    Y, EucMet::EuclideanMetric, p, X)

    Change the representation of a matrix $ξ ∈ \mathbb{R}^{2n \times 2n}$ into the inner product space $(ℝ^{2n \times 2n}, g_p)$ where the inner product is given by $g_p(ξ, η) = \langle p^{-1}ξ, p^{-1}η \rangle = \operatorname{tr}(ξ^{\mathrm{T}}(pp^{\mathrm{T}})^{-1}η)$, as the extension of the RealSymplecticMetric onto the entire embedding space.

    By changing the representation we mean to apply a mapping

    \[ c_p : \mathbb{R}^{2n \times 2n} \rightarrow \mathbb{R}^{2n \times 2n},\]

    defined by requiring that it satisfy the metric compatibility condition

    \[ g_p(c_p(ξ), η) = ⟨p^{-1}c_p(ξ), p^{-1}η⟩ = ⟨ξ, η⟩^{\text{Euc}} + \;∀\; η ∈ T_p\operatorname{Sp}(2n, ℝ).\]

    In this case, we compute the mapping

    \[ c_p(ξ) = pp^{\mathrm{T}} ξ.\]

    source
    ManifoldsBase.check_pointMethod
    check_point(M::Symplectic, p; kwargs...)

    Check whether p is a valid point on the Symplectic M=$\operatorname{Sp}(2n)$, i.e. that it has the right AbstractNumbers type and $p^{+}p$ is (approximately) the identity, where $A^{+} = Q_{2n}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}$ is the symplectic inverse, with

    \[Q_{2n} = +\begin{bmatrix} +0_n & I_n \\ + -I_n & 0_n +\end{bmatrix}.\]

    The tolerance can be set with kwargs... (e.g. atol = 1.0e-14).

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::Symplectic, p, X; kwargs...)

    Checks whether X is a valid tangent vector at p on the Symplectic M=$\operatorname{Sp}(2n)$, i.e. the AbstractNumbers fits and it (approximately) holds that $p^{T}Q_{2n}X + X^{T}Q_{2n}p = 0$, where

    \[Q_{2n} = +\begin{bmatrix} +0_n & I_n \\ + -I_n & 0_n +\end{bmatrix}.\]

    The tolerance can be set with kwargs... (e.g. atol = 1.0e-14).

    source
    ManifoldsBase.distanceMethod
    distance(M::Symplectic, p, q)

    Compute an approximate geodesic distance between two Symplectic matrices $p, q \in \operatorname{Sp}(2n)$, as done in [WangSunFiori2018].

    \[ \operatorname{dist}(p, q) + ≈ ||\operatorname{Log}(p^+q)||_{\operatorname{Fr}},\]

    where the $\operatorname{Log}(\cdot)$ operator is the matrix logarithm.

    This approximation is justified by first recalling the Baker-Campbell-Hausdorf formula,

    \[\operatorname{Log}(\operatorname{Exp}(A)\operatorname{Exp}(B)) + = A + B + \frac{1}{2}[A, B] + \frac{1}{12}[A, [A, B]] + \frac{1}{12}[B, [B, A]] + + \ldots \;.\]

    Then we write the expression for the exponential map from $p$ to $q$ as

    \[ q = + \operatorname{exp}_p(X) + = + p \operatorname{Exp}((p^{+}X)^{\mathrm{T}}) + \operatorname{Exp}([p^{+}X - (p^{+}X)^{\mathrm{T}}]), + X \in T_p\operatorname{Sp},\]

    and with the geodesic distance between $p$ and $q$ given by $\operatorname{dist}(p, q) = ||X||_p = ||p^+X||_{\operatorname{Fr}}$ we see that

    \[ \begin{align*} + ||\operatorname{Log}(p^+q)||_{\operatorname{Fr}} + &= ||\operatorname{Log}\left( + \operatorname{Exp}((p^{+}X)^{\mathrm{T}}) + \operatorname{Exp}(p^{+}X - (p^{+}X)^{\mathrm{T}}) + \right)||_{\operatorname{Fr}} \\ + &= ||p^{+}X + \frac{1}{2}[(p^{+}X)^{\mathrm{T}}, p^{+}X - (p^{+}X)^{\mathrm{T}}] + + \ldots ||_{\operatorname{Fr}} \\ + &≈ ||p^{+}X||_{\operatorname{Fr}} = \operatorname{dist}(p, q). + \end{align*}\]

    source
    ManifoldsBase.innerMethod
    inner(::Symplectic{n, ℝ}, p, X, Y)

    Compute the canonical Riemannian inner product RealSymplecticMetric

    \[ g_p(X, Y) = \operatorname{tr}((p^{-1}X)^{\mathrm{T}} (p^{-1}Y))\]

    between the two tangent vectors $X, Y \in T_p\operatorname{Sp}(2n)$.

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::Symplectic, p, q, ::CayleyInverseRetraction)

    Compute the Cayley Inverse Retraction $X = \mathcal{L}_p^{\operatorname{Sp}}(q)$ such that the Cayley Retraction from $p$ along $X$ lands at $q$, i.e. $\mathcal{R}_p(X) = q$ [BendokatZimmermann2021].

    First, recall the definition the standard symplectic matrix

    \[Q = +\begin{bmatrix} + 0 & I \\ +-I & 0 +\end{bmatrix}\]

    as well as the symplectic inverse of a matrix $A$, $A^{+} = Q^{\mathrm{T}} A^{\mathrm{T}} Q$.

    For $p, q ∈ \operatorname{Sp}(2n, ℝ)$ then, we can then define the inverse cayley retraction as long as the following matrices exist.

    \[ U = (I + p^+ q)^{-1}, \quad V = (I + q^+ p)^{-1}.\]

    If that is the case, the inverse cayley retration at $p$ applied to $q$ is

    \[\mathcal{L}_p^{\operatorname{Sp}}(q) = 2p\bigl(V - U\bigr) + 2\bigl((p + q)U - p\bigr) + ∈ T_p\operatorname{Sp}(2n).\]

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(::Symplectic{n})

    Returns the dimension of the symplectic manifold embedded in $ℝ^{2n \times 2n}$, i.e.

    \[ \operatorname{dim}(\operatorname{Sp}(2n)) = (2n + 1)n.\]

    source
    ManifoldsBase.project!Method
    project!(::MetricManifold{𝔽,Euclidean,ExtendedSymplecticMetric}, Y, p, X) where {𝔽}

    Compute the projection of $X ∈ R^{2n × 2n}$ onto $T_p\operatorname{Sp}(2n, ℝ)$ w.r.t. the Riemannian metric $g$ RealSymplecticMetric. The closed form projection mapping is given by [GaoSonAbsilStykel2021]

    \[ \operatorname{P}^{T_p\operatorname{Sp}(2n)}_{g_p}(X) = pQ\operatorname{sym}(p^{\mathrm{T}}Q^{\mathrm{T}}X),\]

    where $\operatorname{sym}(A) = \frac{1}{2}(A + A^{\mathrm{T}})$. This function is not exported.

    source
    ManifoldsBase.projectMethod
    project(::Symplectic, p, A)
    +project!(::Symplectic, Y, p, A)

    Given a point $p \in \operatorname{Sp}(2n)$, project an element $A \in \mathbb{R}^{2n \times 2n}$ onto the tangent space $T_p\operatorname{Sp}(2n)$ relative to the euclidean metric of the embedding $\mathbb{R}^{2n \times 2n}$.

    That is, we find the element $X \in T_p\operatorname{SpSt}(2n, 2k)$ which solves the constrained optimization problem

    \[ \operatorname{min}_{X \in \mathbb{R}^{2n \times 2n}} \frac{1}{2}||X - A||^2, \quad + \text{s.t.}\; + h(X) \colon= X^{\mathrm{T}} Q p + p^{\mathrm{T}} Q X = 0,\]

    where $h\colon\mathbb{R}^{2n \times 2n} \rightarrow \operatorname{skew}(2n)$ defines the restriction of $X$ onto the tangent space $T_p\operatorname{SpSt}(2n, 2k)$.

    source
    ManifoldsBase.retractMethod
    retract(::Symplectic, p, X, ::CayleyRetraction)
    +retract!(::Symplectic, q, p, X, ::CayleyRetraction)

    Compute the Cayley retraction on $p ∈ \operatorname{Sp}(2n, ℝ)$ in the direction of tangent vector $X ∈ T_p\operatorname{Sp}(2n, ℝ)$, as defined in by Birtea et al in proposition 2 [BirteaCaşuComănescu2020].

    Using the symplectic inverse of a matrix $A \in ℝ^{2n \times 2n}$, $A^{+} := Q_{2n}^{\mathrm{T}} A^{\mathrm{T}} Q_{2n}$ where

    \[Q_{2n} = +\begin{bmatrix} +0_n & I_n \\ + -I_n & 0_n +\end{bmatrix},\]

    the retraction $\mathcal{R}\colon T\operatorname{Sp}(2n) \rightarrow \operatorname{Sp}(2n)$ is defined pointwise as

    \[\begin{align*} +\mathcal{R}_p(X) &= p \operatorname{cay}\left(\frac{1}{2}p^{+}X\right), \\ + &= p \operatorname{exp}_{1/1}(p^{+}X), \\ + &= p (2I - p^{+}X)^{-1}(2I + p^{+}X). +\end{align*}\]

    Here $\operatorname{exp}_{1/1}(z) = (2 - z)^{-1}(2 + z)$ denotes the Padé (1, 1) approximation to $\operatorname{exp}(z)$.

    source

    Literature

    • WangSunFiori2018

      Wang, Jing and Sun, Huafei and Fiori, Simone: A Riemannian-steepest-descent approach for optimization on the real symplectic group, Mathematical Methods in the Applied Sciences, 41(11) pp. 4273-4286, 2018 doi 10.1002/mma.4890

    • Fiori2011

      Simone Fiori: Solving minimal-distance problems over the manifold of real-symplectic matrices, SIAM Journal on Matrix Analysis and Applications 32(3), pp. 938-968, 2011. doi 10.1137/100817115.

    • GaoSonAbsilStykel2021

      Gao, Bin and Son, Nguyen Thanh and Absil, P-A and Stykel, Tatjana: Riemannian optimization on the symplectic Stiefel manifold, SIAM Journal on Optimization 31(2), pp. 1546-1575, 2021. doi 10.1137/20M1348522

    • BendokatZimmermann2021

      Bendokat, Thomas and Zimmermann, Ralf: The real symplectic Stiefel and Grassmann manifolds: metrics, geodesics and applications arXiv preprint arXiv:2108.12447, 2021.

    • BirteaCaşuComănescu2020

      Birtea, Petre and Caşu, Ioan and Comănescu, Dan: Optimization on the real symplectic group, Monatshefte f{"u}r Mathematik, Springer, 2020. doi 10.1007/s00605-020-01369-9

    diff --git a/previews/PR644/manifolds/symplecticstiefel.html b/previews/PR644/manifolds/symplecticstiefel.html new file mode 100644 index 0000000000..5e7b15d91c --- /dev/null +++ b/previews/PR644/manifolds/symplecticstiefel.html @@ -0,0 +1,78 @@ + +Symplectic Stiefel · Manifolds.jl

    Symplectic Stiefel

    The SymplecticStiefel manifold, denoted $\operatorname{SpSt}(2n, 2k)$, represents canonical symplectic bases of $2k$ dimensonal symplectic subspaces of $\mathbb{R}^{2n \times 2n}$. This means that the columns of each element $p \in \operatorname{SpSt}(2n, 2k) \subset \mathbb{R}^{2n \times 2k}$ constitute a canonical symplectic basis of $\operatorname{span}(p)$. The canonical symplectic form is a non-degenerate, bilinear, and skew symmetric map $\omega_{2k}\colon \mathbb{F}^{2k} \times \mathbb{F}^{2k} \rightarrow \mathbb{F}$, given by $\omega_{2k}(x, y) = x^T Q_{2k} y$ for elements $x, y \in \mathbb{F}^{2k}$, with

    \[ Q_{2k} = + \begin{bmatrix} + 0_k & I_k \\ + -I_k & 0_k + \end{bmatrix}.\]

    Specifically given an element $p \in \operatorname{SpSt}(2n, 2k)$ we require that

    \[ \omega_{2n} (p x, p y) = x^T(p^TQ_{2n}p)y = x^TQ_{2k}y = \omega_{2k}(x, y) \;\forall\; x, y \in \mathbb{F}^{2k},\]

    leading to the requirement on $p$ that $p^TQ_{2n}p = Q_{2k}$. In the case that $k = n$, this manifold reduces to the Symplectic manifold, which is also known as the symplectic group.

    Manifolds.SymplecticStiefelType
    SymplecticStiefel{n, k, 𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType}

    The symplectic Stiefel manifold consists of all $2n × 2k, \; n \geq k$ matrices satisfying the requirement

    \[\operatorname{SpSt}(2n, 2k, ℝ) + = \bigl\{ p ∈ ℝ^{2n × 2n} \, \big| \, p^{\mathrm{T}}Q_{2n}p = Q_{2k} \bigr\},\]

    where

    \[Q_{2n} = +\begin{bmatrix} + 0_n & I_n \\ + -I_n & 0_n +\end{bmatrix}.\]

    The symplectic Stiefel tangent space at $p$ can be parametrized as [BendokatZimmermann2021]

    \[ \begin{align*} + T_p\operatorname{SpSt}(2n, 2k) + = \{&X \in \mathbb{R}^{2n \times 2k} \;|\; p^{T}Q_{2n}X + X^{T}Q_{2n}p = 0 \}, \\ + = \{&X = pΩ + p^sB \;|\; + Ω ∈ ℝ^{2k × 2k}, Ω^+ = -Ω, \\ + &\; p^s ∈ \operatorname{SpSt}(2n, 2(n- k)), B ∈ ℝ^{2(n-k) × 2k}, \}, + \end{align*}\]

    where $Ω \in \mathfrak{sp}(2n,F)$ is Hamiltonian and $p^s$ means the symplectic complement of $p$ s.t. $p^{+}p^{s} = 0$.

    Constructor

    SymplecticStiefel(2n::Int, 2k::Int, field::AbstractNumbers=ℝ)
    +    -> SymplecticStiefel{div(2n, 2), div(2k, 2), field}()

    Generate the (real-valued) symplectic Stiefel manifold of $2n \times 2k$ matrices which span a $2k$ dimensional symplectic subspace of $ℝ^{2n \times 2n}$. The constructor for the SymplecticStiefel manifold accepts the even column dimension $2n$ and an even number of columns $2k$ for the real symplectic Stiefel manifold with elements $p \in ℝ^{2n × 2k}$.

    source
    Base.expMethod
    exp(::SymplecticStiefel, p, X)
    +exp!(M::SymplecticStiefel, q, p, X)

    Compute the exponential mapping

    \[ \operatorname{exp}\colon T\operatorname{SpSt}(2n, 2k) + \rightarrow \operatorname{SpSt}(2n, 2k)\]

    at a point $p \in \operatorname{SpSt}(2n, 2k)$ in the direction of $X \in T_p\operatorname{SpSt}(2n, 2k)$.

    The tangent vector $X$ can be written in the form $X = \bar{\Omega}p$ [BendokatZimmermann2021], with

    \[ \bar{\Omega} = X (p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}} + + Q_{2n}p(p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(I_{2n} - Q_{2n}^{\mathrm{T}}p(p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}}Q_{2n})Q_{2n} + \in ℝ^{2n \times 2n},\]

    where $Q_{2n}$ is the SymplecticMatrix. Using this expression for $X$, the exponential mapping can be computed as

    \[ \operatorname{exp}_p(X) = \operatorname{Exp}([\bar{\Omega} - \bar{\Omega}^{\mathrm{T}}]) + \operatorname{Exp}(\bar{\Omega}^{\mathrm{T}})p,\]

    where $\operatorname{Exp}(\cdot)$ denotes the matrix exponential.

    Computing the above mapping directly however, requires taking matrix exponentials of two $2n \times 2n$ matrices, which is computationally expensive when $n$ increases. Therefore we instead follow [BendokatZimmermann2021] who express the above exponential mapping in a way which only requires taking matrix exponentials of an $8k \times 8k$ matrix and a $4k \times 4k$ matrix.

    To this end, first define

    \[\bar{A} = Q_{2k}p^{\mathrm{T}}X(p^{\mathrm{T}}p)^{-1}Q_{2k} + + (p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(p - Q_{2n}^{\mathrm{T}}p(p^{\mathrm{T}}p)^{-1}Q_{2k}) \in ℝ^{2k \times 2k},\]

    and

    \[\bar{H} = (I_{2n} - pp^+)Q_{2n}X(p^{\mathrm{T}}p)^{-1}Q_{2k} \in ℝ^{2n \times 2k}.\]

    We then let $\bar{\Delta} = p\bar{A} + \bar{H}$, and define the matrices

    \[ γ = \left[\left(I_{2n} - \frac{1}{2}pp^+\right)\bar{\Delta} \quad + -p \right] \in ℝ^{2n \times 4k},\]

    and

    \[ λ = \left[Q_{2n}^{\mathrm{T}}pQ_{2k} \quad + \left(\bar{\Delta}^+\left(I_{2n} + - \frac{1}{2}pp^+\right)\right)^{\mathrm{T}}\right] \in ℝ^{2n \times 4k}.\]

    With the above defined matrices it holds that $\bar{\Omega} = λγ^{\mathrm{T}}$. As a last preliminary step, concatenate $γ$ and $λ$ to define the matrices $Γ = [λ \quad -γ] \in ℝ^{2n \times 8k}$ and $Λ = [γ \quad λ] \in ℝ^{2n \times 8k}$.

    With these matrix constructions done, we can compute the exponential mapping as

    \[ \operatorname{exp}_p(X) = + Γ \operatorname{Exp}(ΛΓ^{\mathrm{T}}) + \begin{bmatrix} + 0_{4k} \\ + I_{4k} + \end{bmatrix} + \operatorname{Exp}(λγ^{\mathrm{T}}) + \begin{bmatrix} + 0_{2k} \\ + I_{2k} + \end{bmatrix}.\]

    which only requires computing the matrix exponentials of $ΛΓ^{\mathrm{T}} \in ℝ^{8k \times 8k}$ and $λγ^{\mathrm{T}} \in ℝ^{4k \times 4k}$.

    source
    Base.invMethod
    inv(::SymplecticStiefel{n, k}, A)
    +inv!(::SymplecticStiefel{n, k}, q, p)

    Compute the symplectic inverse $A^+$ of matrix $A ∈ ℝ^{2n × 2k}$. Given a matrix

    \[A ∈ ℝ^{2n × 2k},\quad +A = +\begin{bmatrix} +A_{1, 1} & A_{1, 2} \\ +A_{2, 1} & A_{2, 2} +\end{bmatrix},\; A_{i, j} \in ℝ^{2n × 2k}\]

    the symplectic inverse is defined as:

    \[A^{+} := Q_{2k}^{\mathrm{T}} A^{\mathrm{T}} Q_{2n},\]

    where

    \[Q_{2n} = +\begin{bmatrix} +0_n & I_n \\ + -I_n & 0_n +\end{bmatrix}.\]

    For any $p \in \operatorname{SpSt}(2n, 2k)$ we have that $p^{+}p = I_{2k}$.

    The symplectic inverse of a matrix A can be expressed explicitly as:

    \[A^{+} = +\begin{bmatrix} + A_{2, 2}^{\mathrm{T}} & -A_{1, 2}^{\mathrm{T}} \\[1.2mm] + -A_{2, 1}^{\mathrm{T}} & A_{1, 1}^{\mathrm{T}} +\end{bmatrix}.\]

    source
    Base.randMethod
    rand(M::SymplecticStiefel; vector_at=nothing,
    +    hamiltonian_norm=(vector_at === nothing ? 1/2 : 1.0))

    Generate a random point $p \in \operatorname{SpSt}(2n, 2k)$ or a random tangent vector $X \in T_p\operatorname{SpSt}(2n, 2k)$ if vector_at is set to a point $p \in \operatorname{Sp}(2n)$.

    A random point on $\operatorname{SpSt}(2n, 2k)$ is found by first generating a random point on the symplectic manifold $\operatorname{Sp}(2n)$, and then projecting onto the Symplectic Stiefel manifold using the canonical_project $π_{\operatorname{SpSt}(2n, 2k)}$. That is, $p = π_{\operatorname{SpSt}(2n, 2k)}(p_{\operatorname{Sp}})$.

    To generate a random tangent vector in $T_p\operatorname{SpSt}(2n, 2k)$ this code exploits the second tangent vector space parametrization of SymplecticStiefel, showing that any $X \in T_p\operatorname{SpSt}(2n, 2k)$ can be written as $X = pΩ_X + p^sB_X$. To generate random tangent vectors at $p$ then, this function sets $B_X = 0$ and generates a random Hamiltonian matrix $Ω_X \in \mathfrak{sp}(2n,F)$ with Frobenius norm of hamiltonian_norm before returning $X = pΩ_X$.

    source
    ManifoldDiff.riemannian_gradientMethod
    X = riemannian_gradient(::SymplecticStiefel, f, p, Y; embedding_metric::EuclideanMetric=EuclideanMetric())
    +riemannian_gradient!(::SymplecticStiefel, f, X, p, Y; embedding_metric::EuclideanMetric=EuclideanMetric())

    Compute the riemannian gradient X of f on SymplecticStiefel at a point p, provided that the gradient of the function $\tilde f$, which is f continued into the embedding is given by Y. The metric in the embedding is the Euclidean metric.

    The manifold gradient X is computed from Y as

    \[ X = Yp^{\mathrm{T}}p + Q_{2n}pY^{\mathrm{T}}Q_{2n}p,\]

    where $Q_{2n}$ is the SymplecticMatrix.

    source
    Manifolds.canonical_projectMethod
    canonical_project(::SymplecticStiefel, p_Sp)
    +canonical_project!(::SymplecticStiefel{n,k}, p, p_Sp)

    Define the canonical projection from $\operatorname{Sp}(2n, 2n)$ onto $\operatorname{SpSt}(2n, 2k)$, by projecting onto the first $k$ columns and the $n + 1$'th onto the $n + k$'th columns [BendokatZimmermann2021].

    It is assumed that the point $p$ is on $\operatorname{Sp}(2n, 2n)$.

    source
    Manifolds.symplectic_inverse_timesMethod
    symplectic_inverse_times(::SymplecticStiefel, p, q)
    +symplectic_inverse_times!(::SymplecticStiefel, A, p, q)

    Directly compute the symplectic inverse of $p \in \operatorname{SpSt}(2n, 2k)$, multiplied with $q \in \operatorname{SpSt}(2n, 2k)$. That is, this function efficiently computes $p^+q = (Q_{2k}p^{\mathrm{T}}Q_{2n})q \in ℝ^{2k \times 2k}$, where $Q_{2n}, Q_{2k}$ are the SymplecticMatrix of sizes $2n \times 2n$ and $2k \times 2k$ respectively.

    This function performs this common operation without allocating more than a $2k \times 2k$ matrix to store the result in, or in the case of the in-place function, without allocating memory at all.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::SymplecticStiefel, p; kwargs...)

    Check whether p is a valid point on the SymplecticStiefel, $\operatorname{SpSt}(2n, 2k)$ manifold. That is, the point has the right AbstractNumbers type and $p^{+}p$ is (approximately) the identity, where for $A \in \mathbb{R}^{2n \times 2k}$, $A^{+} = Q_{2k}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}$ is the symplectic inverse, with

    \[Q_{2n} = +\begin{bmatrix} +0_n & I_n \\ + -I_n & 0_n +\end{bmatrix}.\]

    The tolerance can be set with kwargs... (e.g. atol = 1.0e-14).

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::Symplectic, p, X; kwargs...)

    Checks whether X is a valid tangent vector at p on the SymplecticStiefel, $\operatorname{SpSt}(2n, 2k)$ manifold. First recall the definition of the symplectic inverse for $A \in \mathbb{R}^{2n \times 2k}$, $A^{+} = Q_{2k}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}$ is the symplectic inverse, with

    \[ Q_{2n} = + \begin{bmatrix} + 0_n & I_n \\ + -I_n & 0_n +\end{bmatrix}.\]

    The we check that $H = p^{+}X \in 𝔤_{2k}$, where $𝔤$ is the Lie Algebra of the symplectic group $\operatorname{Sp}(2k)$, characterized as [BendokatZimmermann2021],

    \[ 𝔤_{2k} = \{H \in ℝ^{2k \times 2k} \;|\; H^+ = -H \}.\]

    The tolerance can be set with kwargs... (e.g. atol = 1.0e-14).

    source
    ManifoldsBase.innerMethod
    inner(M::SymplecticStiefel{n, k}, p, X. Y)

    Compute the Riemannian inner product $g^{\operatorname{SpSt}}$ at $p \in \operatorname{SpSt}$ between tangent vectors $X, X \in T_p\operatorname{SpSt}$. Given by Proposition 3.10 in [BendokatZimmermann2021].

    \[g^{\operatorname{SpSt}}_p(X, Y) + = \operatorname{tr}\left(X^{\mathrm{T}}\left(I_{2n} - + \frac{1}{2}Q_{2n}^{\mathrm{T}}p(p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}}Q_{2n}\right)Y(p^{\mathrm{T}}p)^{-1}\right).\]

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(::SymplecticStiefel, p, q, ::CayleyInverseRetraction)
    +inverse_retract!(::SymplecticStiefel, q, p, X, ::CayleyInverseRetraction)

    Compute the Cayley Inverse Retraction $X = \mathcal{L}_p^{\operatorname{SpSt}}(q)$ such that the Cayley Retraction from $p$ along $X$ lands at $q$, i.e. $\mathcal{R}_p(X) = q$ [BendokatZimmermann2021].

    First, recall the definition the standard symplectic matrix

    \[Q = +\begin{bmatrix} + 0 & I \\ +-I & 0 +\end{bmatrix}\]

    as well as the symplectic inverse of a matrix $A$, $A^{+} = Q^{\mathrm{T}} A^{\mathrm{T}} Q$.

    For $p, q ∈ \operatorname{SpSt}(2n, 2k, ℝ)$ then, we can define the inverse cayley retraction as long as the following matrices exist.

    \[ U = (I + p^+ q)^{-1} \in ℝ^{2k \times 2k}, + \quad + V = (I + q^+ p)^{-1} \in ℝ^{2k \times 2k}.\]

    If that is the case, the inverse cayley retration at $p$ applied to $q$ is

    \[\mathcal{L}_p^{\operatorname{Sp}}(q) = 2p\bigl(V - U\bigr) + 2\bigl((p + q)U - p\bigr) + ∈ T_p\operatorname{Sp}(2n).\]

    source
    ManifoldsBase.projectMethod
    project(::SymplecticStiefel, p, A)
    +project!(::SymplecticStiefel, Y, p, A)

    Given a point $p \in \operatorname{SpSt}(2n, 2k)$, project an element $A \in \mathbb{R}^{2n \times 2k}$ onto the tangent space $T_p\operatorname{SpSt}(2n, 2k)$ relative to the euclidean metric of the embedding $\mathbb{R}^{2n \times 2k}$.

    That is, we find the element $X \in T_p\operatorname{SpSt}(2n, 2k)$ which solves the constrained optimization problem

    \[ \operatorname{min}_{X \in \mathbb{R}^{2n \times 2k}} \frac{1}{2}||X - A||^2, \quad + \text{s.t.}\; + h(X)\colon= X^{\mathrm{T}} Q p + p^{\mathrm{T}} Q X = 0,\]

    where $h : \mathbb{R}^{2n \times 2k} \rightarrow \operatorname{skew}(2k)$ defines the restriction of $X$ onto the tangent space $T_p\operatorname{SpSt}(2n, 2k)$.

    source
    ManifoldsBase.retractMethod
    retract(::SymplecticStiefel, p, X, ::CayleyRetraction)
    +retract!(::SymplecticStiefel, q, p, X, ::CayleyRetraction)

    Compute the Cayley retraction on the Symplectic Stiefel manifold, computed inplace of q from p along X.

    Given a point $p \in \operatorname{SpSt}(2n, 2k)$, every tangent vector $X \in T_p\operatorname{SpSt}(2n, 2k)$ is of the form $X = \tilde{\Omega}p$, with

    \[ \tilde{\Omega} = \left(I_{2n} - \frac{1}{2}pp^+\right)Xp^+ - + pX^+\left(I_{2n} - \frac{1}{2}pp^+\right) \in ℝ^{2n \times 2n},\]

    as shown in Proposition 3.5 of [BendokatZimmermann2021]. Using this representation of $X$, the Cayley retraction on $\operatorname{SpSt}(2n, 2k)$ is defined pointwise as

    \[ \mathcal{R}_p(X) = \operatorname{cay}\left(\frac{1}{2}\tilde{\Omega}\right)p.\]

    The operator $\operatorname{cay}(A) = (I - A)^{-1}(I + A)$ is the Cayley transform.

    However, the computation of an $2n \times 2n$ matrix inverse in the expression above can be reduced down to inverting a $2k \times 2k$ matrix due to Proposition 5.2 of [BendokatZimmermann2021].

    Let $A = p^+X$ and $H = X - pA$. Then an equivalent expression for the Cayley retraction defined pointwise above is

    \[ \mathcal{R}_p(X) = -p + (H + 2p)(H^+H/4 - A/2 + I_{2k})^{-1}.\]

    It is this expression we compute inplace of q.

    source

    Literature

    • BendokatZimmermann2021

      Bendokat, Thomas and Zimmermann, Ralf: The real symplectic Stiefel and Grassmann manifolds: metrics, geodesics and applications arXiv preprint arXiv:2108.12447, 2021.

    diff --git a/previews/PR644/manifolds/torus.html b/previews/PR644/manifolds/torus.html new file mode 100644 index 0000000000..f44fab7a6c --- /dev/null +++ b/previews/PR644/manifolds/torus.html @@ -0,0 +1,13 @@ + +Torus · Manifolds.jl

    Torus

    The torus $𝕋^d ≅ [-π,π)^d$ is modeled as an AbstractPowerManifold of the (real-valued) Circle and uses ArrayPowerRepresentation. Points on the torus are hence row vectors, $x ∈ ℝ^{d}$.

    Example

    The following code can be used to make a three-dimensional torus $𝕋^3$ and compute a tangent vector:

    using Manifolds
    +M = Torus(3)
    +p = [0.5, 0.0, 0.0]
    +q = [0.0, 0.5, 1.0]
    +X = log(M, p, q)
    3-element Vector{Float64}:
    + -0.5
    +  0.5
    +  1.0

    Types and functions

    Most functions are directly implemented for an AbstractPowerManifold with ArrayPowerRepresentation except the following special cases:

    ManifoldsBase.check_vectorMethod
    check_vector(M::Torus{n}, p, X; kwargs...)

    Checks whether X is a valid tangent vector to p on the Torus M. This means, that p is valid, that X is of correct dimension and elementwise a tangent vector to the elements of p on the Circle.

    source

    Embedded Torus

    Two-dimensional torus embedded in $ℝ^3$.

    Manifolds.DefaultTorusAtlasType
    DefaultTorusAtlas()

    Atlas for torus with charts indexed by two angles numbers $θ₀, φ₀ ∈ [-π, π)$. Inverse of a chart $(θ₀, φ₀)$ is given by

    \[x(θ, φ) = (R + r\cos(θ + θ₀))\cos(φ + φ₀) \\ +y(θ, φ) = (R + r\cos(θ + θ₀))\sin(φ + φ₀) \\ +z(θ, φ) = r\sin(θ + θ₀)\]

    source
    Manifolds.EmbeddedTorusType
    EmbeddedTorus{TR<:Real} <: AbstractDecoratorManifold{ℝ}

    Surface in ℝ³ described by parametric equations:

    \[x(θ, φ) = (R + r\cos θ)\cos φ \\ +y(θ, φ) = (R + r\cos θ)\sin φ \\ +z(θ, φ) = r\sin θ\]

    for θ, φ in $[-π, π)$. It is assumed that $R > r > 0$.

    Alternative names include anchor ring, donut and doughnut.

    Constructor

    EmbeddedTorus(R, r)
    source
    Manifolds.check_chart_switchMethod
    check_chart_switch(::EmbeddedTorus, A::DefaultTorusAtlas, i, a; ϵ = pi/3)

    Return true if parameters a lie closer than ϵ to chart boundary.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::EmbeddedTorus, p; kwargs...)

    Check whether p is a valid point on the EmbeddedTorus M. The tolerance for the last test can be set using the kwargs....

    The method checks if $(p_1^2 + p_2^2 + p_3^2 + R^2 - r^2)^2$ is apprximately equal to $4R^2(p_1^2 + p_2^2)$.

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::EmbeddedTorus, p, X; atol=eps(eltype(p)), kwargs...)

    Check whether X is a valid vector tangent to p on the EmbeddedTorus M. The method checks if the vector X is orthogonal to the vector normal to the torus, see normal_vector. Absolute tolerance can be set using atol.

    source
    ManifoldsBase.innerMethod
    inner(M::EmbeddedTorus, ::DefaultTorusAtlas, i, a, Xc, Yc)

    Inner product on EmbeddedTorus in chart i in the DefaultTorusAtlas. between vectors with coordinates Xc and Yc tangent at point with parameters a. Vector coordinates must be given in the induced basis.

    source
    diff --git a/previews/PR644/manifolds/tucker.html b/previews/PR644/manifolds/tucker.html new file mode 100644 index 0000000000..2f14b983d9 --- /dev/null +++ b/previews/PR644/manifolds/tucker.html @@ -0,0 +1,17 @@ + +Tucker · Manifolds.jl

    Tucker manifold

    Manifolds.TuckerType
    Tucker{N, R, D, 𝔽} <: AbstractManifold{𝔽}

    The manifold of $N_1 \times \dots \times N_D$ real-valued or complex-valued tensors of fixed multilinear rank $(R_1, \dots, R_D)$ . If $R_1 = \dots = R_D = 1$, this is the Segre manifold, i.e., the set of rank-1 tensors.

    Representation in HOSVD format

    Let $\mathbb{F}$ be the real or complex numbers. Any tensor $p$ on the Tucker manifold can be represented as a multilinear product in HOSVD [DeLathauwer2000] form

    \[p = (U_1,\dots,U_D) \cdot \mathcal{C}\]

    where $\mathcal C \in \mathbb{F}^{R_1 \times \dots \times R_D}$ and, for $d=1,\dots,D$, the matrix $U_d \in \mathbb{F}^{N_d \times R_d}$ contains the singular vectors of the $d$th unfolding of $\mathcal{A}$

    Tangent space

    The tangent space to the Tucker manifold at $p = (U_1,\dots,U_D) \cdot \mathcal{C}$ is [Koch2010]

    \[T_p \mathcal{M} = +\bigl\{ +(U_1,\dots,U_D) \cdot \mathcal{C}^\prime ++ \sum_{d=1}^D \bigl( + (U_1, \dots, U_{d-1}, U_d^\prime, U_{d+1}, \dots, U_D) + \cdot \mathcal{C} +\bigr) +\bigr\}\]

    where $\mathcal{C}^\prime$ is arbitrary, $U_d^{\mathrm{H}}$ is the Hermitian adjoint of $U_d$, and $U_d^{\mathrm{H}} U_d^\prime = 0$ for all $d$.

    Constructor

    Tucker(N::NTuple{D, Int}, R::NTuple{D, Int}[, field = ℝ])

    Generate the manifold of field-valued tensors of dimensions N[1] × … × N[D] and multilinear rank R = (R[1], …, R[D]).

    source
    Manifolds.TuckerPointType
    TuckerPoint{T,D}

    An order D tensor of fixed multilinear rank and entries of type T, which makes it a point on the Tucker manifold. The tensor is represented in HOSVD form.

    Constructors:

    TuckerPoint(core::AbstractArray{T,D}, factors::Vararg{<:AbstractMatrix{T},D}) where {T,D}

    Construct an order D tensor of element type T that can be represented as the multilinear product (factors[1], …, factors[D]) ⋅ core. It is assumed that the dimensions of the core are the multilinear rank of the tensor and that the matrices factors each have full rank. No further assumptions are made.

    TuckerPoint(p::AbstractArray{T,D}, mlrank::NTuple{D,Int}) where {T,D}

    The low-multilinear rank tensor arising from the sequentially truncated the higher-order singular value decomposition of the D-dimensional array p of type T. The singular values are truncated to get a multilinear rank mlrank [Vannieuwenhoven2012].

    source
    Manifolds.TuckerTVectorType
    TuckerTVector{T, D} <: TVector

    Tangent vector to the D-th order Tucker manifold at $p = (U_1,\dots,U_D) ⋅ \mathcal{C}$. The numbers are of type T and the vector is represented as

    \[X = +(U_1,\dots,U_D) \cdot \mathcal{C}^\prime + +\sum_{d=1}^D (U_1,\dots,U_{d-1},U_d^\prime,U_{d+1},\dots,U_D) \cdot \mathcal{C}\]

    where $U_d^\mathrm{H} U_d^\prime = 0$.

    Constructor

    TuckerTVector(C′::Array{T,D}, U′::NTuple{D,Matrix{T}}) where {T,D}

    Constructs a Dth order TuckerTVector of number type T with $C^\prime$ and $U^\prime$, so that, together with a TuckerPoint $p$ as above, the tangent vector can be represented as $X$ in the above expression.

    source
    Base.convertMethod
    Base.convert(::Type{Matrix{T}}, basis::CachedBasis{𝔽,DefaultOrthonormalBasis{𝔽, TangentSpaceType},HOSVDBasis{T, D}}) where {𝔽, T, D}
    +Base.convert(::Type{Matrix}, basis::CachedBasis{𝔽,DefaultOrthonormalBasis{𝔽, TangentSpaceType},HOSVDBasis{T, D}}) where {𝔽, T, D}

    Convert a HOSVD-derived cached basis from [Dewaele2021] of the Dth order Tucker manifold with number type T to a matrix. The columns of this matrix are the vectorisations of the embeddings of the basis vectors.

    source
    Base.foreachFunction
    Base.foreach(f, M::Tucker, p::TuckerPoint, basis::AbstractBasis, indices=1:manifold_dimension(M))

    Let basis be and AbstractBasis at a point p on M. Suppose f is a function that takes an index and a vector as an argument. This function applies f to i and the ith basis vector sequentially for each i in indices. Using a CachedBasis may speed up the computation.

    NOTE: The i'th basis vector is overwritten in each iteration. If any information about the vector is to be stored, f must make a copy.

    source
    Base.ndimsMethod
    Base.ndims(p::TuckerPoint{T,D}) where {T,D}

    The order of the tensor corresponding to the TuckerPoint p, i.e., D.

    source
    ManifoldsBase.check_pointMethod
    check_point(M::Tucker{N,R,D}, p; kwargs...) where {N,R,D}

    Check whether the multidimensional array or TuckerPoint p is a point on the Tucker manifold, i.e. it is a Dth order N[1] × … × N[D] tensor of multilinear rank (R[1], …, R[D]). The keyword arguments are passed to the matrix rank function applied to the unfoldings. For a TuckerPoint it is checked that the point is in correct HOSVD form.

    source
    ManifoldsBase.check_vectorMethod
    check_vector(M::Tucker{N,R,D}, p::TuckerPoint{T,D}, X::TuckerTVector) where {N,R,T,D}

    Check whether a TuckerTVector X is is in the tangent space to the Dth order Tucker manifold M at the Dth order TuckerPoint p. This is the case when the dimensions of the factors in X agree with those of p and the factor matrices of X are in the orthogonal complement of the HOSVD factors of p.

    source
    ManifoldsBase.embedMethod
    embed(::Tucker{N,R,D}, p::TuckerPoint) where {N,R,D}

    Convert a TuckerPoint p on the rank R Tucker manifold to a full N[1] × … × N[D]-array by evaluating the Tucker decomposition.

    embed(::Tucker{N,R,D}, p::TuckerPoint, X::TuckerTVector) where {N,R,D}

    Convert a tangent vector X with base point p on the rank R Tucker manifold to a full tensor, represented as an N[1] × … × N[D]-array.

    source
    ManifoldsBase.get_basisMethod
    get_basis(:: Tucker, p::TuckerPoint, basisType::DefaultOrthonormalBasis{𝔽, TangentSpaceType}) where 𝔽

    An implicitly stored basis of the tangent space to the Tucker manifold. Assume $p = (U_1,\dots,U_D) \cdot \mathcal{C}$ is in HOSVD format and that, for $d=1,\dots,D$, the singular values of the $d$'th unfolding are $\sigma_{dj}$, with $j = 1,\dots,R_d$. The basis of the tangent space is as follows: [Dewaele2021]

    \[\bigl\{ +(U_1,\dots,U_D) e_i +\bigr\} \cup \bigl\{ +(U_1,\dots, \sigma_{dj}^{-1} U_d^{\perp} e_i e_j^T,\dots,U_D) \cdot \mathcal{C} +\bigr\}\]

    for all $d = 1,\dots,D$ and all canonical basis vectors $e_i$ and $e_j$. Every $U_d^\perp$ is such that $[U_d \quad U_d^{\perp}]$ forms an orthonormal basis of $\mathbb{R}^{N_d}$.

    source
    ManifoldsBase.innerMethod
    inner(M::Tucker, p::TuckerPoint, X::TuckerTVector, Y::TuckerTVector)

    The Euclidean inner product between tangent vectors X and X at the point p on the Tucker manifold. This is equal to embed(M, p, X) ⋅ embed(M, p, Y).

    inner(::Tucker, A::TuckerPoint, X::TuckerTVector, Y)
    +inner(::Tucker, A::TuckerPoint, X, Y::TuckerTVector)

    The Euclidean inner product between X and Y where X is a vector tangent to the Tucker manifold at p and Y is a vector in the ambient space or vice versa. The vector in the ambient space is represented as a full tensor, i.e., a multidimensional array.

    source
    ManifoldsBase.inverse_retractMethod
    inverse_retract(M::Tucker, p::TuckerPoint, q::TuckerPoint, ::ProjectionInverseRetraction)

    The projection inverse retraction on the Tucker manifold interprets q as a point in the ambient Euclidean space (see embed) and projects it onto the tangent space at to M at p.

    source
    ManifoldsBase.manifold_dimensionMethod
    manifold_dimension(::Tucker{N,R,D}) where {N,R,D}

    The dimension of the manifold of $N_1 \times \dots \times N_D$ tensors of multilinear rank $(R_1, \dots, R_D)$, i.e.

    \[\mathrm{dim}(\mathcal{M}) = \prod_{d=1}^D R_d + \sum_{d=1}^D R_d (N_d - R_d).\]

    source
    ManifoldsBase.projectMethod
    project(M::Tucker, p::TuckerPoint, X)

    The least-squares projection of a dense tensor X onto the tangent space to M at p.

    source
    ManifoldsBase.retractMethod
    retract(::Tucker, p::TuckerPoint, X::TuckerTVector, ::PolarRetraction)

    The truncated HOSVD-based retraction [Kressner2014] to the Tucker manifold, i.e. the result is the sequentially tuncated HOSVD approximation of $p + X$.

    In the exceptional case that the multilinear rank of $p + X$ is lower than that of $p$, this retraction produces a boundary point, which is outside the manifold.

    source

    Literature

    • DeLathauwer2000

      Lieven De Lathauwer, Bart De Moor, Joos Vandewalle: "A multilinear singular value decomposition" SIAM Journal on Matrix Analysis and Applications, 21(4), pp. 1253-1278, 2000 doi: 10.1137/S0895479896305696

    • Koch2010

      Othmar Koch, Christian Lubic, "Dynamical Tensor approximation" SIAM Journal on Matrix Analysis and Applications, 31(5), pp. 2360-2375, 2010 doi: 10.1137/09076578X

    • Vannieuwenhoven2012

      Nick Vannieuwenhoven, Raf Vandebril, Karl Meerbergen: "A new truncation strategy for the higher-order singular value decomposition" SIAM Journal on Scientific Computing, 34(2), pp. 1027-1052, 2012 doi: 10.1137/110836067

    • Dewaele2021

      Nick Dewaele, Paul Breiding, Nick Vannieuwenhoven, "The condition number of many tensor decompositions is invariant under Tucker compression" arxiv: 2106.13034

    • Kressner2014

      Daniel Kressner, Michael Steinlechner, Bart Vandereycken: "Low-rank tensor completion by Riemannian optimization" BIT Numerical Mathematics, 54(2), pp. 447-468, 2014 doi: 10.1007/s10543-013-0455-z

    diff --git a/previews/PR644/manifolds/vector_bundle.html b/previews/PR644/manifolds/vector_bundle.html new file mode 100644 index 0000000000..503587dce0 --- /dev/null +++ b/previews/PR644/manifolds/vector_bundle.html @@ -0,0 +1,33 @@ + +Vector bundle · Manifolds.jl

    Vector bundles

    Vector bundle $E$ is a manifold that is built on top of another manifold $\mathcal M$ (base space). It is characterized by a continuous function $Π : E → \mathcal M$, such that for each point $p ∈ \mathcal M$ the preimage of $p$ by $Π$, $Π^{-1}(\{p\})$, has a structure of a vector space. These vector spaces are called fibers. Bundle projection can be performed using function bundle_projection.

    Tangent bundle is a simple example of a vector bundle, where each fiber is the tangent space at the specified point $x$. An object representing a tangent bundle can be obtained using the constructor called TangentBundle.

    Fibers of a vector bundle are represented by the type VectorBundleFibers. The important difference between functions operating on VectorBundle and VectorBundleFibers is that in the first case both a point on the underlying manifold and the vector are represented together (by a single argument) while in the second case only the vector part is present, while the point is supplied in a different argument where needed.

    VectorBundleFibers refers to the whole set of fibers of a vector bundle. There is also another type, VectorSpaceAtPoint, that represents a specific fiber at a given point. This distinction is made to reduce the need to repeatedly construct objects of type VectorSpaceAtPoint in certain usage scenarios. This is also considered a manifold.

    FVector

    For cases where confusion between different types of vectors is possible, the type FVector can be used to express which type of vector space the vector belongs to. It is used for example in musical isomorphisms (the flat and sharp functions) that are used to go from a tangent space to cotangent space and vice versa.

    Documentation

    Manifolds.SasakiRetractionType
    struct SasakiRetraction <: AbstractRetractionMethod end

    Exponential map on TangentBundle computed via Euler integration as described in [Muralidharan2012]. The system of equations for $\gamma : ℝ \to T\mathcal M$ such that $\gamma(1) = \exp_{p,X}(X_M, X_F)$ and $\gamma(0)=(p, X)$ reads

    \[\dot{\gamma}(t) = (\dot{p}(t), \dot{X}(t)) = (R(X(t), \dot{X}(t))\dot{p}(t), 0)\]

    where $R$ is the Riemann curvature tensor (see riemann_tensor).

    Constructor

    SasakiRetraction(L::Int)

    In this constructor L is the number of integration steps.

    source
    Manifolds.TangentBundleType
    TangentBundle{𝔽,M} = VectorBundle{𝔽,TangentSpaceType,M} where {𝔽,M<:AbstractManifold{𝔽}}

    Tangent bundle for manifold of type M, as a manifold with the Sasaki metric [Sasaki1958].

    Exact retraction and inverse retraction can be approximated using VectorBundleProductRetraction, VectorBundleInverseProductRetraction and SasakiRetraction. VectorBundleProductVectorTransport can be used as a vector transport.

    Constructors

    TangentBundle(M::AbstractManifold)
    +TangentBundle(M::AbstractManifold, vtm::VectorBundleProductVectorTransport)
    source
    Manifolds.TensorProductTypeType
    TensorProductType(spaces::VectorSpaceType...)

    Vector space type corresponding to the tensor product of given vector space types.

    source
    Manifolds.VectorBundleFibersType
    VectorBundleFibers(fiber::VectorSpaceType, M::AbstractManifold)

    Type representing a family of vector spaces (fibers) of a vector bundle over M with vector spaces of type fiber. In contrast with VectorBundle, operations on VectorBundleFibers expect point-like and vector-like parts to be passed separately instead of being bundled together. It can be thought of as a representation of vector spaces from a vector bundle but without storing the point at which a vector space is attached (which is specified separately in various functions).

    source
    Manifolds.VectorBundleInverseProductRetractionType
    struct VectorBundleInverseProductRetraction <: AbstractInverseRetractionMethod end

    Inverse retraction of the point y at point p from vector bundle B over manifold B.fiber (denoted $\mathcal M$). The inverse retraction is derived as a product manifold-style approximation to the logarithmic map in the Sasaki metric. The considered product manifold is the product between the manifold $\mathcal M$ and the topological vector space isometric to the fiber.

    Notation:

    • The point $p = (x_p, V_p)$ where $x_p ∈ \mathcal M$ and $V_p$ belongs to the fiber $F=π^{-1}(\{x_p\})$ of the vector bundle $B$ where $π$ is the canonical projection of that vector bundle $B$. Similarly, $q = (x_q, V_q)$.

    The inverse retraction is calculated as

    \[\operatorname{retr}^{-1}_p q = (\operatorname{retr}^{-1}_{x_p}(x_q), V_{\operatorname{retr}^{-1}} - V_p)\]

    where $V_{\operatorname{retr}^{-1}}$ is the result of vector transport of $V_q$ to the point $x_p$. The difference $V_{\operatorname{retr}^{-1}} - V_p$ corresponds to the logarithmic map in the vector space $F$.

    See also VectorBundleProductRetraction.

    source
    Manifolds.VectorBundleProductRetractionType
    struct VectorBundleProductRetraction <: AbstractRetractionMethod end

    Product retraction map of tangent vector $X$ at point $p$ from vector bundle B over manifold B.fiber (denoted $\mathcal M$). The retraction is derived as a product manifold-style approximation to the exponential map in the Sasaki metric. The considered product manifold is the product between the manifold $\mathcal M$ and the topological vector space isometric to the fiber.

    Notation:

    • The point $p = (x_p, V_p)$ where $x_p ∈ \mathcal M$ and $V_p$ belongs to the fiber $F=π^{-1}(\{x_p\})$ of the vector bundle $B$ where $π$ is the canonical projection of that vector bundle $B$.
    • The tangent vector $X = (V_{X,M}, V_{X,F}) ∈ T_pB$ where $V_{X,M}$ is a tangent vector from the tangent space $T_{x_p}\mathcal M$ and $V_{X,F}$ is a tangent vector from the tangent space $T_{V_p}F$ (isomorphic to $F$).

    The retraction is calculated as

    \[\operatorname{retr}_p(X) = (\exp_{x_p}(V_{X,M}), V_{\exp})\]

    where $V_{\exp}$ is the result of vector transport of $V_p + V_{X,F}$ to the point $\exp_{x_p}(V_{X,M})$. The sum $V_p + V_{X,F}$ corresponds to the exponential map in the vector space $F$.

    See also VectorBundleInverseProductRetraction.

    source
    Manifolds.VectorBundleProductVectorTransportType
    VectorBundleProductVectorTransport{
    +    TMP<:AbstractVectorTransportMethod,
    +    TMV<:AbstractVectorTransportMethod,
    +} <: AbstractVectorTransportMethod

    Vector transport type on VectorBundle. method_point is used for vector transport of the point part and method_vector is used for transport of the vector part.

    The vector transport is derived as a product manifold-style vector transport. The considered product manifold is the product between the manifold $\mathcal M$ and the topological vector space isometric to the fiber.

    Constructor

    VectorBundleProductVectorTransport(
    +    method_point::AbstractVectorTransportMethod,
    +    method_vector::AbstractVectorTransportMethod,
    +)
    +VectorBundleProductVectorTransport()

    By default both methods are set to ParallelTransport.

    source
    Manifolds.VectorSpaceAtPointType
    VectorSpaceAtPoint{
    +    𝔽,
    +    TFiber<:VectorBundleFibers{<:VectorSpaceType,<:AbstractManifold{𝔽}},
    +    TX,
    +} <: AbstractManifold{𝔽}

    A vector space at a point p on the manifold. This is modelled using VectorBundleFibers with only a vector-like part and fixing the point-like part to be just p.

    This vector space itself is also a manifold. Especially, it's flat and hence isometric to the Euclidean manifold.

    Constructor

    VectorSpaceAtPoint(fiber::VectorBundleFibers, p)

    A vector space (fiber type fiber of a vector bundle) at point p from the manifold fiber.manifold.

    source
    Base.expMethod
    exp(M::TangentSpaceAtPoint, p, X)

    Exponential map of tangent vectors X and p from the tangent space M. It is calculated as their sum.

    source
    Base.getindexMethod
    getindex(p::ArrayPartition, M::VectorBundle, s::Symbol)
    +p[M::VectorBundle, s]

    Access the element(s) at index s of a point p on a VectorBundle M by using the symbols :point and :vector for the base and vector component, respectively.

    source
    Base.getindexMethod
    getindex(p::ProductRepr, M::VectorBundle, s::Symbol)
    +p[M::VectorBundle, s]

    Access the element(s) at index s of a point p on a VectorBundle M by using the symbols :point and :vector for the base and vector component, respectively.

    source
    Base.logMethod
    log(M::TangentSpaceAtPoint, p, q)

    Logarithmic map on the tangent space manifold M, calculated as the difference of tangent vectors q and p from M.

    source
    Base.setindex!Method
    setindex!(p::ArrayPartition, val, M::VectorBundle, s::Symbol)
    +p[M::VectorBundle, s] = val

    Set the element(s) at index s of a point p on a VectorBundle M to val by using the symbols :point and :vector for the base and vector component, respectively.

    Note

    The content of element of p is replaced, not the element itself.

    source
    Base.setindex!Method
    setindex!(p::ProductRepr, val, M::VectorBundle, s::Symbol)
    +p[M::VectorBundle, s] = val

    Set the element(s) at index s of a point p on a VectorBundle M to val by using the symbols :point and :vector for the base and vector component, respectively.

    Note

    The content of element of p is replaced, not the element itself.

    source
    LinearAlgebra.normMethod
    norm(B::VectorBundleFibers, p, q)

    Norm of the vector X from the vector space of type B.fiber at point p from manifold B.manifold.

    source
    Manifolds.bundle_projectionMethod
    bundle_projection(B::VectorBundle, p::ArrayPartition)

    Projection of point p from the bundle M to the base manifold. Returns the point on the base manifold B.manifold at which the vector part of p is attached.

    source
    Manifolds.vector_bundle_transportMethod
    vector_bundle_transport(fiber::VectorSpaceType, M::AbstractManifold)

    Determine the vector tranport used for exp and log maps on a vector bundle with vector space type fiber and manifold M.

    source
    ManifoldsBase.allocate_resultMethod
    allocate_result(B::VectorBundleFibers, f, x...)

    Allocates an array for the result of function f that is an element of the vector space of type B.fiber on manifold B.manifold and arguments x... for implementing the non-modifying operation using the modifying operation.

    source
    ManifoldsBase.allocate_result_typeMethod
    allocate_result_type(B::VectorBundleFibers, f, args::NTuple{N,Any}) where N

    Return type of element of the array that will represent the result of function f for representing an operation with result in the vector space fiber for manifold M on given arguments (passed at a tuple).

    source
    ManifoldsBase.distanceMethod
    distance(M::TangentSpaceAtPoint, p, q)

    Distance between vectors p and q from the vector space M. It is calculated as the norm of their difference.

    source
    ManifoldsBase.distanceMethod
    distance(B::VectorBundleFibers, p, X, Y)

    Distance between vectors X and Y from the vector space at point p from the manifold B.manifold, that is the base manifold of M.

    source
    ManifoldsBase.innerMethod
    inner(M::TangentSpaceAtPoint, p, X, Y)

    Inner product of vectors X and Y from the tangent space at M.

    source
    ManifoldsBase.innerMethod
    inner(B::VectorBundle, p, X, Y)

    Inner product of tangent vectors X and Y at point p from the vector bundle B over manifold B.fiber (denoted $\mathcal M$).

    Notation:

    • The point $p = (x_p, V_p)$ where $x_p ∈ \mathcal M$ and $V_p$ belongs to the fiber $F=π^{-1}(\{x_p\})$ of the vector bundle $B$ where $π$ is the canonical projection of that vector bundle $B$.
    • The tangent vector $v = (V_{X,M}, V_{X,F}) ∈ T_{x}B$ where $V_{X,M}$ is a tangent vector from the tangent space $T_{x_p}\mathcal M$ and $V_{X,F}$ is a tangent vector from the tangent space $T_{V_p}F$ (isomorphic to $F$). Similarly for the other tangent vector $w = (V_{Y,M}, V_{Y,F}) ∈ T_{x}B$.

    The inner product is calculated as

    \[⟨X, Y⟩_p = ⟨V_{X,M}, V_{Y,M}⟩_{x_p} + ⟨V_{X,F}, V_{Y,F}⟩_{V_p}.\]

    source
    ManifoldsBase.innerMethod
    inner(B::VectorBundleFibers, p, X, Y)

    Inner product of vectors X and Y from the vector space of type B.fiber at point p from manifold B.manifold.

    source
    ManifoldsBase.projectMethod
    project(M::TangentSpaceAtPoint, p, X)

    Project the vector X from the tangent space M, that is project the vector X tangent at M.point.

    source
    ManifoldsBase.projectMethod
    project(M::TangentSpaceAtPoint, p)

    Project the point p from the tangent space M, that is project the vector p tangent at M.point.

    source
    ManifoldsBase.projectMethod
    project(B::VectorBundle, p, X)

    Project the element X of the ambient space of the tangent space $T_p B$ to the tangent space $T_p B$.

    Notation:

    • The point $p = (x_p, V_p)$ where $x_p ∈ \mathcal M$ and $V_p$ belongs to the fiber $F=π^{-1}(\{x_p\})$ of the vector bundle $B$ where $π$ is the canonical projection of that vector bundle $B$.
    • The vector $x = (V_{X,M}, V_{X,F})$ where $x_p$ belongs to the ambient space of $T_{x_p}\mathcal M$ and $V_{X,F}$ belongs to the ambient space of the fiber $F=π^{-1}(\{x_p\})$ of the vector bundle $B$ where $π$ is the canonical projection of that vector bundle $B$.

    The projection is calculated by projecting $V_{X,M}$ to tangent space $T_{x_p}\mathcal M$ and then projecting the vector $V_{X,F}$ to the fiber $F$.

    source
    ManifoldsBase.projectMethod
    project(B::VectorBundle, p)

    Project the point p from the ambient space of the vector bundle B over manifold B.fiber (denoted $\mathcal M$) to the vector bundle.

    Notation:

    • The point $p = (x_p, V_p)$ where $x_p$ belongs to the ambient space of $\mathcal M$ and $V_p$ belongs to the ambient space of the fiber $F=π^{-1}(\{x_p\})$ of the vector bundle $B$ where $π$ is the canonical projection of that vector bundle $B$.

    The projection is calculated by projecting the point $x_p$ to the manifold $\mathcal M$ and then projecting the vector $V_p$ to the tangent space $T_{x_p}\mathcal M$.

    source
    ManifoldsBase.projectMethod
    project(B::VectorBundleFibers, p, X)

    Project vector X from the vector space of type B.fiber at point p.

    source
    ManifoldsBase.zero_vector!Method
    zero_vector!(B::VectorBundleFibers, X, p)

    Save the zero vector from the vector space of type B.fiber at point p from manifold B.manifold to X.

    source
    ManifoldsBase.zero_vectorMethod
    zero_vector(M::TangentSpaceAtPoint, p)

    Zero tangent vector at point p from the tangent space M, that is the zero tangent vector at point M.point.

    source
    ManifoldsBase.zero_vectorMethod
    zero_vector(B::VectorBundle, p)

    Zero tangent vector at point p from the vector bundle B over manifold B.fiber (denoted $\mathcal M$). The zero vector belongs to the space $T_{p}B$

    Notation:

    • The point $p = (x_p, V_p)$ where $x_p ∈ \mathcal M$ and $V_p$ belongs to the fiber $F=π^{-1}(\{x_p\})$ of the vector bundle $B$ where $π$ is the canonical projection of that vector bundle $B$.

    The zero vector is calculated as

    \[\mathbf{0}_{p} = (\mathbf{0}_{x_p}, \mathbf{0}_F)\]

    where $\mathbf{0}_{x_p}$ is the zero tangent vector from $T_{x_p}\mathcal M$ and $\mathbf{0}_F$ is the zero element of the vector space $F$.

    source
    ManifoldsBase.zero_vectorMethod
    zero_vector(B::VectorBundleFibers, p)

    Compute the zero vector from the vector space of type B.fiber at point p from manifold B.manifold.

    source

    Example

    The following code defines a point on the tangent bundle of the sphere $S^2$ and a tangent vector to that point.

    using Manifolds
    +M = Sphere(2)
    +TB = TangentBundle(M)
    +p = ProductRepr([1.0, 0.0, 0.0], [0.0, 1.0, 3.0])
    +X = ProductRepr([0.0, 1.0, 0.0], [0.0, 0.0, -2.0])
    ProductRepr with 2 submanifold components:
    + Component 1 =
    +  3-element Vector{Float64}:
    +   0.0
    +   1.0
    +   0.0
    + Component 2 =
    +  3-element Vector{Float64}:
    +    0.0
    +    0.0
    +   -2.0

    An approximation of the exponential in the Sasaki metric using 1000 steps can be calculated as follows.

    q = retract(TB, p, X, SasakiRetraction(1000))
    +println("Approximation of the exponential map: ", q)
    Approximation of the exponential map: ProductRepr{Tuple{Vector{Float64}, Vector{Float64}}}(([0.6759570857309881, 0.352414864043865, 0.6472138609849256], [-1.031826958326108, 0.6273324630574114, 0.7360618920075952]))
    • Muralidharan2012

      P. Muralidharan and P. T. Fletcher, “Sasaki Metrics for Analysis of Longitudinal Data on Manifolds,” Proc IEEE Comput Soc Conf Comput Vis Pattern Recognit, vol. 2012, pp. 1027–1034, Jun. 2012, doi: 10.1109/CVPR.2012.6247780.

    • Sasaki1958

      S. Sasaki, “On the differential geometry of tangent bundles of Riemannian manifolds,” Tohoku Math. J. (2), vol. 10, no. 3, pp. 338–354, 1958, doi: 10.2748/tmj/1178244668.

    diff --git a/previews/PR644/misc/about.html b/previews/PR644/misc/about.html new file mode 100644 index 0000000000..be3f578e1a --- /dev/null +++ b/previews/PR644/misc/about.html @@ -0,0 +1,2 @@ + +About · Manifolds.jl
    diff --git a/previews/PR644/misc/contributing.html b/previews/PR644/misc/contributing.html new file mode 100644 index 0000000000..7ee5cdcf29 --- /dev/null +++ b/previews/PR644/misc/contributing.html @@ -0,0 +1,9 @@ + +Contributing · Manifolds.jl

    Contributing to Manifolds.jl

    First, thanks for taking the time to contribute. Any contribution is appreciated and welcome.

    The following is a set of guidelines to Manifolds.jl.

    Table of Contents

    I just have a question

    The developers can most easily be reached in the Julia Slack channel #manifolds. You can apply for the Julia Slack workspace here if you haven't joined yet. You can also ask your question on discourse.julialang.org.

    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.

    How can I contribute?

    Add a missing method

    Not all methods from our interface ManifoldsBase.jl have been implemented for every manifold. If you notice a method missing and can contribute an implementation, please do so! Even providing a single new method is a good contribution.

    Provide a new manifold

    A main contribution you can provide is another manifold that is not yet included in the package. A manifold is a concrete type of AbstractManifold from ManifoldsBase.jl. This package also provides the main set of functions a manifold can/should implement. Don't worry if you can only implement some of the functions. If the application you have in mind only requires a subset of these functions, implement those. The ManifoldsBase.jl interface provides concrete error messages for the remaining unimplemented functions.

    One important detail is that the interface usually provides an in-place as well as a non-mutating variant See for example exp! and exp. The non-mutating one (e.g. exp) always falls back to use the in-place one, so in most cases it should suffice to implement the in-place one (e.g. exp!).

    Note that since the first argument is always the AbstractManifold, the mutated argument is always the second one in the signature. In the example we have exp(M, p, X, t) for the exponential map and exp!(M, q, p, X, t) for the in-place one, which stores the result in q.

    On the other hand, the user will most likely look for the documentation of the non-mutating version, so we recommend adding the docstring for the non-mutating one, where all different signatures should be collected in one string when reasonable. This can best be achieved by adding a docstring to the method with a general signature with the first argument being your manifold:

    struct MyManifold <: AbstractManifold end
    +
    +@doc raw"""
    +    exp(M::MyManifold, p, X)
    +
    +Describe the function.
    +"""
    +exp(::MyManifold, ::Any...)

    Code style

    We try to follow the documentation guidelines from the Julia documentation as well as Blue Style. We run JuliaFormatter.jl on the repo in the way set in the .JuliaFormatter.toml file, which enforces a number of conventions consistent with the Blue Style.

    We also follow a few internal conventions:

    • It is preferred that the AbstractManifold's struct contain a reference to the general theory.
    • Any implemented function should be accompanied by its mathematical formulae if a closed form exists.
    • Within the source code of one manifold, the type of the manifold should be the first element of the file, and an alphabetical order of the functions is preferable.
    • The above implies that the in-place variant of a function follows the non-mutating variant.
    • There should be no dangling = signs.
    • Always add a newline between things of different types (struct/method/const).
    • Always add a newline between methods for different functions (including in-place/nonmutating variants).
    • Prefer to have no newline between methods for the same function; when reasonable, merge the docstrings.
    • All import/using/include should be in the main module file.
    diff --git a/previews/PR644/misc/internals.html b/previews/PR644/misc/internals.html new file mode 100644 index 0000000000..28820c4ed2 --- /dev/null +++ b/previews/PR644/misc/internals.html @@ -0,0 +1,8 @@ + +Internals · Manifolds.jl

    Internal documentation

    This page documents the internal types and methods of Manifolds.jl's that might be of use for writing your own manifold.

    Functions

    Manifolds.eigen_safeFunction
    eigen_safe(x)

    Compute the eigendecomposition of x. If x is a StaticMatrix, it is converted to a Matrix before the decomposition.

    source
    Manifolds.isnormalFunction
    isnormal(x; kwargs...) -> Bool

    Check if the matrix or number x is normal, that is, if it commutes with its adjoint:

    \[x x^\mathrm{H} = x^\mathrm{H} x.\]

    By default, this is an equality check. Provide kwargs for isapprox to perform an approximate check.

    source
    Manifolds.log_safeFunction
    log_safe(x)

    Compute the matrix logarithm of x. If x is a StaticMatrix, it is converted to a Matrix before computing the log.

    source
    Manifolds.log_safe!Function
    log_safe!(y, x)

    Compute the matrix logarithm of x. If the eltype of y is real, then the imaginary part of x is ignored, and a DomainError is raised if real(x) has no real logarithm.

    source
    Manifolds.mul!_safeFunction
    mul!_safe(Y, A, B) -> Y

    Call mul! safely, that is, A and/or B are permitted to alias with Y.

    source
    Manifolds.nzsignFunction
    nzsign(z[, absz])

    Compute a modified sign(z) that is always nonzero, i.e. where

    \[\operatorname(nzsign)(z) = \begin{cases} + 1 & \text{if } z = 0\\ + \frac{z}{|z|} & \text{otherwise} +\end{cases}\]

    source
    Manifolds.realifyFunction
    realify(X::AbstractMatrix{T𝔽}, 𝔽::AbstractNumbers) -> Y::AbstractMatrix{<:Real}

    Given a matrix $X ∈ 𝔽^{n × n}$, compute $Y ∈ ℝ^{m × m}$, where $m = n \operatorname{dim}_𝔽$, and $\operatorname{dim}_𝔽$ is the real_dimension of the number field $𝔽$, using the map $ϕ \colon X ↦ Y$, that preserves the matrix product, so that for all $C,D ∈ 𝔽^{n × n}$,

    \[ϕ(C) ϕ(D) = ϕ(CD).\]

    See realify! for an in-place version, and unrealify! to compute the inverse of $ϕ$.

    source
    Manifolds.realify!Function
    realify!(Y::AbstractMatrix{<:Real}, X::AbstractMatrix{T𝔽}, 𝔽::AbstractNumbers)

    In-place version of realify.

    source
    realify!(Y::AbstractMatrix{<:Real}, X::AbstractMatrix{<:Complex}, ::typeof(ℂ))

    Given a complex matrix $X = A + iB ∈ ℂ^{n × n}$, compute its realified matrix $Y ∈ ℝ^{2n × 2n}$, written where

    \[Y = \begin{pmatrix}A & -B \\ B & A \end{pmatrix}.\]

    source
    Manifolds.select_from_tupleFunction
    select_from_tuple(t::NTuple{N, Any}, positions::Val{P})

    Selects elements of tuple t at positions specified by the second argument. For example select_from_tuple(("a", "b", "c"), Val((3, 1, 1))) returns ("c", "a", "a").

    source
    Manifolds.unrealify!Function
    unrealify!(X::AbstractMatrix{T𝔽}, Y::AbstractMatrix{<:Real}, 𝔽::AbstractNumbers[, n])

    Given a real matrix $Y ∈ ℝ^{m × m}$, where $m = n \operatorname{dim}_𝔽$, and $\operatorname{dim}_𝔽$ is the real_dimension of the number field $𝔽$, compute in-place its equivalent matrix $X ∈ 𝔽^{n × n}$. Note that this function does not check that $Y$ has a valid structure to be un-realified.

    See realify! for the inverse of this function.

    source
    Manifolds.usincFunction
    usinc(θ::Real)

    Unnormalized version of sinc function, i.e. $\operatorname{usinc}(θ) = \frac{\sin(θ)}{θ}$. This is equivalent to sinc(θ/π).

    source
    Manifolds.usinc_from_cosFunction
    usinc_from_cos(x::Real)

    Unnormalized version of sinc function, i.e. $\operatorname{usinc}(θ) = \frac{\sin(θ)}{θ}$, computed from $x = cos(θ)$.

    source
    Manifolds.vec2skew!Function
    vec2skew!(X, v, k)

    create a skew symmetric matrix inplace in X of size $k\times k$ from a vector v, for example for v=[1,2,3] and k=3 this yields

    [  0  1  2;
    +  -1  0  3;
    +  -2 -3  0
    +]
    source
    Manifolds.ziptuplesFunction
    ziptuples(a, b[, c[, d[, e]]])

    Zips tuples a, b, and remaining in a fast, type-stable way. If they have different lengths, the result is trimmed to the length of the shorter tuple.

    source
    diff --git a/previews/PR644/misc/notation.html b/previews/PR644/misc/notation.html new file mode 100644 index 0000000000..7e55b42ad0 --- /dev/null +++ b/previews/PR644/misc/notation.html @@ -0,0 +1,2 @@ + +Notation · Manifolds.jl

    Notation overview

    Since manifolds include a reasonable amount of elements and functions, the following list tries to keep an overview of used notation throughout Manifolds.jl. The order is alphabetical by name. They might be used in a plain form within the code or when referring to that code. This is for example the case with the calligraphic symbols.

    Within the documented functions, the utf8 symbols are used whenever possible, as long as that renders correctly in $\TeX$ within this documentation.

    SymbolDescriptionAlso usedComment
    $\tau_p$action map by group element $p$$\mathrm{L}_p$, $\mathrm{R}_p$either left or right
    $\operatorname{Ad}_p(X)$adjoint action of element $p$ of a Lie group on the element $X$ of the corresponding Lie algebra
    $\times$Cartesian product of two manifoldssee ProductManifold
    $^{\wedge}$(n-ary) Cartesian power of a manifoldsee PowerManifold
    $\cdot^\mathrm{H}$conjugate/Hermitian transpose
    $a$coordinates of a point in a chartsee get_parameters
    $\frac{\mathrm{D}}{\mathrm{d}t}$covariant derivative of a vector field $X(t)$
    $T^*_p \mathcal M$the cotangent space at $p$
    $ξ$a cotangent vector from $T^*_p \mathcal M$$ξ_1, ξ_2,… ,η,\zeta$sometimes written with base point $ξ_p$.
    $\mathrm{d}\phi_p(q)$Differential of a map $\phi: \mathcal M \to \mathcal N$ with respect to $p$ at a point $q$. For functions of multiple variables, for example $\phi(p, p_1)$ where $p \in \mathcal M$ and $p_1 \in \mathcal M_1$, variable $p$ is explicitly stated to specify with respect to which argument the differential is calculated.$\mathrm{d}\phi_q$, $(\mathrm{d}\phi)_q$, $(\phi_*)_q$, $D_p\phi(q)$pushes tangent vectors $X \in T_q \mathcal M$ forward to $\mathrm{d}\phi_p(q)[X] \in T_{\phi(q)} \mathcal N$
    $n$dimension (of a manifold)$n_1,n_2,\ldots,m, \dim(\mathcal M)$for the real dimension sometimes also $\dim_{\mathbb R}(\mathcal M)$
    $d(\cdot,\cdot)$(Riemannian) distance$d_{\mathcal M}(\cdot,\cdot)$
    $\exp_p X$exponential map at $p \in \mathcal M$ of a vector $X \in T_p \mathcal M$$\exp_p(X)$
    $F$a fibersee VectorBundleFibers
    $\mathbb F$a field, usually $\mathbb F \in \{\mathbb R,\mathbb C, \mathbb H\}$, i.e. the real, complex, and quaternion numbers, respectively.field a manifold or a basis is based on
    $\gamma$a geodesic$\gamma_{p;q}$, $\gamma_{p,X}$connecting two points $p,q$ or starting in $p$ with velocity $X$.
    $\operatorname{grad} f(p)$(Riemannian) gradient of function $f \colon \mathcal{M} \to \mathbb{R}$ at $p \in \mathcal{M}$
    $\nabla f(p)$(Euclidean) gradient of function $f \colon \mathcal{M} \to \mathbb{R}$ at $p \in \mathcal{M}$ but thought of as evaluated in the embeddingG
    $\circ$a group operation
    $\cdot^\mathrm{H}$Hermitian or conjugate transposed for both complex or quaternion matrices
    $\operatorname{Hess} f(p)$(Riemannian) Hessian of function $f \colon T_p\mathcal{M} \to T_p\mathcal M$ (i.e. the 1-1-tensor form) at $p \in \mathcal{M}$
    $\nabla^2 f(p)$(Euclidean) Hessian of function $f$ in the embeddingH

    | $e$ | identity element of a group | | | $I_k$ | identity matrix of size $k\times k$ | | | $k$ | indices | $i,j$ | | | $\langle\cdot,\cdot\rangle$ | inner product (in $T_p \mathcal M$) | $\langle\cdot,\cdot\rangle_p, g_p(\cdot,\cdot)$ | | $\operatorname{retr}^{-1}_pq$| an inverse retraction | | | $\mathfrak g$ | a Lie algebra | | | $\mathcal{G}$ | a (Lie) group | | | $\log_p q$ | logarithmic map at $p \in \mathcal M$ of a point $q \in \mathcal M$ | $\log_p(q)$ | | | $\mathcal M$ | a manifold | $\mathcal M_1, \mathcal M_2,\ldots,\mathcal N$ | | | $N_p \mathcal M$ | the normal space of the tangent space $T_p \mathcal M$ in some embedding $\mathcal E$ that should be clear from context | | $V$ | a normal vector from $N_p \mathcal M$$W$ | | | $\operatorname{Exp}$ | the matrix exponential | | | $\operatorname{Log}$ | the matrix logarithm | | | $\mathcal P_{q\gets p}X$ | parallel transport | | of the vector $X$ from $T_p\mathcal M$ to $T_q\mathcal M$ | $\mathcal P_{p,Y}X$ | parallel transport in direction $Y$ | | of the vector $X$ from $T_p\mathcal M$ to $T_q\mathcal M$, $q = \exp_pY$ | $\mathcal P_{t_1\gets t_0}^cX$ | parallel transport along the curve $c$| $\mathcal P^cX=\mathcal P_{1\gets 0}^cX$ | of the vector $X$ from $p=c(0)$ to $c(1)$ | $p$ | a point on $\mathcal M$ | $p_1, p_2, \ldots,q$ | for 3 points one might use $x,y,z$ | | $\operatorname{retr}_pX$| a retraction | | | $ξ$ | a set of tangent vectors | $\{X_1,\ldots,X_n\}$ | | | $T_p \mathcal M$ | the tangent space at $p$ | | | | $X$ | a tangent vector from $T_p \mathcal M$ | $X_1,X_2,\ldots,Y,Z$ | sometimes written with base point $X_p$ | | $\operatorname{tr}$ | trace (of a matrix) | | | $\cdot^\mathrm{T}$ | transposed | | | $e_i \in \mathbb R^n$ | the $i$th unit vector | $e_i^n$ | the space dimension ($n$) is omited, when clear from context | $B$ | a vector bundle | | | $\mathcal T_{q\gets p}X$ | vector transport | | of the vector $X$ from $T_p\mathcal M$ to $T_q\mathcal M$ | $\mathcal T_{p,Y}X$ | vector transport in direction $Y$ | | of the vector $X$ from $T_p\mathcal M$ to $T_q\mathcal M$, where $q$ is deretmined by $Y$, for example using the exponential map or some retraction. | | $\mathcal W$ | the Weingarten map $\mathcal W: T_p\mathcal M × N_p\mathcal M → T_p\mathcal M$$\mathcal W_p$ | the second notation to emphasize the dependency of the point $p\in\mathcal M$ | | $0_k$ | the $k\times k$ zero matrix. | |

    diff --git a/previews/PR644/misc/references.html b/previews/PR644/misc/references.html new file mode 100644 index 0000000000..028bc96714 --- /dev/null +++ b/previews/PR644/misc/references.html @@ -0,0 +1,12 @@ + +References · Manifolds.jl

    Literature

    We are slowly moving to using DocumenterCitatiosn.jl. The goal is to have all references used / mentioned in the documentation of Manifolds.jl also listed here. If you notice a reference still defined in a footnote, please change it into a BibTeX reference and open a PR

    Usually you will find a small reference section at the end of every documentation page that contains references for just that page.

    [AMT13]
    +
    + +
    [Ngu23]
    +
    +
    D. Nguyen. Operator-Valued Formulas for Riemannian Gradient and Hessian and Families of Tractable Metrics in Riemannian Optimization. Journal of Optimization Theory and Applications 198, 135–164 (2023).
    +
    [Van13]
    +
    +
    B. Vandereycken. Low-rank matrix completion by Riemannian optimization. SIAM Journal on Optimization 23, 1214–1236 (2013-01).
    +
    +
    diff --git a/previews/PR644/references.bib b/previews/PR644/references.bib new file mode 100644 index 0000000000..dc3f8b43ac --- /dev/null +++ b/previews/PR644/references.bib @@ -0,0 +1,38 @@ +@incollection{AbsilMahonyTrumpf:2013, + AUTHOR = {P. -A. Absil and Robert Mahony and Jochen Trumpf}, + YEAR = {2013}, + DOI = {10.1007/978-3-642-40020-9_39}, + EDITOR = {Nielsen, Frank + and Barbaresco, Fr{\'e}d{\'e}ric}, + ISBN = {978-3-642-40020-9}, + PUBLISHER = {Springer Berlin Heidelberg}, + PAGES = {361--368}, + TITLE = {An Extrinsic Look at the Riemannian Hessian}, + BOOKTITLE = {Geometric Science of Information}, +} +@article{Nguyen:2023, + DOI = {10.1007/s10957-023-02242-z}, + EPRINT = {2009.10159}, + EPRINTTYPE = {arXiv}, + YEAR = {2023}, + MONTH = jun, + PUBLISHER = {Springer Science and Business Media {LLC}}, + VOLUME = {198}, + NUMBER = {1}, + PAGES = {135--164}, + AUTHOR = {Du Nguyen}, + TITLE = {Operator-Valued Formulas for Riemannian Gradient and Hessian and Families of Tractable Metrics in Riemannian Optimization}, + JOURNAL = {Journal of Optimization Theory and Applications} +} + +@article{Vandereycken:2013, + AUTHOR = {Vandereycken, Bart}, + PUBLISHER = {Society for Industrial \& Applied Mathematics (SIAM)}, + YEAR = {2013-01}, + DOI = {10.1137/110845768}, + JOURNAL = {SIAM Journal on Optimization}, + NUMBER = {2}, + PAGES = {1214--1236}, + TITLE = {Low-rank matrix completion by Riemannian optimization}, + VOLUME = {23} +} \ No newline at end of file diff --git a/previews/PR644/search.html b/previews/PR644/search.html new file mode 100644 index 0000000000..88ab194d41 --- /dev/null +++ b/previews/PR644/search.html @@ -0,0 +1,2 @@ + +Search · Manifolds.jl diff --git a/previews/PR644/search_index.js b/previews/PR644/search_index.js new file mode 100644 index 0000000000..1739b484d3 --- /dev/null +++ b/previews/PR644/search_index.js @@ -0,0 +1,3 @@ +var documenterSearchIndex = {"docs": +[{"location":"tutorials/hand-gestures.html#Hand-gesture-analysis","page":"perform Hand gesture analysis","title":"Hand gesture analysis","text":"","category":"section"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"In this tutorial we will learn how to use Kendall’s shape space to analyze hand gesture data.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"Let’s start by loading libraries required for our work.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"using Manifolds, CSV, DataFrames, Plots, MultivariateStats","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"Our first function loads dataset of hand gestures, described here.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"function load_hands()\n hands_url = \"https://raw.githubusercontent.com/geomstats/geomstats/master/geomstats/datasets/data/hands/hands.txt\"\n hand_labels_url = \"https://raw.githubusercontent.com/geomstats/geomstats/master/geomstats/datasets/data/hands/labels.txt\"\n\n hands = Matrix(CSV.read(download(hands_url), DataFrame, header=false))\n hands = reshape(hands, size(hands, 1), 3, 22)\n hand_labels = CSV.read(download(hand_labels_url), DataFrame, header=false).Column1\n return hands, hand_labels\nend","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"load_hands (generic function with 1 method)","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"The following code plots a sample gesture as a 3D scatter plot of points.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"hands, hand_labels = load_hands()\nscatter3d(hands[1, 1, :], hands[1, 2, :], hands[1, 3, :])","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"(Image: )","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"Each gesture is represented by 22 landmarks in ℝ³, so we use the appropriate Kendall’s shape space","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"Mshape = KendallsShapeSpace(3, 22)","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"KendallsShapeSpace{3, 22}()","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"Hands read from the dataset are projected to the shape space to remove translation and scaling variability. Rotational variability is then handled using the quotient structure of KendallsShapeSpace","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"hands_projected = [project(Mshape, hands[i, :, :]) for i in axes(hands, 1)]","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"In the next part let’s do tangent space PCA. This starts with computing a mean point and computing logithmic maps at mean to each point in the dataset.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"mean_hand = mean(Mshape, hands_projected)\nhand_logs = [log(Mshape, mean_hand, p) for p in hands_projected]","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"For a tangent PCA, we need coordinates in a basis. Some libraries skip this step because the representation of tangent vectors forms a linear subspace of an Euclidean space so PCA automatically detects which directions have no variance but this is a more generic way to solve this issue.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"B = get_basis(Mshape, mean_hand, ProjectedOrthonormalBasis(:svd))\nhand_log_coordinates = [get_coordinates(Mshape, mean_hand, X, B) for X in hand_logs]","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"This code prepares data for MultivariateStats – mean=0 is set because we’ve centered the data geometrically to mean_hand in the code above.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"red_coords = reduce(hcat, hand_log_coordinates)\nfp = fit(PCA, red_coords; mean=0)","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"PCA(indim = 59, outdim = 18, principalratio = 0.9900213563800988)\n\nPattern matrix (unstandardized loadings):\n─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10 PC11 PC12 PC13 PC14 PC15 PC16 PC17 PC18\n─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n1 -0.0290105 0.0208927 -0.01643 0.00190549 0.00901145 0.000643771 -0.00363047 -0.00217327 0.00312554 -0.00356053 0.00478045 0.00165704 0.00218866 0.0037857 0.000320345 -0.00145212 0.000948335 -0.00184176\n2 0.0172527 0.0165863 -0.0168821 -0.0183233 0.0121555 0.00833736 0.00187667 -0.000648234 0.00706323 0.00583622 -0.0044018 0.0012355 0.00118376 -0.00246016 0.00446684 -0.00498993 -0.0028049 -0.00259758\n3 0.0447499 -0.00487667 -0.00247071 -0.00148697 -0.00200127 -0.00795338 0.00905314 0.00687454 0.0114088 -0.000998774 0.00459101 0.00645948 0.00073043 0.00591995 -0.00520394 0.00129428 -0.000463386 -0.00207384\n4 -0.00881422 -0.0341713 0.00749624 0.00795209 -0.00260601 0.00356386 0.00204456 -0.00905276 0.00826807 0.00012095 0.000768538 -0.000460691 0.00411022 -0.00216294 -0.000650028 0.00251224 0.00149784 -0.00181133\n5 0.0325794 -0.023796 0.000642765 0.00509869 0.00759807 0.00483368 -0.00252952 0.00656179 0.00322274 -0.000313146 0.00143493 -0.000676479 0.000146354 -0.00266203 0.00353957 0.0021415 -0.00457168 0.00282965\n6 -0.00617763 6.91201e-5 0.00765638 0.00183758 0.00157382 0.00184956 -0.00797935 0.000700457 0.0087012 0.00992564 0.00263642 0.00294279 -0.0092 0.00133877 0.00145735 -0.0014816 0.00235123 -0.00039541\n7 -0.0183122 0.0131045 0.0125222 -0.00638021 -0.006709 -0.00013628 0.00858169 -0.00159031 -0.00585433 -0.0032447 0.00880912 -0.00149308 0.000724205 0.00469925 0.00432005 0.0012382 -0.00251638 6.89878e-5\n8 0.0392874 -0.0152552 -0.00404674 -0.0183856 -0.0054739 0.000203488 0.00687526 0.00989129 -0.00570517 0.00234255 -0.00221344 -0.00514796 0.000658069 0.00220789 7.02581e-5 0.000380265 0.0007751 0.00234631\n9 -0.00525049 -0.0181427 -0.00473895 -0.0128126 0.000405834 -0.00936332 -0.000781745 0.011196 -0.00498502 0.00199077 0.00355555 -0.00334398 0.00763648 0.000311697 -0.000844841 -0.00526438 -0.00201977 0.00188678\n10 0.0771681 0.0248294 -0.00375548 -0.0138712 -0.0126479 -0.00543573 -0.0136609 -0.00408721 -0.00445726 -0.00407287 0.00696664 -0.00158737 -0.00201909 -0.00211184 0.000907502 0.00235338 -0.00259266 0.00114594\n11 -0.0013693 0.0125762 -0.00145726 0.0119688 -0.00362363 0.00954477 0.000894749 0.00311196 0.000186917 0.00923739 0.0036434 0.00484736 0.000288834 -0.00269382 -0.00194147 -0.000702207 -0.00245996 -0.000458531\n12 0.00497523 0.0154863 0.0409999 -0.00832204 -0.00216091 0.0149159 0.011796 0.0121391 -0.00292353 -0.00532504 -0.00427894 0.000550893 -0.00408841 0.000520159 -0.00344571 0.000625647 0.000271049 -0.00165807\n13 -0.0541357 -0.0291498 0.0140122 0.00292223 0.00128359 0.00301256 -0.00581861 -0.00397323 0.000588485 0.0025976 -0.00442985 -0.00603182 0.00326815 0.00326603 0.000384467 -0.00134404 -0.00160027 -0.00261985\n14 -0.0493144 0.0120223 -0.0163111 0.0103746 -0.0126512 -0.011453 0.00488614 -0.00586095 0.0027455 -0.00434342 0.00203457 -0.000941868 -0.00426973 -0.00447805 -0.00239537 -0.00320013 0.000877498 0.000673572\n15 -0.00654048 0.00225524 -0.028207 0.00306531 0.00321072 -0.000599231 0.00320363 -0.0059508 -0.00586048 0.0031903 -0.00613799 0.00471076 -0.00101853 0.00294667 -0.000548534 0.00402922 0.000405583 2.6607e-5\n16 0.0300802 0.0075843 0.00364836 -0.00205771 -0.0148831 0.0211394 -0.000508637 0.0036868 0.0109845 -0.00574404 -0.00920237 0.0007153 0.000544823 -0.00209521 0.000474541 -0.00052208 0.00180017 0.00202094\n17 -0.0110775 0.0373997 -0.00242133 0.00827109 -0.000567586 -0.0141686 -0.000939656 0.00843637 -0.00590348 0.00649057 0.00259619 -0.000897277 0.00443368 -0.0047585 -0.00160148 0.000335684 0.00152076 -0.00300398\n18 0.0391783 0.0248007 0.0308429 0.00118303 0.00981074 0.00261316 -0.00100239 -0.0062546 -0.00491006 -0.00506867 0.00441608 -0.00367774 -0.00481009 -0.000493728 -0.00329753 0.000419403 0.000711267 0.000406243\n19 0.0138738 -0.0443171 -0.00598066 0.00585226 0.00596223 0.00680714 -0.0079294 -0.00269779 -0.00426069 -0.00718608 0.00761514 0.00336824 -0.00295577 -0.00264683 0.00316699 -0.000418376 -0.00240164 -0.00413196\n20 0.0173164 -0.0215417 0.000863689 -0.0205664 0.00121695 0.00307745 0.00191828 -0.00849558 -0.00147893 0.00180504 0.00814434 0.00372913 0.00188294 -0.00170647 -0.00451407 -0.00100769 -0.000238128 -0.000257117\n21 0.00338984 0.00237562 0.0237069 -0.0129184 0.00148197 -0.000855367 0.00148785 0.00142366 0.00320966 0.00781237 0.000800995 -0.000516126 0.00440079 -0.0079143 0.00215576 0.00201592 -0.000335618 0.00337192\n22 -0.00746071 -0.0116344 0.0021644 0.0152239 0.00723169 0.0120803 -0.000485058 0.00653526 0.0026666 0.00152026 0.0135607 -0.00247612 0.00348543 3.45051e-6 0.0017885 0.000179426 -0.000524643 -0.000805656\n23 0.0478442 -0.0227649 -0.0113793 -0.00367693 0.0106966 0.00169994 0.0135303 -0.00344929 0.000128235 0.00063693 -0.00225447 0.000880574 -0.00665083 -0.0050547 -0.00295617 -0.00422433 0.00166798 -0.00189465\n24 -0.0142467 0.0166931 0.00516018 0.00593988 -0.0210703 0.00438546 0.00643305 0.00174866 0.00505729 0.000463517 0.00763753 -0.00417294 -0.00156206 0.00540319 -0.00301265 -0.00408336 -0.00144362 -0.000137294\n25 0.00108012 0.0195339 0.011519 0.0110158 0.00193433 0.0107534 -0.00146174 0.000236797 0.00226925 -0.00744152 0.00199678 -0.00445237 0.00273993 -0.000207735 -0.00191042 0.00121896 0.00195283 -0.00274164\n26 0.0123466 0.0083253 0.00519553 -0.00196478 0.0137825 -0.00233978 -0.00771765 -0.00232805 -0.00279333 0.00340724 0.0012353 -0.00362154 -0.0013554 0.000632953 -2.37112e-5 0.00141247 -0.000568908 -0.000973567\n27 -0.00893091 0.00641791 0.0087648 0.00424429 -0.000824081 -0.00761539 -0.0152518 0.00995065 0.00317758 8.84094e-5 -0.00419563 -0.00124495 -0.00589762 -0.000929293 0.00477719 0.00377025 0.00267074 0.000761405\n28 0.0378644 -0.0125169 0.012799 0.0178141 0.00260966 -0.00752201 0.00299546 -0.00777486 0.00426756 0.00566038 0.00107451 -0.000215202 -0.00470252 0.00209217 -0.000578698 0.00150591 -0.00148331 0.00229085\n29 0.00205475 0.0304241 -0.0354979 0.00394855 -0.00350914 0.00725592 -0.00678139 0.000307436 -0.00315394 -0.00689183 0.000456785 0.00368637 0.00277269 -0.00277076 -0.00422942 0.00223455 0.0015448 -0.00234455\n30 0.0749975 -0.00999942 0.00367276 0.0100629 -0.00671752 -0.011357 0.00301586 0.000408736 0.00259563 0.000303288 -0.000111357 -0.00159763 0.00161827 -0.000545339 0.00377406 0.00268094 0.00406555 -0.00203144\n31 0.0209729 0.00213421 0.00669869 0.016557 0.00403684 -0.0178951 0.0107244 0.0111298 0.00610797 -0.00390215 -0.00353771 -0.00178467 0.00235713 0.000973802 0.000274041 0.00218045 -0.00215689 -0.00158819\n32 -0.0244084 -0.0371206 0.0192767 -0.000685794 0.0158289 -0.001451 -0.00509477 0.00577056 -0.00513049 -0.00950968 -0.00158958 0.000989458 -0.000699212 0.00122133 -0.000191417 0.000911926 0.00209233 -6.04374e-5\n33 0.00565764 -0.0172793 0.00401092 -0.00793658 0.00504771 -0.00220381 0.00224319 0.0071918 -0.0124133 0.00175162 0.00348751 0.00633021 -0.00260535 0.00565187 -0.00186287 -0.000238933 0.000666333 0.00250607\n34 0.00185581 -0.0166196 -0.0197269 0.00699341 0.00647246 -0.00303065 -0.000117067 0.00490106 0.00667588 -0.00855122 0.00302462 0.00173228 0.00553969 -0.00468124 0.00121978 0.0005079 0.000420239 0.00253235\n35 0.0199811 0.0267965 0.0129649 0.00264194 0.000195136 -0.00349662 0.00294599 -0.00187851 0.00177767 -0.0053757 -0.00330811 -0.00295473 0.00208629 -6.97773e-5 -0.00153972 -0.000773065 -0.00157575 -0.000197057\n36 0.0175704 0.0191343 -0.0116551 0.00882917 -0.0104714 0.0103777 0.00118041 -0.000696881 0.00192364 0.00744034 0.00497109 -0.00164206 0.00162482 -0.00139405 0.00167977 0.000693101 -0.00132024 0.00297973\n37 -0.00462744 -0.013417 0.00735863 0.0138801 -0.0058212 -0.00238145 -0.00576575 0.00188503 0.00101854 0.0035232 0.0016009 0.00106877 -0.00593854 -0.0015165 -0.00563642 -0.000339869 0.00216456 0.002153\n38 -0.0218719 0.00531191 0.00305154 0.0241393 0.0234907 0.00316473 0.0020773 -0.00469298 -0.00845531 0.00456344 -0.000534739 0.00131404 -0.00166945 -0.000113877 -0.00168502 0.00333815 -0.00307554 0.00114466\n39 -0.00848638 0.0208304 0.00949937 0.0226454 0.0052942 -0.000851704 0.00632965 2.91971e-5 0.00329463 6.28469e-5 0.00660731 0.00235582 -0.00130279 -0.00141865 0.00530658 -0.00248136 0.000456183 0.00125713\n40 -0.0887529 -0.0108083 -0.00348235 -0.0197061 -0.00851786 -0.00490488 0.00159713 0.00351037 0.0148414 -0.00401737 0.00779929 0.00245023 -0.00253298 -0.000226246 -0.000206421 0.00510786 0.00148421 0.00186788\n41 0.00130006 0.00193007 -0.00297337 0.0070658 0.00888416 0.00665004 -0.013746 0.000961125 0.00363303 0.00316905 0.000576911 -0.00659932 0.00136165 0.0013939 -0.00380487 -0.00444913 0.00366095 0.00144111\n42 -0.0207553 0.0174796 -0.00445662 -0.0117613 0.0273261 -0.00065484 0.00296882 0.00593266 0.00162045 -0.00318673 0.0066341 -0.0053347 0.000440878 -0.000644585 -0.00244859 0.00184264 0.00345959 -0.000426283\n43 0.0413948 0.00307635 -0.00665062 -0.00226029 0.017443 -0.00424136 0.00950125 -0.00429922 0.00148225 -0.000166312 0.00294757 -0.00069645 0.000696539 0.000366659 0.00282844 -0.00230084 0.0053369 0.00238474\n44 0.00449575 0.0201137 0.03094 -0.0058886 -0.00146264 0.0101428 -0.00516029 0.00543426 -0.00941967 0.000969442 -0.000431407 0.0064443 0.00115545 -0.00181689 0.00364823 -0.000426309 0.000849352 -0.00167685\n45 -0.0205292 -0.00157548 0.013357 -0.00792343 0.00744915 0.00216668 -0.00243796 0.00180573 0.01512 0.00713893 -0.00283512 0.00430074 0.000788886 0.0049491 0.0029426 -0.00139686 0.00105337 -0.00239361\n46 -0.0215505 -0.0112917 0.013841 0.0111599 -0.0105729 0.00953035 0.0113897 -0.00673481 -0.0100248 0.00344613 0.00262901 0.0047878 0.00566946 -6.60172e-5 0.00414744 0.00111141 0.00450865 -0.00145945\n47 -0.0171993 0.0180146 0.00810394 -0.00791244 0.0061704 0.00923438 0.000727892 -0.0152243 0.00748635 -0.00599911 -0.00175649 0.00265434 -8.49398e-5 0.00305952 -0.00198115 0.00274446 -0.0028668 0.00323797\n48 0.0587549 0.0116068 -0.00915491 0.00448539 0.0104133 0.00457871 0.00126112 0.00499596 0.00964989 -0.00404286 0.000207311 0.003728 -0.000433589 -0.000303131 0.00412588 0.000467283 -0.000916261 -0.00103631\n49 -0.00166257 0.0250389 0.00797097 0.000683472 -0.000895449 -0.0133557 -0.00573426 0.000680622 0.00069621 0.00638431 -0.00245348 0.00498899 0.00507946 0.0057863 -0.00069408 0.0014596 0.000877213 -0.000692365\n50 -0.0355097 0.0143079 -0.00981991 0.00946907 -0.00422843 -0.00254884 0.00491884 0.00651818 -0.00548423 -0.0071809 9.81603e-5 0.00390103 -0.00712449 0.0013088 0.00694234 -0.00320143 0.000147409 0.00234526\n51 0.0456319 -0.0188437 0.00614929 0.01619 -0.0156405 0.00353768 -0.00911906 0.000874972 -0.00121217 -0.00403428 -0.000414905 0.00681573 0.00859836 0.00350106 -0.00263157 -0.00122084 0.00183226 0.00257702\n52 0.00746721 0.0133773 -0.0340613 -0.0139034 0.00655522 0.00929538 0.000770716 -0.000483502 -0.00600155 0.00201797 0.0011251 0.00179484 -2.38878e-5 0.00486216 0.00282832 0.00255029 0.00367921 0.00129338\n53 0.00823236 -0.00600734 -0.0200329 0.00202998 -0.0011313 0.0105144 0.00321895 0.00687414 0.000987698 0.00431901 0.000760463 -0.00635147 -0.00119575 0.00474285 4.40898e-5 0.00580837 -0.00332298 -0.00201341\n54 -0.043754 -0.00171994 -0.00111157 0.00123094 -0.00428039 0.0027972 0.00934907 -0.00596239 -0.00226019 0.001642 -0.00513074 -0.00589632 0.00344517 -0.0042949 0.0025378 0.00306413 0.00186166 0.00125999\n55 0.0430398 -0.000525733 0.0081576 -0.00839141 -0.00347855 -0.00933299 0.00251806 -0.0126012 0.002086 0.00272973 0.00204035 -0.000224255 -0.000607192 -0.000454776 -0.000157181 0.00250081 0.00145433 -0.00163108\n56 0.0305092 -0.00319322 -0.010629 0.0139009 0.00442941 0.00855659 0.00087527 -0.00330425 0.000399393 -0.000737765 -0.00150343 -0.00754475 0.000704529 0.00851631 0.00185909 -0.00126123 0.00232031 0.00223781\n57 0.00321453 -0.0190408 -0.0279848 0.00741802 -0.0157076 0.00592558 0.0020086 0.00843992 -0.00442316 0.00325392 -0.002545 -0.00268433 -0.00623548 -0.00142257 -0.00199612 0.0016597 0.000405685 -0.00229266\n58 0.0156328 -0.0074322 0.0066988 -0.0114629 -0.0168092 0.00328227 -0.00226964 -0.00110748 0.000440872 0.00227572 0.00827165 -0.00488151 -0.00316671 -2.58046e-5 0.00360288 0.00115025 0.00316887 -0.00204823\n59 -0.00151264 0.00426245 0.00115303 0.00338067 0.00957651 0.0116283 0.00361068 0.0102905 0.00246382 0.00700902 0.00252521 0.00257786 0.000578243 -0.00384276 -0.00597088 0.00283491 0.00171675 0.00226962\n─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n\nImportance of components:\n──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10 PC11 PC12 PC13 PC14 PC15 PC16 PC17 PC18\n──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\nSS Loadings (Eigenvalues) 0.0559745 0.0192925 0.0128414 0.00672244 0.0055061 0.00364815 0.00229962 0.00223028 0.00206984 0.00135745 0.00119 0.000805397 0.000775895 0.000619591 0.00052072 0.000351929 0.000282879 0.000224033\nVariance explained 0.474806 0.16365 0.108928 0.0570235 0.0467058 0.0309456 0.0195066 0.0189185 0.0175575 0.0115146 0.0100942 0.00683182 0.00658157 0.00525572 0.00441704 0.00298526 0.00239954 0.00190038\nCumulative variance 0.474806 0.638456 0.747384 0.804407 0.851113 0.882059 0.901565 0.920484 0.938041 0.949556 0.95965 0.966482 0.973063 0.978319 0.982736 0.985721 0.988121 0.990021\nProportion explained 0.479592 0.165299 0.110026 0.0575982 0.0471765 0.0312575 0.0197032 0.0191092 0.0177345 0.0116307 0.010196 0.00690068 0.00664791 0.00530869 0.00446156 0.00301535 0.00242373 0.00191953\nCumulative proportion 0.479592 0.644891 0.754917 0.812515 0.859692 0.890949 0.910652 0.929761 0.947496 0.959127 0.969323 0.976223 0.982871 0.98818 0.992641 0.995657 0.99808 1.0\n──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"Now let’s show explained variance of each principal component.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"plot(principalvars(fp), title=\"explained variance\", label=\"Tangent PCA\")","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"(Image: )","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"The next plot shows how projections on the first two pricipal components look like.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"fig = plot(; title=\"coordinates per gesture of the first two principal components\")\nfor label_num in [0, 1]\n mask = hand_labels .== label_num\n cur_hand_logs = red_coords[:, mask]\n cur_t = MultivariateStats.transform(fp, cur_hand_logs)\n scatter!(fig, cur_t[1, :], cur_t[2, :], label=\"gesture \" * string(label_num))\nend\nxlabel!(fig, \"principal component 1\")\nylabel!(fig, \"principal component 2\")\nfig","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"(Image: )","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"The following heatmap displays pairwise distances between gestures. We can use them for clustering, classification, etc.","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"hand_distances = [\n distance(Mshape, hands_projected[i], hands_projected[j]) for\n i in eachindex(hands_projected), j in eachindex(hands_projected)\n]\nheatmap(hand_distances, aspect_ratio=:equal)","category":"page"},{"location":"tutorials/hand-gestures.html","page":"perform Hand gesture analysis","title":"perform Hand gesture analysis","text":"(Image: )","category":"page"},{"location":"features/statistics.html#Statistics","page":"Statistics","title":"Statistics","text":"","category":"section"},{"location":"features/statistics.html","page":"Statistics","title":"Statistics","text":"Modules = [Manifolds,ManifoldsBase]\nPages = [\"statistics.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"features/statistics.html#Manifolds.AbstractEstimationMethod","page":"Statistics","title":"Manifolds.AbstractEstimationMethod","text":"AbstractEstimationMethod\n\nAbstract type for defining statistical estimation methods.\n\n\n\n\n\n","category":"type"},{"location":"features/statistics.html#Manifolds.CyclicProximalPointEstimation","page":"Statistics","title":"Manifolds.CyclicProximalPointEstimation","text":"CyclicProximalPointEstimation <: AbstractEstimationMethod\n\nMethod for estimation using the cyclic proximal point technique.\n\n\n\n\n\n","category":"type"},{"location":"features/statistics.html#Manifolds.ExtrinsicEstimation","page":"Statistics","title":"Manifolds.ExtrinsicEstimation","text":"ExtrinsicEstimation <: AbstractEstimationMethod\n\nMethod for estimation in the ambient space and projecting to the manifold.\n\nFor mean estimation, GeodesicInterpolation is used for mean estimation in the ambient space.\n\n\n\n\n\n","category":"type"},{"location":"features/statistics.html#Manifolds.GeodesicInterpolation","page":"Statistics","title":"Manifolds.GeodesicInterpolation","text":"GeodesicInterpolation <: AbstractEstimationMethod\n\nRepeated weighted geodesic interpolation method for estimating the Riemannian center of mass.\n\nThe algorithm proceeds with the following simple online update:\n\nbeginaligned\nμ_1 = x_1\nt_k = fracw_ksum_i=1^k w_i\nμ_k = γ_μ_k-1(x_k t_k)\nendaligned\n\nwhere x_k are points, w_k are weights, μ_k is the kth estimate of the mean, and γ_x(y t) is the point at time t along the shortest_geodesic between points xy mathcal M. The algorithm terminates when all x_k have been considered. In the Euclidean case, this exactly computes the weighted mean.\n\nThe algorithm has been shown to converge asymptotically with the sample size for the following manifolds equipped with their default metrics when all sampled points are in an open geodesic ball about the mean with corresponding radius (see GeodesicInterpolationWithinRadius):\n\nAll simply connected complete Riemannian manifolds with non-positive sectional curvature at radius [Cheng2016], in particular:\nEuclidean\nSymmetricPositiveDefinite [Ho2013]\nOther manifolds:\nSphere: fracπ2 [Salehian2015]\nGrassmann: fracπ4 [Chakraborty2015]\nStiefel/Rotations: fracπ2 sqrt 2 [Chakraborty2019]\n\nFor online variance computation, the algorithm additionally uses an analogous recursion to the weighted Welford algorithm [West1979].\n\n[Ho2013]: Ho J.; Cheng G.; Salehian H.; Vemuri B. C.; Recursive Karcher expectation estimators and geometric law of large numbers. Proceedings of the 16th International Conference on Artificial Intelligence and Statistics (2013), pp. 325–332. pdf.\n\n[Salehian2015]: Salehian H.; Chakraborty R.; Ofori E.; Vaillancourt D.; An efficient recursive estimator of the Fréchet mean on a hypersphere with applications to Medical Image Analysis. Mathematical Foundations of Computational Anatomy (2015). pdf.\n\n[Chakraborty2015]: Chakraborty R.; Vemuri B. C.; Recursive Fréchet Mean Computation on the Grassmannian and Its Applications to Computer Vision. Proceedings of the IEEE International Conference on Computer Vision (ICCV) (2015), pp. 4229-4237. doi: 10.1109/ICCV.2015.481, link.\n\n[Cheng2016]: Cheng G.; Ho J.; Salehian H.; Vemuri B. C.; Recursive Computation of the Fréchet Mean on Non-positively Curved Riemannian Manifolds with Applications. Riemannian Computing in Computer Vision. Springer, Cham (2016), pp. 21-43. doi: 10.1007/978-3-319-22957-7_2, pdf.\n\n[Chakraborty2019]: Chakraborty R.; Vemuri B. C.; Statistics on the (compact) Stiefel manifold: Theory and Applications. The Annals of Statistics (2019), 47(1), pp. 415-438. doi: 10.1214/18-AOS1692, arxiv: 1708.00045.\n\n[West1979]: West D. H. D.; Updating Mean and Variance Estimates: An Improved Method. Communications of the ACM (1979), 22(9), pp. 532–535. doi: 10.1145/359146.359153.\n\n\n\n\n\n","category":"type"},{"location":"features/statistics.html#Manifolds.GeodesicInterpolationWithinRadius","page":"Statistics","title":"Manifolds.GeodesicInterpolationWithinRadius","text":"GeodesicInterpolationWithinRadius{T} <: AbstractEstimationMethod\n\nEstimation of Riemannian center of mass using GeodesicInterpolation with fallback to GradientDescentEstimation if any points are outside of a geodesic ball of specified radius around the mean.\n\nConstructor\n\nGeodesicInterpolationWithinRadius(radius)\n\n\n\n\n\n","category":"type"},{"location":"features/statistics.html#Manifolds.GradientDescentEstimation","page":"Statistics","title":"Manifolds.GradientDescentEstimation","text":"GradientDescentEstimation <: AbstractEstimationMethod\n\nMethod for estimation using gradient descent.\n\n\n\n\n\n","category":"type"},{"location":"features/statistics.html#Manifolds.WeiszfeldEstimation","page":"Statistics","title":"Manifolds.WeiszfeldEstimation","text":"WeiszfeldEstimation <: AbstractEstimationMethod\n\nMethod for estimation using the Weiszfeld algorithm for the median\n\n\n\n\n\n","category":"type"},{"location":"features/statistics.html#Manifolds.default_estimation_method-Tuple{AbstractManifold, Any}","page":"Statistics","title":"Manifolds.default_estimation_method","text":"default_estimation_method(M::AbstractManifold, f)\n\nSpecify a default AbstractEstimationMethod for an AbstractManifold for a function f, e.g. the median or the mean.\n\nNote that his function is decorated, so it can inherit from the embedding, for example for the IsEmbeddedSubmanifold trait.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.cov-Tuple{AbstractManifold, AbstractVector}","page":"Statistics","title":"Statistics.cov","text":"Statistics.cov(\n M::AbstractManifold,\n x::AbstractVector;\n basis::AbstractBasis=DefaultOrthonormalBasis(),\n tangent_space_covariance_estimator::CovarianceEstimator=SimpleCovariance(;\n corrected=true,\n ),\n mean_estimation_method::AbstractEstimationMethod=GradientDescentEstimation(),\n inverse_retraction_method::AbstractInverseRetractionMethod=default_inverse_retraction_method(\n M, eltype(x),\n ),\n)\n\nEstimate the covariance matrix of a set of points x on manifold M. Since the covariance matrix on a manifold is a rank 2 tensor, the function returns its coefficients in basis induced by the given tangent space basis. See Section 5 of [Pennec2006] for details.\n\nThe mean is calculated using the specified mean_estimation_method using [mean](@ref Statistics.mean(::AbstractManifold, ::AbstractVector, ::AbstractEstimationMethod), and tangent vectors at this mean are calculated using the provided inverse_retraction_method. Finally, the covariance matrix in the tangent plane is estimated using the Euclidean space estimator tangent_space_covariance_estimator. The type CovarianceEstimator is defined in StatsBase.jl and examples of covariance estimation methods can be found in CovarianceEstimation.jl.\n\n[Pennec2006]: X. Pennec, “Intrinsic Statistics on Riemannian Manifolds: Basic Tools for Geometric Measurements,” J Math Imaging Vis, vol. 25, no. 1, p. 127, Jul. 2006, doi: 10.1007/s10851-006-6228-4.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.mean!-Tuple{AbstractManifold, Vararg{Any}}","page":"Statistics","title":"Statistics.mean!","text":"mean!(M::AbstractManifold, y, x::AbstractVector[, w::AbstractWeights]; kwargs...)\nmean!(\n M::AbstractManifold,\n y,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::AbstractEstimationMethod;\n kwargs...,\n)\n\nCompute the mean in-place in y.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.mean-Tuple{AbstractManifold, AbstractVector, AbstractVector, ExtrinsicEstimation}","page":"Statistics","title":"Statistics.mean","text":"mean(\n M::AbstractManifold,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::ExtrinsicEstimation;\n kwargs...,\n)\n\nEstimate the Riemannian center of mass of x using ExtrinsicEstimation, i.e. by computing the mean in the embedding and projecting the result back. You can specify an extrinsic_method to specify which mean estimation method to use in the embedding, which defaults to GeodesicInterpolation.\n\nSee mean for a description of the remaining kwargs.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.mean-Tuple{AbstractManifold, AbstractVector, AbstractVector, GeodesicInterpolationWithinRadius}","page":"Statistics","title":"Statistics.mean","text":"mean(\n M::AbstractManifold,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::GeodesicInterpolationWithinRadius;\n kwargs...,\n)\n\nEstimate the Riemannian center of mass of x using GeodesicInterpolationWithinRadius.\n\nSee mean for a description of kwargs.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.mean-Tuple{AbstractManifold, AbstractVector, AbstractVector, GeodesicInterpolation}","page":"Statistics","title":"Statistics.mean","text":"mean(\n M::AbstractManifold,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::GeodesicInterpolation;\n shuffle_rng=nothing,\n retraction::AbstractRetractionMethod = default_retraction_method(M, eltype(x)),\n inverse_retraction::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, eltype(x)),\n kwargs...,\n)\n\nEstimate the Riemannian center of mass of x in an online fashion using repeated weighted geodesic interpolation. See GeodesicInterpolation for details.\n\nIf shuffle_rng is provided, it is used to shuffle the order in which the points are considered for computing the mean.\n\nOptionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.mean-Tuple{AbstractManifold, Vararg{Any}}","page":"Statistics","title":"Statistics.mean","text":"mean(M::AbstractManifold, x::AbstractVector[, w::AbstractWeights]; kwargs...)\n\nCompute the (optionally weighted) Riemannian center of mass also known as Karcher mean of the vector x of points on the AbstractManifold M, defined as the point that satisfies the minimizer\n\nargmin_y mathcal M frac12 sum_i=1^n w_i sum_i=1^n w_imathrmd_mathcal M^2(yx_i)\n\nwhere mathrmd_mathcal M denotes the Riemannian distance.\n\nIn the general case, the GradientDescentEstimation is used to compute the mean. mean( M::AbstractManifold, x::AbstractVector, [w::AbstractWeights,] method::AbstractEstimationMethod=defaultestimationmethod(M); kwargs..., )\n\nCompute the mean using the specified method.\n\nmean(\n M::AbstractManifold,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::GradientDescentEstimation;\n p0=x[1],\n stop_iter=100,\n retraction::AbstractRetractionMethod = default_retraction_method(M),\n inverse_retraction::AbstractInverseRetractionMethod = default_retraction_method(M, eltype(x)),\n kwargs...,\n)\n\nCompute the mean using the gradient descent scheme GradientDescentEstimation.\n\nOptionally, provide p0, the starting point (by default set to the first data point). stop_iter denotes the maximal number of iterations to perform and the kwargs... are passed to isapprox to stop, when the minimal change between two iterates is small. For more stopping criteria check the Manopt.jl package and use a solver therefrom.\n\nOptionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction.\n\nThe Theory stems from[Karcher1977] and is also described in[PennecArsigny2013] as the exponential barycenter. The algorithm is further described in[Afsari2013].\n\n[Afsari2013]: Afsari, B; Tron, R.; Vidal, R.: On the Convergence of Gradient Descent for Finding the Riemannian Center of Mass, SIAM Journal on Control and Optimization (2013), 51(3), pp. 2230–2260, doi: 10.1137/12086282X, arxiv: 1201.0925\n\n[PennecArsigny2013]: Pennec X., Arsigny V.: Exponential Barycenters of the Canonical Cartan Connection and Invariant Means on Lie Groups. In: Nielsen F., Bhatia R. (eds) Matrix Information Geometry, (2013), pp. 123-166. doi: 10.1007/978-3-642-30232-9_7, hal: https://hal.inria.fr/hal-00699361/document\n\n[Karcher1977]: Karcher, H.: Riemannian center of mass and mollifier smoothing. Communications on Pure Applied Mathematics (1977), 30, pp. 509–541. doi 10.1002/cpa.3160300502\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.median!-Tuple{AbstractManifold, Vararg{Any}}","page":"Statistics","title":"Statistics.median!","text":"median!(M::AbstractManifold, y, x::AbstractVector[, w::AbstractWeights]; kwargs...)\nmedian!(\n M::AbstractManifold,\n y,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::AbstractEstimationMethod;\n kwargs...,\n)\n\ncomputes the median in-place in y.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.median-Tuple{AbstractManifold, AbstractVector, AbstractVector, CyclicProximalPointEstimation}","page":"Statistics","title":"Statistics.median","text":"median(\n M::AbstractManifold,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::CyclicProximalPointEstimation;\n p0=x[1],\n stop_iter=1000000,\n retraction::AbstractRetractionMethod = default_retraction_method(M, eltype(x),),\n inverse_retraction::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, eltype(x),),\n kwargs...,\n)\n\nCompute the median using CyclicProximalPointEstimation.\n\nOptionally, provide p0, the starting point (by default set to the first data point). stop_iter denotes the maximal number of iterations to perform and the kwargs... are passed to isapprox to stop, when the minimal change between two iterates is small. For more stopping criteria check the Manopt.jl package and use a solver therefrom.\n\nOptionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction.\n\nThe algorithm is further described in [Bačák2014].\n\n[Bačák2014]: Bačák, M: Computing Medians and Means in Hadamard Spaces. SIAM Journal on Optimization (2014), 24(3), pp. 1542–1566, doi: 10.1137/140953393, arxiv: 1210.2145\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.median-Tuple{AbstractManifold, AbstractVector, AbstractVector, ExtrinsicEstimation}","page":"Statistics","title":"Statistics.median","text":"median(\n M::AbstractManifold,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::ExtrinsicEstimation;\n extrinsic_method = CyclicProximalPointEstimation(),\n kwargs...,\n)\n\nEstimate the median of x using ExtrinsicEstimation, i.e. by computing the median in the embedding and projecting the result back. You can specify an extrinsic_method to specify which median estimation method to use in the embedding, which defaults to CyclicProximalPointEstimation.\n\nSee median for a description of kwargs.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.median-Tuple{AbstractManifold, AbstractVector, AbstractVector, Manifolds.WeiszfeldEstimation}","page":"Statistics","title":"Statistics.median","text":"median(\n M::AbstractManifold,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::WeiszfeldEstimation;\n α = 1.0,\n p0=x[1],\n stop_iter=2000,\n retraction::AbstractRetractionMethod = default_retraction_method(M, eltype(x)),\n inverse_retraction::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, eltype(x)),\n kwargs...,\n)\n\nCompute the median using WeiszfeldEstimation.\n\nOptionally, provide p0, the starting point (by default set to the first data point). stop_iter denotes the maximal number of iterations to perform and the kwargs... are passed to isapprox to stop, when the minimal change between two iterates is small. For more stopping criteria check the Manopt.jl package and use a solver therefrom.\n\nThe parameter αin (02 is a step size.\n\nThe algorithm is further described in [FletcherVenkatasubramanianJoshi2008], especially the update rule in Eq. (6), i.e. Let q_k denote the current iterate, n the number of points x_1ldotsx_n, and\n\nI_k = bigl i in 1ldotsn big x_i neq q_k bigr\n\nall indices of points that are not equal to the current iterate. Then the update reads q_k+1 = exp_q_k(αX), where\n\nX = frac1ssum_iin I_k fracw_id_mathcal M(q_kx_i)log_q_kx_i\nquad\ntext with \nquad\ns = sum_iin I_k fracw_id_mathcal M(q_kx_i)\n\nand where mathrmd_mathcal M denotes the Riemannian distance.\n\nOptionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction, which by default use the exponential and logarithmic map, respectively.\n\n[FletcherVenkatasubramanianJoshi2008]: Fletcher, T., Venkatasubramanian, S., Joshi, S: Robust statistics on Riemannian manifolds via the geometric median 2008 IEEE Conference on Computer Vision and Pattern Recognition, doi: 10.1109/CVPR.2008.4587747,\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.median-Tuple{AbstractManifold, Vararg{Any}}","page":"Statistics","title":"Statistics.median","text":"median(M::AbstractManifold, x::AbstractVector[, w::AbstractWeights]; kwargs...)\nmedian(\n M::AbstractManifold,\n x::AbstractVector,\n [w::AbstractWeights,]\n method::AbstractEstimationMethod;\n kwargs...,\n)\n\nCompute the (optionally weighted) Riemannian median of the vector x of points on the AbstractManifold M, defined as the point that satisfies the minimizer\n\nargmin_y mathcal M frac1sum_i=1^n w_i sum_i=1^n w_imathrmd_mathcal M(yx_i)\n\nwhere mathrmd_mathcal M denotes the Riemannian distance. This function is nonsmooth (i.e nondifferentiable).\n\nIn the general case, the CyclicProximalPointEstimation is used to compute the median. However, this default may be overloaded for specific manifolds.\n\nCompute the median using the specified method.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.std-Tuple{AbstractManifold, Vararg{Any}}","page":"Statistics","title":"Statistics.std","text":"std(M, x, m=mean(M, x); corrected=true, kwargs...)\nstd(M, x, w::AbstractWeights, m=mean(M, x, w); corrected=false, kwargs...)\n\ncompute the optionally weighted standard deviation of a Vector x of n data points on the AbstractManifold M, i.e.\n\nsqrtfrac1c sum_i=1^n w_i d_mathcal M^2 (x_im)\n\nwhere c is a correction term, see Statistics.std. The mean of x can be specified as m, and the corrected variance can be activated by setting corrected=true.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Statistics.var-Tuple{AbstractManifold, Any}","page":"Statistics","title":"Statistics.var","text":"var(M, x, m=mean(M, x); corrected=true)\nvar(M, x, w::AbstractWeights, m=mean(M, x, w); corrected=false)\n\ncompute the (optionally weighted) variance of a Vector x of n data points on the AbstractManifold M, i.e.\n\nfrac1c sum_i=1^n w_i d_mathcal M^2 (x_im)\n\nwhere c is a correction term, see Statistics.var. The mean of x can be specified as m, and the corrected variance can be activated by setting corrected=true. All further kwargs... are passed to the computation of the mean (if that is not provided).\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#StatsBase.kurtosis-Tuple{AbstractManifold, AbstractVector, StatsBase.AbstractWeights}","page":"Statistics","title":"StatsBase.kurtosis","text":"kurtosis(M::AbstractManifold, x::AbstractVector, k::Int[, w::AbstractWeights], m=mean(M, x[, w]))\n\nCompute the excess kurtosis of points in x on manifold M. Optionally provide weights w and/or a precomputed mean m.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#StatsBase.mean_and_std-Tuple{AbstractManifold, Vararg{Any}}","page":"Statistics","title":"StatsBase.mean_and_std","text":"mean_and_std(M::AbstractManifold, x::AbstractVector[, w::AbstractWeights]; kwargs...) -> (mean, std)\n\nCompute the mean and the standard deviation std simultaneously.\n\nmean_and_std(\n M::AbstractManifold,\n x::AbstractVector\n [w::AbstractWeights,]\n method::AbstractEstimationMethod;\n kwargs...,\n) -> (mean, var)\n\nUse the method for simultaneously computing the mean and standard deviation. To use a mean-specific method, call mean and then std.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#StatsBase.mean_and_var-Tuple{AbstractManifold, AbstractVector, StatsBase.AbstractWeights, GeodesicInterpolationWithinRadius}","page":"Statistics","title":"StatsBase.mean_and_var","text":"mean_and_var(\n M::AbstractManifold,\n x::AbstractVector\n [w::AbstractWeights,]\n method::GeodesicInterpolationWithinRadius;\n kwargs...,\n) -> (mean, var)\n\nUse repeated weighted geodesic interpolation to estimate the mean. Simultaneously, use a Welford-like recursion to estimate the variance.\n\nSee GeodesicInterpolationWithinRadius and mean_and_var for more information.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#StatsBase.mean_and_var-Tuple{AbstractManifold, AbstractVector, StatsBase.AbstractWeights, GeodesicInterpolation}","page":"Statistics","title":"StatsBase.mean_and_var","text":"mean_and_var(\n M::AbstractManifold,\n x::AbstractVector\n [w::AbstractWeights,]\n method::GeodesicInterpolation;\n shuffle_rng::Union{AbstractRNG,Nothing} = nothing,\n retraction::AbstractRetractionMethod = default_retraction_method(M, eltype(x)),\n inverse_retraction::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, eltype(x)),\n kwargs...,\n) -> (mean, var)\n\nUse the repeated weighted geodesic interpolation to estimate the mean. Simultaneously, use a Welford-like recursion to estimate the variance.\n\nIf shuffle_rng is provided, it is used to shuffle the order in which the points are considered. Optionally, pass retraction and inverse_retraction method types to specify the (inverse) retraction.\n\nSee GeodesicInterpolation for details on the geodesic interpolation method.\n\nnote: Note\nThe Welford algorithm for the variance is experimental and is not guaranteed to give accurate results except on Euclidean.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#StatsBase.mean_and_var-Tuple{AbstractManifold, Vararg{Any}}","page":"Statistics","title":"StatsBase.mean_and_var","text":"mean_and_var(M::AbstractManifold, x::AbstractVector[, w::AbstractWeights]; kwargs...) -> (mean, var)\n\nCompute the mean and the variance simultaneously. See those functions for a description of the arguments.\n\nmean_and_var(\n M::AbstractManifold,\n x::AbstractVector\n [w::AbstractWeights,]\n method::AbstractEstimationMethod;\n kwargs...,\n) -> (mean, var)\n\nUse the method for simultaneously computing the mean and variance. To use a mean-specific method, call mean and then var.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#StatsBase.moment","page":"Statistics","title":"StatsBase.moment","text":"moment(M::AbstractManifold, x::AbstractVector, k::Int[, w::AbstractWeights], m=mean(M, x[, w]))\n\nCompute the kth central moment of points in x on manifold M. Optionally provide weights w and/or a precomputed mean.\n\n\n\n\n\n","category":"function"},{"location":"features/statistics.html#StatsBase.skewness-Tuple{AbstractManifold, AbstractVector, StatsBase.AbstractWeights}","page":"Statistics","title":"StatsBase.skewness","text":"skewness(M::AbstractManifold, x::AbstractVector, k::Int[, w::AbstractWeights], m=mean(M, x[, w]))\n\nCompute the standardized skewness of points in x on manifold M. Optionally provide weights w and/or a precomputed mean m.\n\n\n\n\n\n","category":"method"},{"location":"features/statistics.html#Literature","page":"Statistics","title":"Literature","text":"","category":"section"},{"location":"manifolds/spectrahedron.html#Spectrahedron","page":"Spectrahedron","title":"Spectrahedron","text":"","category":"section"},{"location":"manifolds/spectrahedron.html","page":"Spectrahedron","title":"Spectrahedron","text":"Modules = [Manifolds]\nPages = [\"manifolds/Spectrahedron.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/spectrahedron.html#Manifolds.Spectrahedron","page":"Spectrahedron","title":"Manifolds.Spectrahedron","text":"Spectrahedron{N,K} <: AbstractDecoratorManifold{ℝ}\n\nThe Spectrahedron manifold, also known as the set of correlation matrices (symmetric positive semidefinite matrices) of rank k with unit trace.\n\nbeginaligned\nmathcal S(nk) =\nbiglp ℝ^n n big a^mathrmTpa geq 0 text for all a ℝ^n\noperatornametr(p) = sum_i=1^n p_ii = 1\ntextand p = qq^mathrmT text for q in ℝ^n k\ntext with operatornamerank(p) = operatornamerank(q) = k\nbigr\nendaligned\n\nThis manifold is working solely on the matrices q. Note that this q is not unique, indeed for any orthogonal matrix A we have (qA)(qA)^mathrmT = qq^mathrmT = p, so the manifold implemented here is the quotient manifold. The unit trace translates to unit frobenius norm of q.\n\nThe tangent space at p, denoted T_pmathcal E(nk), is also represented by matrices Yin ℝ^n k and reads as\n\nT_pmathcal S(nk) = bigl\nX ℝ^n nX = qY^mathrmT + Yq^mathrmT\ntext with operatornametr(X) = sum_i=1^nX_ii = 0\nbigr\n\nendowed with the Euclidean metric from the embedding, i.e. from the ℝ^n k\n\nThis manifold was for example investigated in[JourneeBachAbsilSepulchre2010].\n\nConstructor\n\nSpectrahedron(n,k)\n\ngenerates the manifold mathcal S(nk) subset ℝ^n n.\n\n[JourneeBachAbsilSepulchre2010]: Journée, M., Bach, F., Absil, P.-A., and Sepulchre, R.: “Low-Rank Optimization on the Cone of Positive Semidefinite Matrices”, SIAM Journal on Optimization (20)5, pp. 2327–2351, 2010. doi: 10.1137/080731359, arXiv: 0807.4423.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.check_point-Union{Tuple{K}, Tuple{N}, Tuple{Spectrahedron{N, K}, Any}} where {N, K}","page":"Spectrahedron","title":"ManifoldsBase.check_point","text":"check_point(M::Spectrahedron, q; kwargs...)\n\nchecks, whether q is a valid reprsentation of a point p=qq^mathrmT on the Spectrahedron M, i.e. is a matrix of size (N,K), such that p is symmetric positive semidefinite and has unit trace, i.e. q has to have unit frobenius norm. Since by construction p is symmetric, this is not explicitly checked. Since p is by construction positive semidefinite, this is not checked. The tolerances for positive semidefiniteness and unit trace can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.check_vector-Union{Tuple{K}, Tuple{N}, Tuple{Spectrahedron{N, K}, Any, Any}} where {N, K}","page":"Spectrahedron","title":"ManifoldsBase.check_vector","text":"check_vector(M::Spectrahedron, q, Y; kwargs...)\n\nCheck whether X = qY^mathrmT + Yq^mathrmT is a tangent vector to p=qq^mathrmT on the Spectrahedron M, i.e. atfer check_point of q, Y has to be of same dimension as q and a X has to be a symmetric matrix with trace. The tolerance for the base point check and zero diagonal can be set using the kwargs.... Note that symmetry of X holds by construction and is not explicitly checked.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.is_flat-Tuple{Spectrahedron}","page":"Spectrahedron","title":"ManifoldsBase.is_flat","text":"is_flat(::Spectrahedron)\n\nReturn false. Spectrahedron is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.manifold_dimension-Union{Tuple{Spectrahedron{N, K}}, Tuple{K}, Tuple{N}} where {N, K}","page":"Spectrahedron","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::Spectrahedron)\n\nreturns the dimension of Spectrahedron M=mathcal S(nk) nk ℕ, i.e.\n\ndim mathcal S(nk) = nk - 1 - frack(k-1)2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.project-Tuple{Spectrahedron, Any}","page":"Spectrahedron","title":"ManifoldsBase.project","text":"project(M::Spectrahedron, q)\n\nproject q onto the manifold Spectrahedron M, by normalizing w.r.t. the Frobenius norm\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.project-Tuple{Spectrahedron, Vararg{Any}}","page":"Spectrahedron","title":"ManifoldsBase.project","text":"project(M::Spectrahedron, q, Y)\n\nProject Y onto the tangent space at q, i.e. row-wise onto the Spectrahedron manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.representation_size-Union{Tuple{Spectrahedron{N, K}}, Tuple{K}, Tuple{N}} where {N, K}","page":"Spectrahedron","title":"ManifoldsBase.representation_size","text":"representation_size(M::Spectrahedron)\n\nReturn the size of an array representing an element on the Spectrahedron manifold M, i.e. n k, the size of such factor of p=qq^mathrmT on mathcal M = mathcal S(nk).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.retract-Tuple{Spectrahedron, Any, Any, ProjectionRetraction}","page":"Spectrahedron","title":"ManifoldsBase.retract","text":"retract(M::Spectrahedron, q, Y, ::ProjectionRetraction)\n\ncompute a projection based retraction by projecting q+Y back onto the manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.vector_transport_to-Tuple{Spectrahedron, Any, Any, Any, ProjectionTransport}","page":"Spectrahedron","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::Spectrahedron, p, X, q)\n\ntransport the tangent vector X at p to q by projecting it onto the tangent space at q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#ManifoldsBase.zero_vector-Tuple{Spectrahedron, Vararg{Any}}","page":"Spectrahedron","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::Spectrahedron,p)\n\nreturns the zero tangent vector in the tangent space of the symmetric positive definite matrix p on the Spectrahedron manifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spectrahedron.html#Literature","page":"Spectrahedron","title":"Literature","text":"","category":"section"},{"location":"manifolds/choleskyspace.html#Cholesky-space","page":"Cholesky space","title":"Cholesky space","text":"","category":"section"},{"location":"manifolds/choleskyspace.html","page":"Cholesky space","title":"Cholesky space","text":"The Cholesky space is a Riemannian manifold on the lower triangular matrices. Its metric is based on the cholesky decomposition. The CholeskySpace is used to define the LogCholeskyMetric on the manifold of SymmetricPositiveDefinite matrices.","category":"page"},{"location":"manifolds/choleskyspace.html","page":"Cholesky space","title":"Cholesky space","text":"Modules = [Manifolds]\nPages = [\"manifolds/CholeskySpace.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/choleskyspace.html#Manifolds.CholeskySpace","page":"Cholesky space","title":"Manifolds.CholeskySpace","text":"CholeskySpace{N} <: AbstractManifold{ℝ}\n\nThe manifold of lower triangular matrices with positive diagonal and a metric based on the cholesky decomposition. The formulae for this manifold are for example summarized in Table 1 of [Lin2019].\n\nConstructor\n\nCholeskySpace(n)\n\nGenerate the manifold of n n lower triangular matrices with positive diagonal.\n\n[Lin2019]: Lin, Zenhua: Riemannian Geometry of Symmetric Positive Definite Matrices via Cholesky Decomposition, arXiv: 1908.09326.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/choleskyspace.html","page":"Cholesky space","title":"Cholesky space","text":"Modules = [Manifolds]\nPages = [\"manifolds/CholeskySpace.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/choleskyspace.html#Base.exp-Tuple{CholeskySpace, Vararg{Any}}","page":"Cholesky space","title":"Base.exp","text":"exp(M::CholeskySpace, p, X)\n\nCompute the exponential map on the CholeskySpace M emanating from the lower triangular matrix with positive diagonal p towards the lower triangular matrix X The formula reads\n\nexp_p X = p + X + operatornamediag(p)\noperatornamediag(p)expbigl( operatornamediag(X)operatornamediag(p)^-1bigr)\n\nwhere cdot denotes the strictly lower triangular matrix, and operatornamediag extracts the diagonal matrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#Base.log-Tuple{LinearAlgebra.Cholesky, Vararg{Any}}","page":"Cholesky space","title":"Base.log","text":"log(M::CholeskySpace, X, p, q)\n\nCompute the logarithmic map on the CholeskySpace M for the geodesic emanating from the lower triangular matrix with positive diagonal p towards q. The formula reads\n\nlog_p q = p - q + operatornamediag(p)logbigl(operatornamediag(q)operatornamediag(p)^-1bigr)\n\nwhere cdot denotes the strictly lower triangular matrix, and operatornamediag extracts the diagonal matrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#ManifoldsBase.check_point-Tuple{CholeskySpace, Any}","page":"Cholesky space","title":"ManifoldsBase.check_point","text":"check_point(M::CholeskySpace, p; kwargs...)\n\nCheck whether the matrix p lies on the CholeskySpace M, i.e. it's size fits the manifold, it is a lower triangular matrix and has positive entries on the diagonal. The tolerance for the tests can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#ManifoldsBase.check_vector-Tuple{CholeskySpace, Any, Any}","page":"Cholesky space","title":"ManifoldsBase.check_vector","text":"check_vector(M::CholeskySpace, p, X; kwargs... )\n\nCheck whether v is a tangent vector to p on the CholeskySpace M, i.e. after check_point(M,p), X has to have the same dimension as p and a symmetric matrix. The tolerance for the tests can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#ManifoldsBase.distance-Tuple{CholeskySpace, Any, Any}","page":"Cholesky space","title":"ManifoldsBase.distance","text":"distance(M::CholeskySpace, p, q)\n\nCompute the Riemannian distance on the CholeskySpace M between two matrices p, q that are lower triangular with positive diagonal. The formula reads\n\nd_mathcal M(pq) = sqrtsum_ij (p_ij-q_ij)^2 +\nsum_j=1^m (log p_jj - log q_jj)^2\n\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#ManifoldsBase.inner-Tuple{CholeskySpace, Any, Any, Any}","page":"Cholesky space","title":"ManifoldsBase.inner","text":"inner(M::CholeskySpace, p, X, Y)\n\nCompute the inner product on the CholeskySpace M at the lower triangular matric with positive diagonal p and the two tangent vectors X,Y, i.e they are both lower triangular matrices with arbitrary diagonal. The formula reads\n\ng_p(XY) = sum_ij X_ijY_ij + sum_j=1^m X_iiY_iip_ii^-2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#ManifoldsBase.is_flat-Tuple{CholeskySpace}","page":"Cholesky space","title":"ManifoldsBase.is_flat","text":"is_flat(::CholeskySpace)\n\nReturn false. CholeskySpace is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#ManifoldsBase.manifold_dimension-Union{Tuple{CholeskySpace{N}}, Tuple{N}} where N","page":"Cholesky space","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::CholeskySpace)\n\nReturn the manifold dimension for the CholeskySpace M, i.e.\n\n dim(mathcal M) = fracN(N+1)2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#ManifoldsBase.parallel_transport_to-Tuple{CholeskySpace, Any, Any, Any}","page":"Cholesky space","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::CholeskySpace, p, X, q)\n\nParallely transport the tangent vector X at p along the geodesic to q on the CholeskySpace manifold M. The formula reads\n\nmathcal P_qp(X) = X \n+ operatornamediag(q)operatornamediag(p)^-1operatornamediag(X)\n\nwhere cdot denotes the strictly lower triangular matrix, and operatornamediag extracts the diagonal matrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#ManifoldsBase.representation_size-Union{Tuple{CholeskySpace{N}}, Tuple{N}} where N","page":"Cholesky space","title":"ManifoldsBase.representation_size","text":"representation_size(M::CholeskySpace)\n\nReturn the representation size for the CholeskySpace{N} M, i.e. (N,N).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#ManifoldsBase.zero_vector-Tuple{CholeskySpace, Vararg{Any}}","page":"Cholesky space","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::CholeskySpace, p)\n\nReturn the zero tangent vector on the CholeskySpace M at p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/choleskyspace.html#Literature","page":"Cholesky space","title":"Literature","text":"","category":"section"},{"location":"features/utilities.html#Ease-of-notation","page":"Utilities","title":"Ease of notation","text":"","category":"section"},{"location":"features/utilities.html","page":"Utilities","title":"Utilities","text":"The following terms introduce a nicer notation for some operations, for example using the ∈ operator, p mathcal M, to determine whether p is a point on the AbstractManifold mathcal M.","category":"page"},{"location":"features/utilities.html","page":"Utilities","title":"Utilities","text":"in\nTangentSpace","category":"page"},{"location":"features/utilities.html#Base.in","page":"Utilities","title":"Base.in","text":"Base.in(p, M::AbstractManifold; kwargs...)\np ∈ M\n\nCheck, whether a point p is a valid point (i.e. in) a AbstractManifold M. This method employs is_point deactivating the error throwing option.\n\n\n\n\n\nBase.in(p, TpM::TangentSpaceAtPoint; kwargs...)\nX ∈ TangentSpaceAtPoint(M,p)\n\nCheck whether X is a tangent vector from (in) the tangent space T_pmathcal M, i.e. the TangentSpaceAtPoint at p on the AbstractManifold M. This method uses is_vector deactivating the error throw option.\n\n\n\n\n\n","category":"function"},{"location":"features/utilities.html#ManifoldsBase.TangentSpace","page":"Utilities","title":"ManifoldsBase.TangentSpace","text":"TangentSpace(M::AbstractManifold, p)\n\nReturn a TangentSpaceAtPoint representing tangent space at p on the AbstractManifold M.\n\n\n\n\n\n","category":"constant"},{"location":"features/utilities.html#Fallback-for-the-exponential-map:-Solving-the-corresponding-ODE","page":"Utilities","title":"Fallback for the exponential map: Solving the corresponding ODE","text":"","category":"section"},{"location":"features/utilities.html","page":"Utilities","title":"Utilities","text":"When additionally loading NLSolve.jl the following fallback for the exponential map is available.","category":"page"},{"location":"features/utilities.html","page":"Utilities","title":"Utilities","text":"Modules = [Manifolds]\nPages = [\"nlsolve.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"features/utilities.html#Public-documentation","page":"Utilities","title":"Public documentation","text":"","category":"section"},{"location":"features/utilities.html","page":"Utilities","title":"Utilities","text":"The following functions are of interest for extending and using the ProductManifold.","category":"page"},{"location":"features/utilities.html","page":"Utilities","title":"Utilities","text":"submanifold_component\nsubmanifold_components\nProductRepr","category":"page"},{"location":"features/utilities.html#Manifolds.submanifold_component","page":"Utilities","title":"Manifolds.submanifold_component","text":"submanifold_component(M::AbstractManifold, p, i::Integer)\nsubmanifold_component(M::AbstractManifold, p, ::Val(i)) where {i}\nsubmanifold_component(p, i::Integer)\nsubmanifold_component(p, ::Val(i)) where {i}\n\nProject the product array p on M to its ith component. A new array is returned.\n\n\n\n\n\n","category":"function"},{"location":"features/utilities.html#Manifolds.submanifold_components","page":"Utilities","title":"Manifolds.submanifold_components","text":"submanifold_components(M::AbstractManifold, p)\nsubmanifold_components(p)\n\nGet the projected components of p on the submanifolds of M. The components are returned in a Tuple.\n\n\n\n\n\n","category":"function"},{"location":"features/utilities.html#Manifolds.ProductRepr","page":"Utilities","title":"Manifolds.ProductRepr","text":"ProductRepr(parts)\n\nA more general but slower representation of points and tangent vectors on a product manifold.\n\nExample:\n\nA product point on a product manifold Sphere(2) × Euclidean(2) might be created as\n\nProductRepr([1.0, 0.0, 0.0], [2.0, 3.0])\n\nwhere [1.0, 0.0, 0.0] is the part corresponding to the sphere factor and [2.0, 3.0] is the part corresponding to the euclidean manifold.\n\nwarning: Warning\nProductRepr is deprecated and will be removed in a future release. Please use ArrayPartition instead.\n\n\n\n\n\n","category":"type"},{"location":"features/utilities.html#Specific-exception-types","page":"Utilities","title":"Specific exception types","text":"","category":"section"},{"location":"features/utilities.html","page":"Utilities","title":"Utilities","text":"For some manifolds it is useful to keep an extra index, at which point on the manifold, the error occurred as well as to collect all errors that occurred on a manifold. This page contains the manifold-specific error messages this package introduces.","category":"page"},{"location":"features/utilities.html","page":"Utilities","title":"Utilities","text":"Modules = [Manifolds]\nPages = [\"errors.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/oblique.html#Oblique-manifold","page":"Oblique manifold","title":"Oblique manifold","text":"","category":"section"},{"location":"manifolds/oblique.html","page":"Oblique manifold","title":"Oblique manifold","text":"The oblique manifold mathcalOB(nm) is modeled as an AbstractPowerManifold of the (real-valued) Sphere and uses ArrayPowerRepresentation. Points on the torus are hence matrices, x ℝ^nm.","category":"page"},{"location":"manifolds/oblique.html","page":"Oblique manifold","title":"Oblique manifold","text":"Modules = [Manifolds]\nPages = [\"manifolds/Oblique.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/oblique.html#Manifolds.Oblique","page":"Oblique manifold","title":"Manifolds.Oblique","text":"Oblique{N,M,𝔽} <: AbstractPowerManifold{𝔽}\n\nThe oblique manifold mathcalOB(nm) is the set of 𝔽-valued matrices with unit norm column endowed with the metric from the embedding. This yields exactly the same metric as considering the product metric of the unit norm vectors, i.e. PowerManifold of the (n-1)-dimensional Sphere.\n\nThe Sphere is stored internally within M.manifold, such that all functions of AbstractPowerManifold can be used directly.\n\nConstructor\n\nOblique(n,m)\n\nGenerate the manifold of matrices mathbb R^n m such that the m columns are unit vectors, i.e. from the Sphere(n-1).\n\n\n\n\n\n","category":"type"},{"location":"manifolds/oblique.html#Functions","page":"Oblique manifold","title":"Functions","text":"","category":"section"},{"location":"manifolds/oblique.html","page":"Oblique manifold","title":"Oblique manifold","text":"Most functions are directly implemented for an AbstractPowerManifold with ArrayPowerRepresentation except the following special cases:","category":"page"},{"location":"manifolds/oblique.html","page":"Oblique manifold","title":"Oblique manifold","text":"Modules = [Manifolds]\nPages = [\"manifolds/Oblique.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/oblique.html#ManifoldsBase.check_point-Tuple{Oblique, Any}","page":"Oblique manifold","title":"ManifoldsBase.check_point","text":"check_point(M::Oblique{n,m},p)\n\nChecks whether p is a valid point on the Oblique{m,n} M, i.e. is a matrix of m unit columns from mathbb R^n, i.e. each column is a point from Sphere(n-1).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/oblique.html#ManifoldsBase.check_vector-Union{Tuple{m}, Tuple{n}, Tuple{Oblique{n, m}, Any, Any}} where {n, m}","page":"Oblique manifold","title":"ManifoldsBase.check_vector","text":"check_vector(M::Oblique p, X; kwargs...)\n\nChecks whether X is a valid tangent vector to p on the Oblique M. This means, that p is valid, that X is of correct dimension and columnswise a tangent vector to the columns of p on the Sphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/oblique.html#ManifoldsBase.parallel_transport_to-Tuple{Oblique, Any, Any, Any}","page":"Oblique manifold","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::Oblique, p, X, q)\n\nCompute the parallel transport on the Oblique manifold by doing a column wise parallel transport on the Sphere\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#Orthogonal-and-Unitary-matrices","page":"Orthogonal and Unitary Matrices","title":"Orthogonal and Unitary matrices","text":"","category":"section"},{"location":"manifolds/generalunitary.html","page":"Orthogonal and Unitary Matrices","title":"Orthogonal and Unitary Matrices","text":"Both OrthogonalMatrices and UnitaryMatrices are quite similar, as are Rotations, as well as unitary matrices with determinant equal to one. So these share a {common implementation}(@ref generalunitarymatrices)","category":"page"},{"location":"manifolds/generalunitary.html#Orthogonal-Matrices","page":"Orthogonal and Unitary Matrices","title":"Orthogonal Matrices","text":"","category":"section"},{"location":"manifolds/generalunitary.html","page":"Orthogonal and Unitary Matrices","title":"Orthogonal and Unitary Matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/Orthogonal.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/generalunitary.html#Manifolds.OrthogonalMatrices","page":"Orthogonal and Unitary Matrices","title":"Manifolds.OrthogonalMatrices","text":" OrthogonalMatrices{n} = GeneralUnitaryMatrices{n,ℝ,AbsoluteDeterminantOneMatrices}\n\nThe manifold of (real) orthogonal matrices mathrmO(n).\n\nOrthogonalMatrices(n)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/generalunitary.html#Unitary-Matrices","page":"Orthogonal and Unitary Matrices","title":"Unitary Matrices","text":"","category":"section"},{"location":"manifolds/generalunitary.html","page":"Orthogonal and Unitary Matrices","title":"Orthogonal and Unitary Matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/Unitary.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/generalunitary.html#Manifolds.UnitaryMatrices","page":"Orthogonal and Unitary Matrices","title":"Manifolds.UnitaryMatrices","text":"const UnitaryMatrices{n,𝔽} = AbstarctUnitaryMatrices{n,𝔽,AbsoluteDeterminantOneMatrices}\n\nThe manifold U(n𝔽) of nn complex matrices (when 𝔽=ℂ) or quaternionic matrices (when 𝔽=ℍ) such that\n\np^mathrmHp = mathrmI_n\n\nwhere mathrmI_n is the nn identity matrix. Such matrices p have a property that lVert det(p) rVert = 1.\n\nThe tangent spaces are given by\n\n T_pU(n) coloneqq bigl\n X big pY text where Y text is skew symmetric i e Y = -Y^mathrmH\n bigr\n\nBut note that tangent vectors are represented in the Lie algebra, i.e. just using Y in the representation above.\n\nConstructor\n\nUnitaryMatrices(n, 𝔽::AbstractNumbers=ℂ)\n\nsee also OrthogonalMatrices for the real valued case.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/generalunitary.html#ManifoldsBase.manifold_dimension-Union{Tuple{UnitaryMatrices{n, ℂ}}, Tuple{n}} where n","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::UnitaryMatrices{n,ℂ}) where {n}\n\nReturn the dimension of the manifold unitary matrices.\n\ndim_mathrmU(n) = n^2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.manifold_dimension-Union{Tuple{UnitaryMatrices{n, ℍ}}, Tuple{n}} where n","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::UnitaryMatrices{n,ℍ})\n\nReturn the dimension of the manifold unitary matrices.\n\ndim_mathrmU(n ℍ) = n(2n+1)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#generalunitarymatrices","page":"Orthogonal and Unitary Matrices","title":"Common functions","text":"","category":"section"},{"location":"manifolds/generalunitary.html","page":"Orthogonal and Unitary Matrices","title":"Orthogonal and Unitary Matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/GeneralUnitaryMatrices.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/generalunitary.html#Manifolds.AbsoluteDeterminantOneMatrices","page":"Orthogonal and Unitary Matrices","title":"Manifolds.AbsoluteDeterminantOneMatrices","text":"AbsoluteDeterminantOneMatrices <: AbstractMatrixType\n\nA type to indicate that we require (orthogonal / unitary) matrices with normed determinant, i.e. that the absolute value of the determinant is 1.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/generalunitary.html#Manifolds.AbstractMatrixType","page":"Orthogonal and Unitary Matrices","title":"Manifolds.AbstractMatrixType","text":"AbstractMatrixType\n\nA plain type to distinguish different types of matrices, for example DeterminantOneMatrices and AbsoluteDeterminantOneMatrices\n\n\n\n\n\n","category":"type"},{"location":"manifolds/generalunitary.html#Manifolds.DeterminantOneMatrices","page":"Orthogonal and Unitary Matrices","title":"Manifolds.DeterminantOneMatrices","text":"DeterminantOneMatrices <: AbstractMatrixType\n\nA type to indicate that we require special (orthogonal / unitary) matrices, i.e. of determinant 1.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/generalunitary.html#Manifolds.GeneralUnitaryMatrices","page":"Orthogonal and Unitary Matrices","title":"Manifolds.GeneralUnitaryMatrices","text":"GeneralUnitaryMatrices{n,𝔽,S<:AbstractMatrixType} <: AbstractDecoratorManifold\n\nA common parametric type for matrices with a unitary property of size nn over the field mathbb F which additionally have the AbstractMatrixType, e.g. are DeterminantOneMatrices.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/generalunitary.html#Base.exp-Tuple{Manifolds.GeneralUnitaryMatrices, Any, Any}","page":"Orthogonal and Unitary Matrices","title":"Base.exp","text":"exp(M::Rotations, p, X)\nexp(M::OrthogonalMatrices, p, X)\nexp(M::UnitaryMatrices, p, X)\n\nCompute the exponential map, that is, since X is represented in the Lie algebra,\n\nexp_p(X) = p\\mathrm{e}^X\n\nFor different sizes, like n=234 there is specialised implementations\n\nThe algorithm used is a more numerically stable form of those proposed in [Gallier2002] and [Andrica2013].\n\n[Gallier2002]: Gallier J.; Xu D.; Computing exponentials of skew-symmetric matrices and logarithms of orthogonal matrices. International Journal of Robotics and Automation (2002), 17(4), pp. 1-11. pdf.\n\n[Andrica2013]: Andrica D.; Rohan R.-A.; Computing the Rodrigues coefficients of the exponential map of the Lie groups of matrices. Balkan Journal of Geometry and Its Applications (2013), 18(2), pp. 1-2. pdf.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#Base.log-Tuple{Manifolds.GeneralUnitaryMatrices, Any, Any}","page":"Orthogonal and Unitary Matrices","title":"Base.log","text":"log(M::Rotations, p, X)\nlog(M::OrthogonalMatrices, p, X)\nlog(M::UnitaryMatrices, p, X)\n\nCompute the logarithmic map, that is, since the resulting X is represented in the Lie algebra,\n\nlog_p q = \\log(p^{\\mathrm{H}q)\n\nwhich is projected onto the skew symmetric matrices for numerical stability.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#Base.log-Union{Tuple{n}, Tuple{Manifolds.GeneralUnitaryMatrices{n, ℝ}, Vararg{Any}}} where n","page":"Orthogonal and Unitary Matrices","title":"Base.log","text":"log(M::Rotations, p, q)\n\nCompute the logarithmic map on the Rotations manifold M which is given by\n\nlog_p q = operatornamelog(p^mathrmTq)\n\nwhere operatornameLog denotes the matrix logarithm. For numerical stability, the result is projected onto the set of skew symmetric matrices.\n\nFor antipodal rotations the function returns deterministically one of the tangent vectors that point at q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#Manifolds.cos_angles_4d_rotation_matrix-Tuple{Any}","page":"Orthogonal and Unitary Matrices","title":"Manifolds.cos_angles_4d_rotation_matrix","text":"cos_angles_4d_rotation_matrix(R)\n\n4D rotations can be described by two orthogonal planes that are unchanged by the action of the rotation (vectors within a plane rotate only within the plane). The cosines of the two angles αβ of rotation about these planes may be obtained from the distinct real parts of the eigenvalues of the rotation matrix. This function computes these more efficiently by solving the system\n\nbeginaligned\ncos α + cos β = frac12 operatornametr(R)\ncos α cos β = frac18 operatornametr(R)^2\n - frac116 operatornametr((R - R^T)^2) - 1\nendaligned\n\nBy convention, the returned values are sorted in decreasing order. See also angles_4d_skew_sym_matrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{n}, Tuple{Manifolds.GeneralUnitaryMatrices{n, 𝔽, Manifolds.DeterminantOneMatrices}, Any}} where {n, 𝔽}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.check_point","text":"check_point(M::Rotations, p; kwargs...)\n\nCheck whether p is a valid point on the UnitaryMatrices M, i.e. that p has an determinante of absolute value one, i.e. that p^mathrmHp\n\nThe tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{n}, Tuple{UnitaryMatrices{n, 𝔽}, Any}} where {n, 𝔽}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.check_point","text":"check_point(M::UnitaryMatrices, p; kwargs...)\ncheck_point(M::OrthogonalMatrices, p; kwargs...)\ncheck_point(M::GeneralUnitaryMatrices{n,𝔽}, p; kwargs...)\n\nCheck whether p is a valid point on the UnitaryMatrices or [OrthogonalMatrices] M, i.e. that p has an determinante of absolute value one\n\nThe tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.check_vector-Union{Tuple{𝔽}, Tuple{n}, Tuple{Manifolds.GeneralUnitaryMatrices{n, 𝔽}, Any, Any}} where {n, 𝔽}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.check_vector","text":"check_vector(M::UnitaryMatrices{n}, p, X; kwargs... )\ncheck_vector(M::OrthogonalMatrices{n}, p, X; kwargs... )\ncheck_vector(M::Rotations{n}, p, X; kwargs... )\ncheck_vector(M::GeneralUnitaryMatrices{n,𝔽}, p, X; kwargs... )\n\nCheck whether X is a tangent vector to p on the UnitaryMatrices space M, i.e. after check_point(M,p), X has to be skew symmetric (Hermitian) and orthogonal to p.\n\nThe tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.embed-Tuple{Manifolds.GeneralUnitaryMatrices, Any, Any}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.embed","text":"embed(M::GeneralUnitaryMatrices{n,𝔽}, p, X)\n\nEmbed the tangent vector X at point p in M from its Lie algebra representation (set of skew matrices) into the Riemannian submanifold representation\n\nThe formula reads\n\nX_textembedded = p * X\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.get_coordinates-Union{Tuple{n}, Tuple{Manifolds.GeneralUnitaryMatrices{n, ℝ}, Vararg{Any}}} where n","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.get_coordinates","text":"get_coordinates(M::Rotations, p, X)\nget_coordinates(M::OrthogonalMatrices, p, X)\nget_coordinates(M::UnitaryMatrices, p, X)\n\nExtract the unique tangent vector components X^i at point p on Rotations mathrmSO(n) from the matrix representation X of the tangent vector.\n\nThe basis on the Lie algebra 𝔰𝔬(n) is chosen such that for mathrmSO(2), X^1 = θ = X_21 is the angle of rotation, and for mathrmSO(3), (X^1 X^2 X^3) = (X_32 X_13 X_21) = θ u is the angular velocity and axis-angle representation, where u is the unit vector along the axis of rotation.\n\nFor mathrmSO(n) where n 4, the additional elements of X^i are X^j (j - 3)2 + k + 1 = X_jk, for j 4n k 1j).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.get_embedding-Union{Tuple{Manifolds.GeneralUnitaryMatrices{n, 𝔽}}, Tuple{𝔽}, Tuple{n}} where {n, 𝔽}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.get_embedding","text":"get_embedding(M::OrthogonalMatrices{n})\nget_embedding(M::Rotations{n})\nget_embedding(M::UnitaryMatrices{n})\n\nReturn the embedding, i.e. The mathbb F^nn, where mathbb F = mathbb R for the first two and mathbb F = mathbb C for the unitary matrices.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.get_vector-Union{Tuple{n}, Tuple{Manifolds.GeneralUnitaryMatrices{n, ℝ}, Vararg{Any}}} where n","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.get_vector","text":"get_vector(M::OrthogonalMatrices, p, Xⁱ, B::DefaultOrthogonalBasis)\nget_vector(M::Rotations, p, Xⁱ, B::DefaultOrthogonalBasis)\n\nConvert the unique tangent vector components Xⁱ at point p on Rotations or OrthogonalMatrices to the matrix representation X of the tangent vector. See get_coordinates for the conventions used.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.injectivity_radius-Tuple{Manifolds.GeneralUnitaryMatrices}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(G::GeneraliUnitaryMatrices)\n\nReturn the injectivity radius for general unitary matrix manifolds, which is[1]\n\n operatornameinj_mathrmU(n) = π\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.injectivity_radius-Union{Tuple{Manifolds.GeneralUnitaryMatrices{n, ℂ, Manifolds.DeterminantOneMatrices}}, Tuple{ℂ}, Tuple{n}} where {n, ℂ}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(G::GeneralUnitaryMatrices{n,ℂ,DeterminantOneMatrices})\n\nReturn the injectivity radius for general complex unitary matrix manifolds, where the determinant is +1, which is[1]\n\n operatornameinj_mathrmSU(n) = π sqrt2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.injectivity_radius-Union{Tuple{Manifolds.GeneralUnitaryMatrices{n, ℝ}}, Tuple{n}} where n","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(G::SpecialOrthogonal)\ninjectivity_radius(G::Orthogonal)\ninjectivity_radius(M::Rotations)\ninjectivity_radius(M::Rotations, ::ExponentialRetraction)\n\nReturn the radius of injectivity on the Rotations manifold M, which is πsqrt2. [1]\n\n[1]: For a derivation of the injectivity radius, see sethaxen.com/blog/2023/02/the-injectivity-radii-of-the-unitary-groups/.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.is_flat-Tuple{Manifolds.GeneralUnitaryMatrices}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.is_flat","text":"is_flat(M::GeneralUnitaryMatrices)\n\nReturn true if GeneralUnitaryMatrices M is SO(2) or U(1) and false otherwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.manifold_dimension-Union{Tuple{Manifolds.GeneralUnitaryMatrices{n, ℂ, Manifolds.DeterminantOneMatrices}}, Tuple{n}} where n","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::GeneralUnitaryMatrices{n,ℂ,DeterminantOneMatrices})\n\nReturn the dimension of the manifold of special unitary matrices.\n\ndim_mathrmSU(n) = n^2-1\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.manifold_dimension-Union{Tuple{Manifolds.GeneralUnitaryMatrices{n, ℝ}}, Tuple{n}} where n","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::Rotations)\nmanifold_dimension(M::OrthogonalMatrices)\n\nReturn the dimension of the manifold orthogonal matrices and of the manifold of rotations\n\ndim_mathrmO(n) = dim_mathrmSO(n) = fracn(n-1)2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.project-Tuple{Manifolds.GeneralUnitaryMatrices, Any, Any}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.project","text":" project(M::OrthogonalMatrices{n}, p, X)\n project(M::Rotations{n}, p, X)\n project(M::UnitaryMatrices{n}, p, X)\n\nOrthogonally project the tangent vector X 𝔽^n n, mathbb F mathbb R mathbb C to the tangent space of M at p, and change the representer to use the corresponding Lie algebra, i.e. we compute\n\n operatornameproj_p(X) = fracp^mathrmH X - (p^mathrmH X)^mathrmH2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.project-Union{Tuple{𝔽}, Tuple{n}, Tuple{UnitaryMatrices{n, 𝔽}, Any}} where {n, 𝔽}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.project","text":" project(G::UnitaryMatrices{n}, p)\n project(G::OrthogonalMatrices{n}, p)\n\nProject the point p 𝔽^n n to the nearest point in mathrmU(n𝔽)=Unitary(n,𝔽) under the Frobenius norm. If p = U S V^mathrmH is the singular value decomposition of p, then the projection is\n\n operatornameproj_mathrmU(n𝔽) colon p U V^mathrmH\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.retract-Union{Tuple{𝔽}, Tuple{n}, Tuple{Manifolds.GeneralUnitaryMatrices{n, 𝔽}, Any, Any, PolarRetraction}} where {n, 𝔽}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.retract","text":"retract(M::Rotations, p, X, ::PolarRetraction)\nretract(M::OrthogonalMatrices, p, X, ::PolarRetraction)\n\nCompute the SVD-based retraction on the Rotations and OrthogonalMatrices M from p in direction X (as an element of the Lie group) and is a second-order approximation of the exponential map. Let\n\nUSV = p + pX\n\nbe the singular value decomposition, then the formula reads\n\noperatornameretr_p X = UV^mathrmT\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.retract-Union{Tuple{𝔽}, Tuple{n}, Tuple{Manifolds.GeneralUnitaryMatrices{n, 𝔽}, Any, Any, QRRetraction}} where {n, 𝔽}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.retract","text":"retract(M::Rotations, p, X, ::QRRetraction)\nretract(M::OrthogonalMatrices, p. X, ::QRRetraction)\n\nCompute the QR-based retraction on the Rotations and OrthogonalMatrices M from p in direction X (as an element of the Lie group), which is a first-order approximation of the exponential map.\n\nThis is also the default retraction on these manifolds.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#ManifoldsBase.riemann_tensor-Tuple{Manifolds.GeneralUnitaryMatrices, Vararg{Any, 4}}","page":"Orthogonal and Unitary Matrices","title":"ManifoldsBase.riemann_tensor","text":"riemann_tensor(::GeneralUnitaryMatrices, p, X, Y, Z)\n\nCompute the value of Riemann tensor on the GeneralUnitaryMatrices manifold. The formula reads[Rentmeesters2011] R(XY)Z=frac14Z X Y.\n\n[Rentmeesters2011]: Q. Rentmeesters, “A gradient method for geodesic data fitting on some symmetric Riemannian manifolds,” in 2011 50th IEEE Conference on Decision and Control and European Control Conference, Dec. 2011, pp. 7141–7146. doi: 10.1109/CDC.2011.6161280.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#Statistics.mean-Union{Tuple{n}, Tuple{Manifolds.GeneralUnitaryMatrices{n, ℝ}, Any}} where n","page":"Orthogonal and Unitary Matrices","title":"Statistics.mean","text":"mean(\n M::Rotations,\n x::AbstractVector,\n [w::AbstractWeights,]\n method = GeodesicInterpolationWithinRadius(π/2/√2);\n kwargs...,\n)\n\nCompute the Riemannian mean of x using GeodesicInterpolationWithinRadius.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalunitary.html#Footnotes-and-References","page":"Orthogonal and Unitary Matrices","title":"Footnotes and References","text":"","category":"section"},{"location":"manifolds/multinomialdoublystochastic.html#Multinomial-doubly-stochastic-matrices","page":"Multinomial doubly stochastic matrices","title":"Multinomial doubly stochastic matrices","text":"","category":"section"},{"location":"manifolds/multinomialdoublystochastic.html","page":"Multinomial doubly stochastic matrices","title":"Multinomial doubly stochastic matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/MultinomialDoublyStochastic.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/multinomialdoublystochastic.html#Manifolds.AbstractMultinomialDoublyStochastic","page":"Multinomial doubly stochastic matrices","title":"Manifolds.AbstractMultinomialDoublyStochastic","text":"AbstractMultinomialDoublyStochastic{N} <: AbstractDecoratorManifold{ℝ}\n\nA common type for manifolds that are doubly stochastic, for example by direct constraint MultinomialDoubleStochastic or by symmetry MultinomialSymmetric, as long as they are also modeled as IsIsometricEmbeddedManifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/multinomialdoublystochastic.html#Manifolds.MultinomialDoubleStochastic","page":"Multinomial doubly stochastic matrices","title":"Manifolds.MultinomialDoubleStochastic","text":"MultinomialDoublyStochastic{n} <: AbstractMultinomialDoublyStochastic{N}\n\nThe set of doubly stochastic multinomial matrices consists of all nn matrices with stochastic columns and rows, i.e.\n\nbeginaligned\nmathcalDP(n) coloneqq biglp ℝ^nn big p_ij 0 text for all i=1n j=1m\n pmathbf1_n = p^mathrmTmathbf1_n = mathbf1_n\nbigr\nendaligned\n\nwhere mathbf1_n is the vector of length n containing ones.\n\nThe tangent space can be written as\n\nT_pmathcalDP(n) coloneqq bigl\nX ℝ^nn big X = X^mathrmT text and \nXmathbf1_n = X^mathrmTmathbf1_n = mathbf0_n\nbigr\n\nwhere mathbf0_n is the vector of length n containing zeros.\n\nMore details can be found in Section III[DouikHassibi2019].\n\nConstructor\n\nMultinomialDoubleStochastic(n)\n\nGenerate the manifold of matrices mathbb R^nn that are doubly stochastic and symmetric.\n\n[DouikHassibi2019]: A. Douik, B. Hassibi: AbstractManifold Optimization Over the Set of Doubly Stochastic Matrices: A Second-Order Geometry, IEEE Transactions on Signal Processing 67(22), pp. 5761–5774, 2019. doi: 10.1109/tsp.2019.2946024, arXiv: 1802.02628.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/multinomialdoublystochastic.html#ManifoldsBase.check_point-Union{Tuple{n}, Tuple{MultinomialDoubleStochastic{n}, Any}} where n","page":"Multinomial doubly stochastic matrices","title":"ManifoldsBase.check_point","text":"check_point(M::MultinomialDoubleStochastic, p)\n\nChecks whether p is a valid point on the MultinomialDoubleStochastic(n) M, i.e. is a matrix with positive entries whose rows and columns sum to one.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialdoublystochastic.html#ManifoldsBase.check_vector-Union{Tuple{n}, Tuple{MultinomialDoubleStochastic{n}, Any, Any}} where n","page":"Multinomial doubly stochastic matrices","title":"ManifoldsBase.check_vector","text":"check_vector(M::MultinomialDoubleStochastic p, X; kwargs...)\n\nChecks whether X is a valid tangent vector to p on the MultinomialDoubleStochastic M. This means, that p is valid, that X is of correct dimension and sums to zero along any column or row.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialdoublystochastic.html#ManifoldsBase.is_flat-Tuple{MultinomialDoubleStochastic}","page":"Multinomial doubly stochastic matrices","title":"ManifoldsBase.is_flat","text":"is_flat(::MultinomialDoubleStochastic)\n\nReturn false. MultinomialDoubleStochastic is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialdoublystochastic.html#ManifoldsBase.manifold_dimension-Union{Tuple{MultinomialDoubleStochastic{n}}, Tuple{n}} where n","page":"Multinomial doubly stochastic matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::MultinomialDoubleStochastic{n}) where {n}\n\nreturns the dimension of the MultinomialDoubleStochastic manifold namely\n\noperatornamedim_mathcalDP(n) = (n-1)^2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialdoublystochastic.html#ManifoldsBase.project-Tuple{Manifolds.AbstractMultinomialDoublyStochastic, Any}","page":"Multinomial doubly stochastic matrices","title":"ManifoldsBase.project","text":"project(\n M::AbstractMultinomialDoublyStochastic,\n p;\n maxiter = 100,\n tolerance = eps(eltype(p))\n)\n\nproject a matrix p with positive entries applying Sinkhorn's algorithm. Note that this projct method – different from the usual case, accepts keywords.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialdoublystochastic.html#ManifoldsBase.project-Tuple{MultinomialDoubleStochastic, Any, Any}","page":"Multinomial doubly stochastic matrices","title":"ManifoldsBase.project","text":"project(M::MultinomialDoubleStochastic{n}, p, Y) where {n}\n\nProject Y onto the tangent space at p on the MultinomialDoubleStochastic M, return the result in X. The formula reads\n\n operatornameproj_p(Y) = Y - (αmathbf1_n^mathrmT + mathbf1_nβ^mathrmT) p\n\nwhere denotes the Hadamard or elementwise product and mathbb1_n is the vector of length n containing ones. The two vectors αβ ℝ^nn are computed as a solution (typically using the left pseudo inverse) of\n\n beginpmatrix I_n pp^mathrmT I_n endpmatrix\n beginpmatrix α βendpmatrix\n =\n beginpmatrix Ymathbf1Y^mathrmTmathbf1endpmatrix\n\nwhere I_n is the nn unit matrix and mathbf1_n is the vector of length n containing ones.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialdoublystochastic.html#ManifoldsBase.retract-Tuple{MultinomialDoubleStochastic, Any, Any, ProjectionRetraction}","page":"Multinomial doubly stochastic matrices","title":"ManifoldsBase.retract","text":"retract(M::MultinomialDoubleStochastic, p, X, ::ProjectionRetraction)\n\ncompute a projection based retraction by projecting podotexp(Xp) back onto the manifold, where are elementwise multiplication and division, respectively. Similarly, exp refers to the elementwise exponentiation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialdoublystochastic.html#Literature","page":"Multinomial doubly stochastic matrices","title":"Literature","text":"","category":"section"},{"location":"manifolds/product.html#ProductManifoldSection","page":"Product manifold","title":"Product manifold","text":"","category":"section"},{"location":"manifolds/product.html","page":"Product manifold","title":"Product manifold","text":"Product manifold mathcal M = mathcalM_1 mathcalM_2 mathcalM_n of manifolds mathcalM_1 mathcalM_2 mathcalM_n. Points on the product manifold can be constructed using ProductRepr with canonical projections Π_i mathcalM mathcalM_i for i 1 2 n provided by submanifold_component.","category":"page"},{"location":"manifolds/product.html","page":"Product manifold","title":"Product manifold","text":"Modules = [Manifolds]\nPages = [\"manifolds/ProductManifold.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/product.html#Manifolds.InverseProductRetraction","page":"Product manifold","title":"Manifolds.InverseProductRetraction","text":"InverseProductRetraction(retractions::AbstractInverseRetractionMethod...)\n\nProduct inverse retraction of inverse retractions. Works on ProductManifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/product.html#Manifolds.ProductBasisData","page":"Product manifold","title":"Manifolds.ProductBasisData","text":"ProductBasisData\n\nA typed tuple to store tuples of data of stored/precomputed bases for a ProductManifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/product.html#Manifolds.ProductFVectorDistribution","page":"Product manifold","title":"Manifolds.ProductFVectorDistribution","text":"ProductFVectorDistribution([type::VectorBundleFibers], [x], distrs...)\n\nGenerates a random vector at point x from vector space (a fiber of a tangent bundle) of type type using the product distribution of given distributions.\n\nVector space type and x can be automatically inferred from distributions distrs.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/product.html#Manifolds.ProductManifold","page":"Product manifold","title":"Manifolds.ProductManifold","text":"ProductManifold{𝔽,TM<:Tuple} <: AbstractManifold{𝔽}\n\nProduct manifold M_1 M_2 M_n with product geometry.\n\nConstructor\n\nProductManifold(M_1, M_2, ..., M_n)\n\ngenerates the product manifold M_1 M_2 M_n. Alternatively, the same manifold can be contructed using the × operator: M_1 × M_2 × M_3.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/product.html#Manifolds.ProductMetric","page":"Product manifold","title":"Manifolds.ProductMetric","text":"ProductMetric <: AbstractMetric\n\nA type to represent the product of metrics for a ProductManifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/product.html#Manifolds.ProductPointDistribution","page":"Product manifold","title":"Manifolds.ProductPointDistribution","text":"ProductPointDistribution(M::ProductManifold, distributions)\n\nProduct distribution on manifold M, combined from distributions.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/product.html#Manifolds.ProductRetraction","page":"Product manifold","title":"Manifolds.ProductRetraction","text":"ProductRetraction(retractions::AbstractRetractionMethod...)\n\nProduct retraction of retractions. Works on ProductManifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/product.html#Manifolds.ProductVectorTransport","page":"Product manifold","title":"Manifolds.ProductVectorTransport","text":"ProductVectorTransport(methods::AbstractVectorTransportMethod...)\n\nProduct vector transport type of methods. Works on ProductManifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/product.html#Base.exp-Tuple{ProductManifold, Vararg{Any}}","page":"Product manifold","title":"Base.exp","text":"exp(M::ProductManifold, p, X)\n\ncompute the exponential map from p in the direction of X on the ProductManifold M, which is the elementwise exponential map on the internal manifolds that build M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Base.getindex-Tuple{ProductManifold, Integer}","page":"Product manifold","title":"Base.getindex","text":"getindex(M::ProductManifold, i)\nM[i]\n\naccess the ith manifold component from the ProductManifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Base.getindex-Tuple{ProductRepr, ProductManifold, Union{Colon, Integer, Val, AbstractVector}}","page":"Product manifold","title":"Base.getindex","text":"getindex(p, M::ProductManifold, i::Union{Integer,Colon,AbstractVector})\np[M::ProductManifold, i]\n\nAccess the element(s) at index i of a point p on a ProductManifold M by linear indexing. See also Array Indexing in Julia.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Base.log-Tuple{ProductManifold, Vararg{Any}}","page":"Product manifold","title":"Base.log","text":"log(M::ProductManifold, p, q)\n\nCompute the logarithmic map from p to q on the ProductManifold M, which can be computed using the logarithmic maps of the manifolds elementwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Base.rand-Tuple{ProductManifold}","page":"Product manifold","title":"Base.rand","text":"rand(M::ProductManifold; parts_kwargs = map(_ -> (;), M.manifolds))\n\nReturn a random point on ProductManifold M. parts_kwargs is a tuple of keyword arguments for rand on each manifold in M.manifolds.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Base.setindex!-Tuple{Union{ProductRepr, ArrayPartition}, Any, ProductManifold, Union{Colon, Integer, Val, AbstractVector}}","page":"Product manifold","title":"Base.setindex!","text":"setindex!(q, p, M::ProductManifold, i::Union{Integer,Colon,AbstractVector})\nq[M::ProductManifold,i...] = p\n\nset the element [i...] of a point q on a ProductManifold by linear indexing to q. See also Array Indexing in Julia.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#LinearAlgebra.cross-Tuple{Vararg{AbstractManifold}}","page":"Product manifold","title":"LinearAlgebra.cross","text":"cross(M, N)\ncross(M1, M2, M3,...)\n\nReturn the ProductManifold For two AbstractManifolds M and N, where for the case that one of them is a ProductManifold itself, the other is either prepended (if N is a product) or appenden (if M) is. If both are product manifold, they are combined into one product manifold, keeping the order.\n\nFor the case that more than one is a product manifold of these is build with the same approach as above\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#LinearAlgebra.norm-Tuple{ProductManifold, Any, Any}","page":"Product manifold","title":"LinearAlgebra.norm","text":"norm(M::ProductManifold, p, X)\n\nCompute the norm of X from the tangent space of p on the ProductManifold, i.e. from the element wise norms the 2-norm is computed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Manifolds.flat-Tuple{ProductManifold, Vararg{Any}}","page":"Product manifold","title":"Manifolds.flat","text":"flat(M::ProductManifold, p, X::FVector{TangentSpaceType})\n\nuse the musical isomorphism to transform the tangent vector X from the tangent space at p on the ProductManifold M to a cotangent vector. This can be done elementwise for every entry of X (with respect to the corresponding entry in p) separately.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Manifolds.number_of_components-Union{Tuple{ProductManifold{𝔽, <:Tuple{Vararg{Any, N}}}}, Tuple{N}, Tuple{𝔽}} where {𝔽, N}","page":"Product manifold","title":"Manifolds.number_of_components","text":"number_of_components(M::ProductManifold{<:NTuple{N,Any}}) where {N}\n\nCalculate the number of manifolds multiplied in the given ProductManifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Manifolds.sharp-Tuple{ProductManifold, Vararg{Any}}","page":"Product manifold","title":"Manifolds.sharp","text":"sharp(M::ProductManifold, p, ξ::FVector{CotangentSpaceType})\n\nUse the musical isomorphism to transform the cotangent vector ξ from the tangent space at p on the ProductManifold M to a tangent vector. This can be done elementwise for every entry of ξ (and p) separately\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Manifolds.submanifold-Tuple{ProductManifold, Integer}","page":"Product manifold","title":"Manifolds.submanifold","text":"submanifold(M::ProductManifold, i::Integer)\n\nExtract the ith factor of the product manifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#Manifolds.submanifold-Tuple{ProductManifold, Val}","page":"Product manifold","title":"Manifolds.submanifold","text":"submanifold(M::ProductManifold, i::Val)\nsubmanifold(M::ProductManifold, i::AbstractVector)\n\nExtract the factor of the product manifold M indicated by indices in i. For example, for i equal to Val((1, 3)) the product manifold constructed from the first and the third factor is returned.\n\nThe version with AbstractVector is not type-stable, for better preformance use Val.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.change_metric-Tuple{ProductManifold, AbstractMetric, Any, Any}","page":"Product manifold","title":"ManifoldsBase.change_metric","text":"change_metric(M::ProductManifold, ::AbstractMetric, p, X)\n\nSince the metric on a product manifold decouples, the change of metric can be done elementwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.change_representer-Tuple{ProductManifold, AbstractMetric, Any, Any}","page":"Product manifold","title":"ManifoldsBase.change_representer","text":"change_representer(M::ProductManifold, ::AbstractMetric, p, X)\n\nSince the metric on a product manifold decouples, the change of a representer can be done elementwise\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.check_point-Tuple{ProductManifold, Union{ProductRepr, ArrayPartition}}","page":"Product manifold","title":"ManifoldsBase.check_point","text":"check_point(M::ProductManifold, p; kwargs...)\n\nCheck whether p is a valid point on the ProductManifold M. If p is not a point on M a CompositeManifoldError.consisting of all error messages of the components, for which the tests fail is returned.\n\nThe tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.check_size-Tuple{ProductManifold, Union{ProductRepr, ArrayPartition}}","page":"Product manifold","title":"ManifoldsBase.check_size","text":"check_size(M::ProductManifold, p; kwargs...)\n\nCheck whether p is of valid size on the ProductManifold M. If p has components of wrong size a CompositeManifoldError.consisting of all error messages of the components, for which the tests fail is returned.\n\nThe tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.check_vector-Tuple{ProductManifold, Union{ProductRepr, ArrayPartition}, Union{ProductRepr, ArrayPartition}}","page":"Product manifold","title":"ManifoldsBase.check_vector","text":"check_vector(M::ProductManifold, p, X; kwargs... )\n\nCheck whether X is a tangent vector to p on the ProductManifold M, i.e. all projections to base manifolds must be respective tangent vectors. If X is not a tangent vector to p on M a CompositeManifoldError.consisting of all error messages of the components, for which the tests fail is returned.\n\nThe tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.distance-Tuple{ProductManifold, Any, Any}","page":"Product manifold","title":"ManifoldsBase.distance","text":"distance(M::ProductManifold, p, q)\n\nCompute the distance between two points p and q on the ProductManifold M, which is the 2-norm of the elementwise distances on the internal manifolds that build M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.get_component-Tuple{ProductManifold, Any, Any}","page":"Product manifold","title":"ManifoldsBase.get_component","text":"get_component(M::ProductManifold, p, i)\n\nGet the ith component of a point p on a ProductManifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.injectivity_radius-Tuple{ProductManifold, Vararg{Any}}","page":"Product manifold","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::ProductManifold)\ninjectivity_radius(M::ProductManifold, x)\n\nCompute the injectivity radius on the ProductManifold, which is the minimum of the factor manifolds.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.inner-Tuple{ProductManifold, Any, Any, Any}","page":"Product manifold","title":"ManifoldsBase.inner","text":"inner(M::ProductManifold, p, X, Y)\n\ncompute the inner product of two tangent vectors X, Y from the tangent space at p on the ProductManifold M, which is just the sum of the internal manifolds that build M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.inverse_retract-Tuple{ProductManifold, Any, Any, Any, Manifolds.InverseProductRetraction}","page":"Product manifold","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::ProductManifold, p, q, m::InverseProductRetraction)\n\nCompute the inverse retraction from p with respect to q on the ProductManifold M using an InverseProductRetraction, which by default encapsulates a inverse retraction for each manifold of the product. Then this method is performed elementwise, so the encapsulated inverse retraction methods have to be available per factor.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.is_flat-Tuple{ProductManifold}","page":"Product manifold","title":"ManifoldsBase.is_flat","text":"is_flat(::ProductManifold)\n\nReturn true if and only if all component manifolds of ProductManifold M are flat.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.manifold_dimension-Tuple{ProductManifold}","page":"Product manifold","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::ProductManifold)\n\nReturn the manifold dimension of the ProductManifold, which is the sum of the manifold dimensions the product is made of.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.retract-Tuple{ProductManifold, Vararg{Any}}","page":"Product manifold","title":"ManifoldsBase.retract","text":"retract(M::ProductManifold, p, X, m::ProductRetraction)\n\nCompute the retraction from p with tangent vector X on the ProductManifold M using an ProductRetraction, which by default encapsulates retractions of the base manifolds. Then this method is performed elementwise, so the encapsulated retractions method has to be one that is available on the manifolds.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.riemann_tensor-Tuple{ProductManifold, Vararg{Any, 4}}","page":"Product manifold","title":"ManifoldsBase.riemann_tensor","text":"riemann_tensor(M::ProductManifold, p, X, Y, Z)\n\nCompute the Riemann tensor at point from p with tangent vectors X, Y and Z on the ProductManifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.set_component!-Tuple{ProductManifold, Any, Any, Any}","page":"Product manifold","title":"ManifoldsBase.set_component!","text":"set_component!(M::ProductManifold, q, p, i)\n\nSet the ith component of a point q on a ProductManifold M to p, where p is a point on the AbstractManifold this factor of the product manifold consists of.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/product.html#ManifoldsBase.vector_transport_to-Tuple{ProductManifold, Any, Any, Any, ProductVectorTransport}","page":"Product manifold","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::ProductManifold, p, X, q, m::ProductVectorTransport)\n\nCompute the vector transport the tangent vector Xat p to q on the ProductManifold M using an ProductVectorTransport m. This method is performed elementwise, i.e. the method m has to be implemented on the base manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spdfixeddeterminant.html#SPDFixedDeterminantSection","page":"SPD, fixed determinant","title":"Symmetric positive definite matrices of fixed determinant","text":"","category":"section"},{"location":"manifolds/spdfixeddeterminant.html","page":"SPD, fixed determinant","title":"SPD, fixed determinant","text":"SPDFixedDeterminant","category":"page"},{"location":"manifolds/spdfixeddeterminant.html#Manifolds.SPDFixedDeterminant","page":"SPD, fixed determinant","title":"Manifolds.SPDFixedDeterminant","text":"SPDFixedDeterminant{N,D} <: AbstractDecoratorManifold{ℝ}\n\nThe manifold of symmetric positive definite matrices of fixed determinant d 0, i.e.\n\nmathcal P_d(n) =\nbigl\np ℝ^n n big a^mathrmTpa 0 text for all a ℝ^nbackslash0\n text and det(p) = d\nbigr\n\nThis manifold is modelled as a submanifold of SymmetricPositiveDefinite(n).\n\nThese matrices are sometimes also called isochoric, which refers to the interpretation of the matrix representing an ellipsoid. All ellipsoids that represent points on this manifold have the same volume.\n\nThe tangent space is modelled the same as for SymmetricPositiveDefinite(n) and consists of all symmetric matrices with zero trace\n\n T_pmathcal P_d(n) =\n bigl\n X in mathbb R^nn big X=X^mathrmT text and operatornametr(p) = 0\n bigr\n\nsince for a constant determinant we require that 0 = D\\det(p)[Z] = \\det(p)\\operatorname{tr}(p^{-1}Z) for all tangent vectors Z. Additionally we store the tangent vectors as X=p^{-1}Z, i.e. symmetric matrices.\n\nConstructor\n\nSPDFixedDeterminant(n::Int, d::Real=1.0)\n\ngenerates the manifold mathcal P_d(n) subset mathcal P(n) of determinant d, which defaults to 1.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/spdfixeddeterminant.html","page":"SPD, fixed determinant","title":"SPD, fixed determinant","text":"This manifold can is a submanifold of the symmetric positive definite matrices and hence inherits most properties therefrom.","category":"page"},{"location":"manifolds/spdfixeddeterminant.html","page":"SPD, fixed determinant","title":"SPD, fixed determinant","text":"The differences are the functions","category":"page"},{"location":"manifolds/spdfixeddeterminant.html","page":"SPD, fixed determinant","title":"SPD, fixed determinant","text":"Modules = [Manifolds]\nPages = [\"manifolds/SPDFixedDeterminant.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/spdfixeddeterminant.html#ManifoldsBase.check_point-Union{Tuple{n}, Tuple{SPDFixedDeterminant{n}, Any}} where n","page":"SPD, fixed determinant","title":"ManifoldsBase.check_point","text":"check_point(M::SPDFixedDeterminant{n}, p; kwargs...)\n\nCheck whether p is a valid manifold point on the SPDFixedDeterminant(n,d) M, i.e. whether p is a SymmetricPositiveDefinite matrix of size (n, n)\n\nwith determinant det(p) =M.d.\n\nThe tolerance for the determinant of p can be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spdfixeddeterminant.html#ManifoldsBase.check_vector-Tuple{SPDFixedDeterminant, Any, Any}","page":"SPD, fixed determinant","title":"ManifoldsBase.check_vector","text":"check_vector(M::SPDFixedDeterminant, p, X; kwargs... )\n\nCheck whether X is a tangent vector to manifold point p on the SPDFixedDeterminant M, i.e. X has to be a tangent vector on SymmetricPositiveDefinite, so a symmetric matrix, and additionally fulfill operatornametr(X) = 0.\n\nThe tolerance for the trace check of X can be set using kwargs..., which influences the isapprox-check.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spdfixeddeterminant.html#ManifoldsBase.project-Tuple{SPDFixedDeterminant, Any, Any}","page":"SPD, fixed determinant","title":"ManifoldsBase.project","text":"Y = project(M::SPDFixedDeterminant{n}, p, X)\nproject!(M::SPDFixedDeterminant{n}, Y, p, X)\n\nProject the symmetric matrix X onto the tangent space at p of the (sub-)manifold of s.p.d. matrices of determinant M.d (in place of Y), by setting its diagonal (and hence its trace) to zero.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spdfixeddeterminant.html#ManifoldsBase.project-Tuple{SPDFixedDeterminant, Any}","page":"SPD, fixed determinant","title":"ManifoldsBase.project","text":"q = project(M::SPDFixedDeterminant{n}, p)\nproject!(M::SPDFixedDeterminant{n}, q, p)\n\nProject the symmetric positive definite (s.p.d.) matrix p from the embedding onto the (sub-)manifold of s.p.d. matrices of determinant M.d (in place of q).\n\nThe formula reads\n\nq = Bigl(fracddet(p)Bigr)^frac1np\n\n\n\n\n\n","category":"method"},{"location":"features/distributions.html#Distributions","page":"Distributions","title":"Distributions","text":"","category":"section"},{"location":"features/distributions.html","page":"Distributions","title":"Distributions","text":"The following functions and types provide support for manifold-valued and tangent space-valued distributions:","category":"page"},{"location":"features/distributions.html","page":"Distributions","title":"Distributions","text":"Modules = [Manifolds]\nPages = [\"distributions.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"features/distributions.html#Manifolds.FVectorDistribution","page":"Distributions","title":"Manifolds.FVectorDistribution","text":"FVectorDistribution{TSpace<:VectorBundleFibers, T}\n\nAn abstract distribution for vector bundle fiber-valued distributions (values from a fiber of a vector bundle at point x from the given manifold). For example used for tangent vector-valued distributions.\n\n\n\n\n\n","category":"type"},{"location":"features/distributions.html#Manifolds.FVectorSupport","page":"Distributions","title":"Manifolds.FVectorSupport","text":"FVectorSupport(space::AbstractManifold, VectorBundleFibers)\n\nValue support for vector bundle fiber-valued distributions (values from a fiber of a vector bundle at a point from the given manifold). For example used for tangent vector-valued distributions.\n\n\n\n\n\n","category":"type"},{"location":"features/distributions.html#Manifolds.FVectorvariate","page":"Distributions","title":"Manifolds.FVectorvariate","text":"FVectorvariate\n\nStructure that subtypes VariateForm, indicating that a single sample is a vector from a fiber of a vector bundle.\n\n\n\n\n\n","category":"type"},{"location":"features/distributions.html#Manifolds.MPointDistribution","page":"Distributions","title":"Manifolds.MPointDistribution","text":"MPointDistribution{TM<:AbstractManifold}\n\nAn abstract distribution for points on manifold of type TM.\n\n\n\n\n\n","category":"type"},{"location":"features/distributions.html#Manifolds.MPointSupport","page":"Distributions","title":"Manifolds.MPointSupport","text":"MPointSupport(M::AbstractManifold)\n\nValue support for manifold-valued distributions (values from given AbstractManifold M).\n\n\n\n\n\n","category":"type"},{"location":"features/distributions.html#Manifolds.MPointvariate","page":"Distributions","title":"Manifolds.MPointvariate","text":"MPointvariate\n\nStructure that subtypes VariateForm, indicating that a single sample is a point on a manifold.\n\n\n\n\n\n","category":"type"},{"location":"features/distributions.html#Distributions.support-Tuple{T} where T<:Manifolds.FVectorDistribution","page":"Distributions","title":"Distributions.support","text":"support(d::FVectorDistribution)\n\nGet the object of type FVectorSupport for the distribution d.\n\n\n\n\n\n","category":"method"},{"location":"features/distributions.html","page":"Distributions","title":"Distributions","text":"Modules = [Manifolds]\nPages = [\"projected_distribution.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"features/distributions.html#Manifolds.ProjectedFVectorDistribution","page":"Distributions","title":"Manifolds.ProjectedFVectorDistribution","text":"ProjectedFVectorDistribution(type::VectorBundleFibers, p, d, project!)\n\nGenerates a random vector from ambient space of manifold type.manifold at point p and projects it to vector space of type type using function project!, see project for documentation. Generated arrays are of type TResult.\n\n\n\n\n\n","category":"type"},{"location":"features/distributions.html#Manifolds.ProjectedPointDistribution","page":"Distributions","title":"Manifolds.ProjectedPointDistribution","text":"ProjectedPointDistribution(M::AbstractManifold, d, proj!, p)\n\nGenerates a random point in ambient space of M and projects it to M using function proj!. Generated arrays are of type TResult, which can be specified by providing the p argument.\n\n\n\n\n\n","category":"type"},{"location":"features/distributions.html#Manifolds.normal_tvector_distribution-Tuple{AbstractManifold, Any, Any}","page":"Distributions","title":"Manifolds.normal_tvector_distribution","text":"normal_tvector_distribution(M::Euclidean, p, σ)\n\nNormal distribution in ambient space with standard deviation σ projected to tangent space at p.\n\n\n\n\n\n","category":"method"},{"location":"features/distributions.html#Manifolds.projected_distribution","page":"Distributions","title":"Manifolds.projected_distribution","text":"projected_distribution(M::AbstractManifold, d, [p=rand(d)])\n\nWrap the standard distribution d into a manifold-valued distribution. Generated points will be of similar type to p. By default, the type is not changed.\n\n\n\n\n\n","category":"function"},{"location":"manifolds/fixedrankmatrices.html#FixedRankMatrices","page":"Fixed-rank matrices","title":"Fixed-rank matrices","text":"","category":"section"},{"location":"manifolds/fixedrankmatrices.html","page":"Fixed-rank matrices","title":"Fixed-rank matrices","text":"Modules = [Manifolds]\nPages = [\"FixedRankMatrices.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/fixedrankmatrices.html#Manifolds.FixedRankMatrices","page":"Fixed-rank matrices","title":"Manifolds.FixedRankMatrices","text":"FixedRankMatrices{m,n,k,𝔽} <: AbstractDecoratorManifold{𝔽}\n\nThe manifold of m n real-valued or complex-valued matrices of fixed rank k, i.e.\n\nbigl p 𝔽^m n big operatornamerank(p) = kbigr\n\nwhere 𝔽 ℝℂ and the rank is the number of linearly independent columns of a matrix.\n\nRepresentation with 3 matrix factors\n\nA point p mathcal M can be stored using unitary matrices U 𝔽^m k, V 𝔽^n k as well as the k singular values of p = U_p S V_p^mathrmH, where cdot^mathrmH denotes the complex conjugate transpose or Hermitian. In other words, U and V are from the manifolds Stiefel(m,k,𝔽) and Stiefel(n,k,𝔽), respectively; see SVDMPoint for details.\n\nThe tangent space T_p mathcal M at a point p mathcal M with p=U_p S V_p^mathrmH is given by\n\nT_pmathcal M = bigl U_p M V_p^mathrmH + U_X V_p^mathrmH + U_p V_X^mathrmH \n M 𝔽^k k\n U_X 𝔽^m k\n V_X 𝔽^n k\n text st \n U_p^mathrmHU_X = 0_k\n V_p^mathrmHV_X = 0_k\nbigr\n\nwhere 0_k is the k k zero matrix. See UMVTVector for details.\n\nThe (default) metric of this manifold is obtained by restricting the metric on ℝ^m n to the tangent bundle[Vandereycken2013].\n\nConstructor\n\nFixedRankMatrices(m, n, k[, field=ℝ])\n\nGenerate the manifold of m-by-n (field-valued) matrices of rank k.\n\n[Vandereycken2013]: Bart Vandereycken: \"Low-rank matrix completion by Riemannian Optimization, SIAM Journal on Optiomoization, 23(2), pp. 1214–1236, 2013. doi: 10.1137/110845768, arXiv: 1209.3834.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/fixedrankmatrices.html#Manifolds.SVDMPoint","page":"Fixed-rank matrices","title":"Manifolds.SVDMPoint","text":"SVDMPoint <: AbstractManifoldPoint\n\nA point on a certain manifold, where the data is stored in a svd like fashion, i.e. in the form USV^mathrmH, where this structure stores U, S and V^mathrmH. The storage might also be shortened to just k singular values and accordingly shortened U (columns) and V^mathrmH (rows).\n\nConstructors\n\nSVDMPoint(A) for a matrix A, stores its svd factors (i.e. implicitly k=minmn)\nSVDMPoint(S) for an SVD object, stores its svd factors (i.e. implicitly k=minmn)\nSVDMPoint(U,S,Vt) for the svd factors to initialize the SVDMPoint(i.e. implicitlyk=\\min\\{m,n\\}`)\nSVDMPoint(A,k) for a matrix A, stores its svd factors shortened to the best rank k approximation\nSVDMPoint(S,k) for an SVD object, stores its svd factors shortened to the best rank k approximation\nSVDMPoint(U,S,Vt,k) for the svd factors to initialize the SVDMPoint, stores its svd factors shortened to the best rank k approximation\n\n\n\n\n\n","category":"type"},{"location":"manifolds/fixedrankmatrices.html#Manifolds.UMVTVector","page":"Fixed-rank matrices","title":"Manifolds.UMVTVector","text":"UMVTVector <: TVector\n\nA tangent vector that can be described as a product U_p M V_p^mathrmH + U_X V_p^mathrmH + U_p V_X^mathrmH, where X = U_X S V_X^mathrmH is its base point, see for example FixedRankMatrices.\n\nThe base point p is required for example embedding this point, but it is not stored. The fields of thie tangent vector are U for U_X, M and Vt to store V_X^mathrmH\n\nConstructors\n\nUMVTVector(U,M,Vt) store umv factors to initialize the UMVTVector\nUMVTVector(U,M,Vt,k) store the umv factors after shortening them down to inner dimensions k.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/fixedrankmatrices.html#Base.rand-Tuple{FixedRankMatrices}","page":"Fixed-rank matrices","title":"Base.rand","text":"Random.rand(M::FixedRankMatrices; vector_at=nothing, kwargs...)\n\nIf vector_at is nothing, return a random point on the FixedRankMatrices manifold. The orthogonal matrices are sampled from the Stiefel manifold and the singular values are sampled uniformly at random.\n\nIf vector_at is not nothing, generate a random tangent vector in the tangent space of the point vector_at on the FixedRankMatrices manifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldDiff.riemannian_Hessian-Tuple{FixedRankMatrices, Vararg{Any, 4}}","page":"Fixed-rank matrices","title":"ManifoldDiff.riemannian_Hessian","text":"riemannian_Hessian(M::FixedRankMatrices, p, g, H, X)\n\nThe Riemannian Hessian can be computed as stated in Remark 4.1 [Ngu23] or Section 2.3 [Van13], that B. Vandereycken adopted for Manopt (Matlab).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.check_point-Union{Tuple{k}, Tuple{n}, Tuple{m}, Tuple{FixedRankMatrices{m, n, k}, Any}} where {m, n, k}","page":"Fixed-rank matrices","title":"ManifoldsBase.check_point","text":"check_point(M::FixedRankMatrices{m,n,k}, p; kwargs...)\n\nCheck whether the matrix or SVDMPoint x ids a valid point on the FixedRankMatrices{m,n,k,𝔽} M, i.e. is an m-byn matrix of rank k. For the SVDMPoint the internal representation also has to have the right shape, i.e. p.U and p.Vt have to be unitary. The keyword arguments are passed to the rank function that verifies the rank of p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.check_vector-Union{Tuple{k}, Tuple{n}, Tuple{m}, Tuple{FixedRankMatrices{m, n, k}, SVDMPoint, UMVTVector}} where {m, n, k}","page":"Fixed-rank matrices","title":"ManifoldsBase.check_vector","text":"check_vector(M:FixedRankMatrices{m,n,k}, p, X; kwargs...)\n\nCheck whether the tangent UMVTVector X is from the tangent space of the SVDMPoint p on the FixedRankMatrices M, i.e. that v.U and v.Vt are (columnwise) orthogonal to x.U and x.Vt, respectively, and its dimensions are consistent with p and X.M, i.e. correspond to m-by-n matrices of rank k.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.default_inverse_retraction_method-Tuple{FixedRankMatrices}","page":"Fixed-rank matrices","title":"ManifoldsBase.default_inverse_retraction_method","text":"default_inverse_retraction_method(M::FixedRankMatrices)\n\nReturn PolarInverseRetraction as the default inverse retraction for the FixedRankMatrices manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.default_retraction_method-Tuple{FixedRankMatrices}","page":"Fixed-rank matrices","title":"ManifoldsBase.default_retraction_method","text":"default_retraction_method(M::FixedRankMatrices)\n\nReturn PolarRetraction as the default retraction for the FixedRankMatrices manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.default_vector_transport_method-Tuple{FixedRankMatrices}","page":"Fixed-rank matrices","title":"ManifoldsBase.default_vector_transport_method","text":"default_vector_transport_method(M::FixedRankMatrices)\n\nReturn the ProjectionTransport as the default vector transport method for the FixedRankMatrices manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.embed-Tuple{FixedRankMatrices, SVDMPoint, UMVTVector}","page":"Fixed-rank matrices","title":"ManifoldsBase.embed","text":"embed(M::FixedRankMatrices, p, X)\n\nEmbed the tangent vector X at point p in M from its UMVTVector representation into the set of mn matrices.\n\nThe formula reads\n\nU_pMV_p^mathrmH + U_XV_p^mathrmH + U_pV_X^mathrmH\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.embed-Tuple{FixedRankMatrices, SVDMPoint}","page":"Fixed-rank matrices","title":"ManifoldsBase.embed","text":"embed(::FixedRankMatrices, p::SVDMPoint)\n\nEmbed the point p from its SVDMPoint representation into the set of mn matrices by computing USV^mathrmH.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.injectivity_radius-Union{Tuple{FixedRankMatrices{m, n, k}}, Tuple{k}, Tuple{n}, Tuple{m}} where {m, n, k}","page":"Fixed-rank matrices","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(::FixedRankMatrices)\n\nReturn the incjectivity radius of the manifold of FixedRankMatrices, i.e. 0. See [HosseiniUschmajew2017].\n\n[HosseiniUschmajew2017]: S. Hosseini and A. Uschmajew, “A Riemannian Gradient Sampling Algorithm for Nonsmooth Optimization on Manifolds,” SIAM J. Optim., vol. 27, no. 1, pp. 173–189, Jan. 2017, doi: 10.1137/16M1069298.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.inner-Tuple{FixedRankMatrices, SVDMPoint, UMVTVector, UMVTVector}","page":"Fixed-rank matrices","title":"ManifoldsBase.inner","text":"inner(M::FixedRankMatrices, p::SVDMPoint, X::UMVTVector, Y::UMVTVector)\n\nCompute the inner product of X and Y in the tangent space of p on the FixedRankMatrices M, which is inherited from the embedding, i.e. can be computed using dot on the elements (U, Vt, M) of X and Y.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.is_flat-Tuple{FixedRankMatrices}","page":"Fixed-rank matrices","title":"ManifoldsBase.is_flat","text":"is_flat(::FixedRankMatrices)\n\nReturn false. FixedRankMatrices is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.manifold_dimension-Union{Tuple{FixedRankMatrices{m, n, k, 𝔽}}, Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{m}} where {m, n, k, 𝔽}","page":"Fixed-rank matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::FixedRankMatrices{m,n,k,𝔽})\n\nReturn the manifold dimension for the 𝔽-valued FixedRankMatrices M of dimension mxn of rank k, namely\n\ndim(mathcal M) = k(m + n - k) dim_ℝ 𝔽\n\nwhere dim_ℝ 𝔽 is the real_dimension of 𝔽.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.project-Tuple{FixedRankMatrices, Any, Any}","page":"Fixed-rank matrices","title":"ManifoldsBase.project","text":"project(M, p, A)\n\nProject the matrix A ℝ^mn or from the embedding the tangent space at p on the FixedRankMatrices M, further decomposing the result into X=UMV^mathrmH, i.e. a UMVTVector.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.representation_size-Union{Tuple{FixedRankMatrices{m, n}}, Tuple{n}, Tuple{m}} where {m, n}","page":"Fixed-rank matrices","title":"ManifoldsBase.representation_size","text":"representation_size(M::FixedRankMatrices{m,n,k})\n\nReturn the element size of a point on the FixedRankMatrices M, i.e. the size of matrices on this manifold (mn).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.retract-Tuple{FixedRankMatrices, Any, Any, PolarRetraction}","page":"Fixed-rank matrices","title":"ManifoldsBase.retract","text":"retract(M, p, X, ::PolarRetraction)\n\nCompute an SVD-based retraction on the FixedRankMatrices M by computing\n\n q = U_kS_kV_k^mathrmH\n\nwhere U_k S_k V_k^mathrmH is the shortened singular value decomposition USV^mathrmH=p+X, in the sense that S_k is the diagonal matrix of size k k with the k largest singular values and U and V are shortened accordingly.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.vector_transport_to!-Tuple{FixedRankMatrices, Any, Any, Any, ProjectionTransport}","page":"Fixed-rank matrices","title":"ManifoldsBase.vector_transport_to!","text":"vector_transport_to(M::FixedRankMatrices, p, X, q, ::ProjectionTransport)\n\nCompute the vector transport of the tangent vector X at p to q, using the project of X to q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#ManifoldsBase.zero_vector-Union{Tuple{k}, Tuple{n}, Tuple{m}, Tuple{FixedRankMatrices{m, n, k}, SVDMPoint}} where {m, n, k}","page":"Fixed-rank matrices","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::FixedRankMatrices, p::SVDMPoint)\n\nReturn a UMVTVector representing the zero tangent vector in the tangent space of p on the FixedRankMatrices M, for example all three elements of the resulting structure are zero matrices.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/fixedrankmatrices.html#Literature","page":"Fixed-rank matrices","title":"Literature","text":"","category":"section"},{"location":"manifolds/fixedrankmatrices.html","page":"Fixed-rank matrices","title":"Fixed-rank matrices","text":"Pages = [\"manifolds/fixedrankmatrices.md\"]\nCanonical=false","category":"page"},{"location":"manifolds/stiefel.html#Stiefel","page":"Stiefel","title":"Stiefel","text":"","category":"section"},{"location":"manifolds/stiefel.html#Common-and-metric-independent-functions","page":"Stiefel","title":"Common and metric independent functions","text":"","category":"section"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"Modules = [Manifolds]\nPages = [\"manifolds/Stiefel.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/stiefel.html#Manifolds.Stiefel","page":"Stiefel","title":"Manifolds.Stiefel","text":"Stiefel{n,k,𝔽} <: AbstractDecoratorManifold{𝔽}\n\nThe Stiefel manifold consists of all n k, n k unitary matrices, i.e.\n\noperatornameSt(nk) = bigl p 𝔽^n k big p^mathrmHp = I_k bigr\n\nwhere 𝔽 ℝ ℂ, cdot^mathrmH denotes the complex conjugate transpose or Hermitian, and I_k ℝ^k k denotes the k k identity matrix.\n\nThe tangent space at a point p mathcal M is given by\n\nT_p mathcal M = X 𝔽^n k p^mathrmHX + overlineX^mathrmHp = 0_k\n\nwhere 0_k is the k k zero matrix and overlinecdot the (elementwise) complex conjugate.\n\nThis manifold is modeled as an embedded manifold to the Euclidean, i.e. several functions like the inner product and the zero_vector are inherited from the embedding.\n\nThe manifold is named after Eduard L. Stiefel (1909–1978).\n\nConstructor\n\nStiefel(n, k, field = ℝ)\n\nGenerate the (real-valued) Stiefel manifold of n k dimensional orthonormal matrices.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/stiefel.html#Base.rand-Tuple{Stiefel}","page":"Stiefel","title":"Base.rand","text":"rand(::Stiefel; vector_at=nothing, σ::Real=1.0)\n\nWhen vector_at is nothing, return a random (Gaussian) point x on the Stiefel manifold M by generating a (Gaussian) matrix with standard deviation σ and return the orthogonalized version, i.e. return the Q component of the QR decomposition of the random matrix of size nk.\n\nWhen vector_at is not nothing, return a (Gaussian) random vector from the tangent space T_vector_atmathrmSt(nk) with mean zero and standard deviation σ by projecting a random Matrix onto the tangent vector at vector_at.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#Manifolds.uniform_distribution-Union{Tuple{k}, Tuple{n}, Tuple{Stiefel{n, k, ℝ}, Any}} where {n, k}","page":"Stiefel","title":"Manifolds.uniform_distribution","text":"uniform_distribution(M::Stiefel{n,k,ℝ}, p)\n\nUniform distribution on given (real-valued) Stiefel M. Specifically, this is the normalized Haar and Hausdorff measure on M. Generated points will be of similar type as p.\n\nThe implementation is based on Section 2.5.1 in [Chikuse2003]; see also Theorem 2.2.1(iii) in [Chikuse2003].\n\n[Chikuse2003]: Y. Chikuse: \"Statistics on Special Manifolds\", Springer New York, 2003, doi: 10.1007/978-0-387-21540-2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.change_metric-Tuple{Stiefel, EuclideanMetric, Any, Any}","page":"Stiefel","title":"ManifoldsBase.change_metric","text":"change_metric(M::Stiefel, ::EuclideanMetric, p X)\n\nChange X to the corresponding vector with respect to the metric of the Stiefel M, which is just the identity, since the manifold is isometrically embedded.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.change_representer-Tuple{Stiefel, EuclideanMetric, Any, Any}","page":"Stiefel","title":"ManifoldsBase.change_representer","text":"change_representer(M::Stiefel, ::EuclideanMetric, p, X)\n\nChange X to the corresponding representer of a cotangent vector at p. Since the Stiefel manifold M, is isometrically embedded, this is the identity\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{Stiefel{n, k, 𝔽}, Any}} where {n, k, 𝔽}","page":"Stiefel","title":"ManifoldsBase.check_point","text":"check_point(M::Stiefel, p; kwargs...)\n\nCheck whether p is a valid point on the Stiefel M=operatornameSt(nk), i.e. that it has the right AbstractNumbers type and p^mathrmHp is (approximately) the identity, where cdot^mathrmH is the complex conjugate transpose. The settings for approximately can be set with kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.check_vector-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{Stiefel{n, k, 𝔽}, Any, Any}} where {n, k, 𝔽}","page":"Stiefel","title":"ManifoldsBase.check_vector","text":"check_vector(M::Stiefel, p, X; kwargs...)\n\nChecks whether X is a valid tangent vector at p on the Stiefel M=operatornameSt(nk), i.e. the AbstractNumbers fits and it (approximately) holds that p^mathrmHX + overlineX^mathrmHp = 0, where cdot^mathrmH denotes the Hermitian and overlinecdot the (elementwise) complex conjugate. The settings for approximately can be set with kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.default_inverse_retraction_method-Tuple{Stiefel}","page":"Stiefel","title":"ManifoldsBase.default_inverse_retraction_method","text":"default_inverse_retraction_method(M::Stiefel)\n\nReturn PolarInverseRetraction as the default inverse retraction for the Stiefel manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.default_retraction_method-Tuple{Stiefel}","page":"Stiefel","title":"ManifoldsBase.default_retraction_method","text":"default_retraction_method(M::Stiefel)\n\nReturn PolarRetraction as the default retraction for the Stiefel manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.default_vector_transport_method-Tuple{Stiefel}","page":"Stiefel","title":"ManifoldsBase.default_vector_transport_method","text":"default_vector_transport_method(M::Stiefel)\n\nReturn the DifferentiatedRetractionVectorTransport of the [PolarRetraction](PolarRetraction as the default vector transport method for the Stiefel manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.inverse_retract-Tuple{Stiefel, Any, Any, PolarInverseRetraction}","page":"Stiefel","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::Stiefel, p, q, ::PolarInverseRetraction)\n\nCompute the inverse retraction based on a singular value decomposition for two points p, q on the Stiefel manifold M. This follows the folloing approach: From the Polar retraction we know that\n\noperatornameretr_p^-1q = qs - t\n\nif such a symmetric positive definite k k matrix exists. Since qs - t is also a tangent vector at p we obtain\n\np^mathrmHqs + s(p^mathrmHq)^mathrmH + 2I_k = 0\n\nwhich can either be solved by a Lyapunov approach or a continuous-time algebraic Riccati equation.\n\nThis implementation follows the Lyapunov approach.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.inverse_retract-Tuple{Stiefel, Any, Any, QRInverseRetraction}","page":"Stiefel","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::Stiefel, p, q, ::QRInverseRetraction)\n\nCompute the inverse retraction based on a qr decomposition for two points p, q on the Stiefel manifold M and return the resulting tangent vector in X. The computation follows Algorithm 1 in [KanekoFioriTanaka2013].\n\n[KanekoFioriTanaka2013]: T. Kaneko, S. Fiori, T. Tanaka: \"Empirical Arithmetic Averaging over the Compact Stiefel AbstractManifold\", IEEE Transactions on Signal Processing, 2013, doi: 10.1109/TSP.2012.2226167.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.is_flat-Tuple{Stiefel}","page":"Stiefel","title":"ManifoldsBase.is_flat","text":"is_flat(M::Stiefel)\n\nReturn true if Stiefel M is one-dimensional.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.manifold_dimension-Union{Tuple{Stiefel{n, k, ℝ}}, Tuple{k}, Tuple{n}} where {n, k}","page":"Stiefel","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::Stiefel)\n\nReturn the dimension of the Stiefel manifold M=operatornameSt(nk𝔽). The dimension is given by\n\nbeginaligned\ndim mathrmSt(n k ℝ) = nk - frac12k(k+1)\ndim mathrmSt(n k ℂ) = 2nk - k^2\ndim mathrmSt(n k ℍ) = 4nk - k(2k-1)\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.representation_size-Union{Tuple{Stiefel{n, k}}, Tuple{k}, Tuple{n}} where {n, k}","page":"Stiefel","title":"ManifoldsBase.representation_size","text":"representation_size(M::Stiefel)\n\nReturns the representation size of the Stiefel M=operatornameSt(nk), i.e. (n,k), which is the matrix dimensions.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.retract-Tuple{Stiefel, Any, Any, CayleyRetraction}","page":"Stiefel","title":"ManifoldsBase.retract","text":"retract(::Stiefel, p, X, ::CayleyRetraction)\n\nCompute the retraction on the Stiefel that is based on the Cayley transform[Zhu2017]. Using\n\n W_pX = operatornameP_pXp^mathrmH - pX^mathrmHoperatornameP_p\n quadtextwhere\n operatornameP_p = I - frac12pp^mathrmH\n\nthe formula reads\n\n operatornameretr_pX = Bigl(I - frac12W_pXBigr)^-1Bigl(I + frac12W_pXBigr)p\n\nIt is implemented as the case m=1 of the PadeRetraction.\n\n[Zhu2017]: X. Zhu: A Riemannian conjugate gradient method for optimizazion on the Stiefel manifold, Computational Optimization and Applications 67(1), pp. 73–110, 2017. doi 10.1007/s10589-016-9883-4.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.retract-Tuple{Stiefel, Any, Any, PadeRetraction}","page":"Stiefel","title":"ManifoldsBase.retract","text":"retract(M::Stiefel, p, X, ::PadeRetraction{m})\n\nCompute the retraction on the Stiefel manifold M based on the Padé approximation of order m[ZhuDuan2018]. Let p_m and q_m be defined for any matrix A ℝ^nx as\n\n p_m(A) = sum_k=0^m frac(2m-k)m(2m)(m-k)fracA^kk\n\nand\n\n q_m(A) = sum_k=0^m frac(2m-k)m(2m)(m-k)frac(-A)^kk\n\nrespectively. Then the Padé approximation (of the matrix exponential exp(A)) reads\n\n r_m(A) = q_m(A)^-1p_m(A)\n\nDefining further\n\n W_pX = operatornameP_pXp^mathrmH - pX^mathrmHoperatornameP_p\n quadtextwhere \n operatornameP_p = I - frac12pp^mathrmH\n\nthe retraction reads\n\n operatornameretr_pX = r_m(W_pX)p\n\n[ZhuDuan2018]: X. Zhu, C. Duan: On matrix exponentials and their approximations related to optimization on the Stiefel manifold, Optimizazion Letters 13(5), pp. 1069–1083, 2018. doi 10.1007/s11590-018-1341-z.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.retract-Tuple{Stiefel, Any, Any, PolarRetraction}","page":"Stiefel","title":"ManifoldsBase.retract","text":"retract(M::Stiefel, p, X, ::PolarRetraction)\n\nCompute the SVD-based retraction PolarRetraction on the Stiefel manifold M. With USV = p + X the retraction reads\n\noperatornameretr_p X = UbarV^mathrmH\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.retract-Tuple{Stiefel, Any, Any, QRRetraction}","page":"Stiefel","title":"ManifoldsBase.retract","text":"retract(M::Stiefel, p, X, ::QRRetraction)\n\nCompute the QR-based retraction QRRetraction on the Stiefel manifold M. With QR = p + X the retraction reads\n\noperatornameretr_p X = QD\n\nwhere D is a n k matrix with\n\nD = operatornamediagbigl(operatornamesgn(R_ii+05)_i=1^k bigr)\n\nwhere operatornamesgn(p) = begincases 1 text for p 0\n0 text for p = 0\n-1 text for p 0 endcases\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.vector_transport_direction-Tuple{Stiefel, Any, Any, Any, DifferentiatedRetractionVectorTransport{CayleyRetraction}}","page":"Stiefel","title":"ManifoldsBase.vector_transport_direction","text":"vector_transport_direction(::Stiefel, p, X, d, ::DifferentiatedRetractionVectorTransport{CayleyRetraction})\n\nCompute the vector transport given by the differentiated retraction of the CayleyRetraction, cf. [Zhu2017] Equation (17).\n\nThe formula reads\n\noperatornameT_pd(X) =\nBigl(I - frac12W_pdBigr)^-1W_pXBigl(I - frac12W_pdBigr)^-1p\n\nwith\n\n W_pX = operatornameP_pXp^mathrmH - pX^mathrmHoperatornameP_p\n quadtextwhere \n operatornameP_p = I - frac12pp^mathrmH\n\nSince this is the differentiated retraction as a vector transport, the result will be in the tangent space at q=operatornameretr_p(d) using the CayleyRetraction.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.vector_transport_direction-Tuple{Stiefel, Any, Any, Any, DifferentiatedRetractionVectorTransport{PolarRetraction}}","page":"Stiefel","title":"ManifoldsBase.vector_transport_direction","text":"vector_transport_direction(M::Stiefel, p, X, d, DifferentiatedRetractionVectorTransport{PolarRetraction})\n\nCompute the vector transport by computing the push forward of retract(::Stiefel, ::Any, ::Any, ::PolarRetraction) Section 3.5 of [Zhu2017]:\n\nT_pd^textPol(X) = q*Λ + (I-qq^mathrmT)X(1+d^mathrmTd)^-frac12\n\nwhere q = operatornameretr^mathrmPol_p(d), and Λ is the unique solution of the Sylvester equation\n\n Λ(I+d^mathrmTd)^frac12 + (I + d^mathrmTd)^frac12 = q^mathrmTX - X^mathrmTq\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.vector_transport_direction-Tuple{Stiefel, Any, Any, Any, DifferentiatedRetractionVectorTransport{QRRetraction}}","page":"Stiefel","title":"ManifoldsBase.vector_transport_direction","text":"vector_transport_direction(M::Stiefel, p, X, d, DifferentiatedRetractionVectorTransport{QRRetraction})\n\nCompute the vector transport by computing the push forward of the retract(::Stiefel, ::Any, ::Any, ::QRRetraction), See [AbsilMahonySepulchre2008], p. 173, or Section 3.5 of [Zhu2017].\n\nT_pd^textQR(X) = q*rho_mathrms(q^mathrmTXR^-1) + (I-qq^mathrmT)XR^-1\n\nwhere q = operatornameretr^mathrmQR_p(d), R is the R factor of the QR decomposition of p + d, and\n\nbigl( rho_mathrms(A) bigr)_ij\n= begincases\nA_ijtext if i j\n0 text if i = j\n-A_ji text if i j\nendcases\n\n[AbsilMahonySepulchre2008]: Absil, P.-A., Mahony, R. and Sepulchre R., Optimization Algorithms on Matrix Manifolds Princeton University Press, 2008, doi: 10.1515/9781400830244 open access\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.vector_transport_to-Tuple{Stiefel, Any, Any, Any, DifferentiatedRetractionVectorTransport{PolarRetraction}}","page":"Stiefel","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::Stiefel, p, X, q, DifferentiatedRetractionVectorTransport{PolarRetraction})\n\nCompute the vector transport by computing the push forward of the retract(M::Stiefel, ::Any, ::Any, ::PolarRetraction), see Section 4 of [HuangGallivanAbsil2015] or Section 3.5 of [Zhu2017]:\n\nT_qgets p^textPol(X) = q*Λ + (I-qq^mathrmT)X(1+d^mathrmTd)^-frac12\n\nwhere d = bigl( operatornameretr^mathrmPol_pbigr)^-1(q), and Λ is the unique solution of the Sylvester equation\n\n Λ(I+d^mathrmTd)^frac12 + (I + d^mathrmTd)^frac12 = q^mathrmTX - X^mathrmTq\n\n[HuangGallivanAbsil2015]: Huang, W., Gallivan, K. A., and Absil, P.-A.: A Broyden class of quasi-Newton methods for Riemannian optimization SIAM Journal of Optimization, 2015, Vol. 25, No. 3, pp. 1660–1685 doi: 10.1137/140955483 pdf: tech. report\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.vector_transport_to-Tuple{Stiefel, Any, Any, Any, DifferentiatedRetractionVectorTransport{QRRetraction}}","page":"Stiefel","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::Stiefel, p, X, q, DifferentiatedRetractionVectorTransport{QRRetraction})\n\nCompute the vector transport by computing the push forward of the retract(M::Stiefel, ::Any, ::Any, ::QRRetraction), see [AbsilMahonySepulchre2008], p. 173, or Section 3.5 of [Zhu2017].\n\nT_q gets p^textQR(X) = q*rho_mathrms(q^mathrmTXR^-1) + (I-qq^mathrmT)XR^-1\n\nwhere d = bigl(operatornameretr^mathrmQRbigr)^-1_p(q), R is the R factor of the QR decomposition of p+X, and\n\nbigl( rho_mathrms(A) bigr)_ij\n= begincases\nA_ijtext if i j\n0 text if i = j\n-A_ji text if i j\nendcases\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.vector_transport_to-Tuple{Stiefel, Any, Any, Any, ProjectionTransport}","page":"Stiefel","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::Stiefel, p, X, q, ::ProjectionTransport)\n\nCompute a vector transport by projection, i.e. project X from the tangent space at p by projection it onto the tangent space at q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#Default-metric:-the-Euclidean-metric","page":"Stiefel","title":"Default metric: the Euclidean metric","text":"","category":"section"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"The EuclideanMetric is obtained from the embedding of the Stiefel manifold in ℝ^nk.","category":"page"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"Modules = [Manifolds]\nPages = [\"manifolds/StiefelEuclideanMetric.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/stiefel.html#Base.exp-Tuple{Stiefel, Vararg{Any}}","page":"Stiefel","title":"Base.exp","text":"exp(M::Stiefel, p, X)\n\nCompute the exponential map on the Stiefel{n,k,𝔽}() manifold M emanating from p in tangent direction X.\n\nexp_p X = beginpmatrix\n pX\n endpmatrix\n operatornameExp\n left(\n beginpmatrix p^mathrmHX - X^mathrmHX\n I_n p^mathrmHXendpmatrix\n right)\nbeginpmatrix exp( -p^mathrmHX) 0_nendpmatrix\n\nwhere operatornameExp denotes matrix exponential, cdot^mathrmH denotes the complex conjugate transpose or Hermitian, and I_k and 0_k are the identity matrix and the zero matrix of dimension k k, respectively.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldDiff.riemannian_Hessian-Tuple{Stiefel, Vararg{Any, 4}}","page":"Stiefel","title":"ManifoldDiff.riemannian_Hessian","text":"riemannian_Hessian(M::Stiefel, p, G, H, X)\n\nThe Riemannian Hessian can be computed by adopting Eq. (5.6) [Ngu23], where we use for the EuclideanMetric α_0=α_1=1 in their formula. Let nabla f(p) denote the Euclidean gradient G, nabla^2 f(p)X the Euclidean Hessian H. Then the formula reads\n\n operatornameHessf(p)X\n =\n operatornameproj_T_pmathcal MBigl(\n ^2f(p)X - frac12 X bigl((f(p))^mathrmHp + p^mathrmHf(p)bigr)\n Bigr)\n\nCompared to Eq. (5.6) also the metric conversion simplifies to the identity.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.Weingarten-Tuple{Stiefel, Any, Any, Any}","page":"Stiefel","title":"ManifoldsBase.Weingarten","text":"Weingarten(M::Stiefel, p, X, V)\n\nCompute the Weingarten map mathcal W_p at p on the Stiefel M with respect to the tangent vector X in T_pmathcal M and the normal vector V in N_pmathcal M.\n\nThe formula is due to [AMT13] given by\n\nmathcal W_p(XV) = -Xp^mathrmTV - frac12pbigl(X^mathrmTV + V^mathrmTXbigr)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.get_basis-Union{Tuple{k}, Tuple{n}, Tuple{Stiefel{n, k, ℝ}, Any, DefaultOrthonormalBasis{ℝ, ManifoldsBase.TangentSpaceType}}} where {n, k}","page":"Stiefel","title":"ManifoldsBase.get_basis","text":"get_basis(M::Stiefel{n,k,ℝ}, p, B::DefaultOrthonormalBasis) where {n,k}\n\nCreate the default basis using the parametrization for any X T_pmathcal M. Set p_bot in ℝ^ntimes(n-k) the matrix such that the ntimes n matrix of the common columns p p_bot is an ONB. For any skew symmetric matrix a ℝ^ktimes k and any b ℝ^(n-k)times k the matrix\n\nX = pa + p_bot b T_pmathcal M\n\nand we can use the frac12k(k-1) + (n-k)k = nk-frac12k(k+1) entries of a and b to specify a basis for the tangent space. using unit vectors for constructing both the upper matrix of a to build a skew symmetric matrix and the matrix b, the default basis is constructed.\n\nSince p p_bot is an automorphism on ℝ^ntimes p the elements of a and b are orthonormal coordinates for the tangent space. To be precise exactly one element in the upper trangular entries of a is set to 1 its symmetric entry to -1 and we normalize with the factor frac1sqrt2 and for b one can just use unit vectors reshaped to a matrix to obtain orthonormal set of parameters.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.inverse_retract-Tuple{Stiefel, Any, Any, ProjectionInverseRetraction}","page":"Stiefel","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::Stiefel, p, q, method::ProjectionInverseRetraction)\n\nCompute a projection-based inverse retraction.\n\nThe inverse retraction is computed by projecting the logarithm map in the embedding to the tangent space at p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.project-Tuple{Stiefel, Any, Any}","page":"Stiefel","title":"ManifoldsBase.project","text":"project(M::Stiefel,p)\n\nProjects p from the embedding onto the Stiefel M, i.e. compute q as the polar decomposition of p such that q^mathrmHq is the identity, where cdot^mathrmH denotes the hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.project-Tuple{Stiefel, Vararg{Any}}","page":"Stiefel","title":"ManifoldsBase.project","text":"project(M::Stiefel, p, X)\n\nProject X onto the tangent space of p to the Stiefel manifold M. The formula reads\n\noperatornameproj_T_pmathcal M(X) = X - p operatornameSym(p^mathrmHX)\n\nwhere operatornameSym(q) is the symmetrization of q, e.g. by operatornameSym(q) = fracq^mathrmH+q2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.retract-Tuple{Stiefel, Any, Any, ProjectionRetraction}","page":"Stiefel","title":"ManifoldsBase.retract","text":"retract(M::Stiefel, p, X, method::ProjectionRetraction)\n\nCompute a projection-based retraction.\n\nThe retraction is computed by projecting the exponential map in the embedding to M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#The-canonical-metric","page":"Stiefel","title":"The canonical metric","text":"","category":"section"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"Any XT_pmathcal M, pmathcal M, can be written as","category":"page"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"X = pA + (I_n-pp^mathrmT)B\nquad\nA ℝ^pp text skew-symmetric\nquad\nB ℝ^np text arbitrary","category":"page"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"In the EuclideanMetric, the elements from A are counted twice (i.e. weighted with a factor of 2). The canonical metric avoids this.","category":"page"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"Modules = [Manifolds]\nPages = [\"manifolds/StiefelCanonicalMetric.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/stiefel.html#Manifolds.ApproximateLogarithmicMap","page":"Stiefel","title":"Manifolds.ApproximateLogarithmicMap","text":"ApproximateLogarithmicMap <: ApproximateInverseRetraction\n\nAn approximate implementation of the logarithmic map, which is an inverse_retraction. See inverse_retract(::MetricManifold{ℝ,Stiefel{n,k,ℝ},CanonicalMetric}, ::Any, ::Any, ::ApproximateLogarithmicMap) where {n,k} for a use case.\n\nFields\n\nmax_iterations – maximal number of iterations used in the approximation\ntolerance – a tolerance used as a stopping criterion\n\n\n\n\n\n","category":"type"},{"location":"manifolds/stiefel.html#Manifolds.CanonicalMetric","page":"Stiefel","title":"Manifolds.CanonicalMetric","text":"CanonicalMetric <: AbstractMetric\n\nThe Canonical Metric refers to a metric for the Stiefel manifold, see[EdelmanAriasSmith1998].\n\n[EdelmanAriasSmith1998]: Edelman, A., Ariar, T. A., Smith, S. T.: The Geometry of Algorihthms with Orthogonality Constraints, SIAM Journal on Matrix Analysis and Applications (20(2), pp. 303–353, 1998. doi: 10.1137/S0895479895290954 arxiv: 9806030\n\n\n\n\n\n","category":"type"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"Modules = [Manifolds]\nPages = [\"manifolds/StiefelCanonicalMetric.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/stiefel.html#Base.exp-Union{Tuple{k}, Tuple{n}, Tuple{MetricManifold{ℝ, Stiefel{n, k, ℝ}, CanonicalMetric}, Vararg{Any}}} where {n, k}","page":"Stiefel","title":"Base.exp","text":"q = exp(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, CanonicalMetric}, p, X)\nexp!(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, q, CanonicalMetric}, p, X)\n\nCompute the exponential map on the Stiefel(n,k) manifold with respect to the CanonicalMetric.\n\nFirst, decompose The tangent vector X into its horizontal and vertical component with respect to p, i.e.\n\nX = pp^mathrmTX + (I_n-pp^mathrmT)X\n\nwhere I_n is the ntimes n identity matrix. We introduce A=p^mathrmTX and QR = (I_n-pp^mathrmT)X the qr decomposition of the vertical component. Then using the matrix exponential operatornameExp we introduce B and C as\n\nbeginpmatrix\nBC\nendpmatrix\ncoloneqq\noperatornameExpleft(\nbeginpmatrix\nA -R^mathrmT R 0\nendpmatrix\nright)\nbeginpmatrixI_k0endpmatrix\n\nthe exponential map reads\n\nq = exp_p X = pC + QB\n\nFor more details, see [EdelmanAriasSmith1998][Zimmermann2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.inner-Union{Tuple{k}, Tuple{n}, Tuple{MetricManifold{ℝ, Stiefel{n, k, ℝ}, CanonicalMetric}, Any, Any, Any}} where {n, k}","page":"Stiefel","title":"ManifoldsBase.inner","text":"inner(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, X, CanonicalMetric}, p, X, Y)\n\nCompute the inner product on the Stiefel manifold with respect to the CanonicalMetric. The formula reads\n\ng_p(XY) = operatornametrbigl( X^mathrmT(I_n - frac12pp^mathrmT)Y bigr)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.inverse_retract-Union{Tuple{k}, Tuple{n}, Tuple{MetricManifold{ℝ, Stiefel{n, k, ℝ}, CanonicalMetric}, Any, Any, ApproximateLogarithmicMap}} where {n, k}","page":"Stiefel","title":"ManifoldsBase.inverse_retract","text":"X = inverse_retract(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, CanonicalMetric}, p, q, a::ApproximateLogarithmicMap)\ninverse_retract!(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, X, CanonicalMetric}, p, q, a::ApproximateLogarithmicMap)\n\nCompute an approximation to the logarithmic map on the Stiefel(n,k) manifold with respect to the CanonicalMetric using a matrix-algebraic based approach to an iterative inversion of the formula of the exp.\n\nThe algorithm is derived in[Zimmermann2017] and it uses the max_iterations and the tolerance field from the ApproximateLogarithmicMap.\n\n[Zimmermann2017]: Zimmermann, R.: _A matrix-algebraic algorithm for the Riemannian logarithm on the Stiefel manifold under the canoncial metric. SIAM Journal on Matrix Analysis and Applications 28(2), pp. 322-342, 2017. doi: 10.1137/16M1074485, arXiv: 1604.05054.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#The-submersion-or-normal-metric","page":"Stiefel","title":"The submersion or normal metric","text":"","category":"section"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"Modules = [Manifolds]\nPages = [\"manifolds/StiefelSubmersionMetric.jl\"]\nOrder = [:type, :function]\nPublic = true\nPrivate = false","category":"page"},{"location":"manifolds/stiefel.html#Manifolds.StiefelSubmersionMetric","page":"Stiefel","title":"Manifolds.StiefelSubmersionMetric","text":"StiefelSubmersionMetric{T<:Real} <: RiemannianMetric\n\nThe submersion (or normal) metric family on the Stiefel manifold.\n\nThe family, with a single real parameter α-1, has two special cases:\n\nα = -frac12: EuclideanMetric\nα = 0: CanonicalMetric\n\nThe family was described in [HüperMarkinaLeite2021]. This implementation follows the description in [ZimmermanHüper2022].\n\n[HüperMarkinaLeite2021]: Hüper, M., Markina, A., Leite, R. T. (2021) \"A Lagrangian approach to extremal curves on Stiefel manifolds\" Journal of Geometric Mechanics, 13(1): 55-72. doi: 10.3934/jgm.2020031\n\n[ZimmermanHüper2022]: Ralf Zimmerman and Knut Hüper. (2022). \"Computing the Riemannian logarithm on the Stiefel manifold: metrics, methods and performance.\" arXiv: 2103.12046\n\nConstructor\n\nStiefelSubmersionMetric(α)\n\nConstruct the submersion metric on the Stiefel manifold with the parameter α.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/stiefel.html#Base.exp-Union{Tuple{k}, Tuple{n}, Tuple{MetricManifold{ℝ, Stiefel{n, k, ℝ}, <:StiefelSubmersionMetric}, Vararg{Any}}} where {n, k}","page":"Stiefel","title":"Base.exp","text":"q = exp(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, <:StiefelSubmersionMetric}, p, X)\nexp!(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, q, <:StiefelSubmersionMetric}, p, X)\n\nCompute the exponential map on the Stiefel(n,k) manifold with respect to the StiefelSubmersionMetric.\n\nThe exponential map is given by\n\nexp_p X = operatornameExpbigl(\n -frac2α+1α+1 p p^mathrmT X p^mathrmT +\n X p^mathrmT - p X^mathrmT\nbigr) p operatornameExpbigl(fracalphaalpha+1 p^mathrmT Xbigr)\n\nThis implementation is based on [ZimmermanHüper2022].\n\nFor k fracn2 the exponential is computed more efficiently using StiefelFactorization.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#Base.log-Union{Tuple{k}, Tuple{n}, Tuple{MetricManifold{ℝ, Stiefel{n, k, ℝ}, <:StiefelSubmersionMetric}, Any, Any}} where {n, k}","page":"Stiefel","title":"Base.log","text":"log(M::MetricManifold{ℝ,Stiefel{n,k,ℝ},<:StiefelSubmersionMetric}, p, q; kwargs...)\n\nCompute the logarithmic map on the Stiefel(n,k) manifold with respect to the StiefelSubmersionMetric.\n\nThe logarithmic map is computed using ShootingInverseRetraction. For k lfloorfracn2rfloor, this is sped up using the k-shooting method of [ZimmermanHüper2022]. Keyword arguments are forwarded to ShootingInverseRetraction; see that documentation for details. Their defaults are:\n\nnum_transport_points=4\ntolerance=sqrt(eps())\nmax_iterations=1_000\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.inner-Union{Tuple{k}, Tuple{n}, Tuple{MetricManifold{ℝ, Stiefel{n, k, ℝ}, <:StiefelSubmersionMetric}, Any, Any, Any}} where {n, k}","page":"Stiefel","title":"ManifoldsBase.inner","text":"inner(M::MetricManifold{ℝ, Stiefel{n,k,ℝ}, X, <:StiefelSubmersionMetric}, p, X, Y)\n\nCompute the inner product on the Stiefel manifold with respect to the StiefelSubmersionMetric. The formula reads\n\ng_p(XY) = operatornametrbigl( X^mathrmT(I_n - frac2α+12(α+1)pp^mathrmT)Y bigr)\n\nwhere α is the parameter of the metric.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#ManifoldsBase.inverse_retract-Tuple{MetricManifold{ℝ, <:Stiefel, <:StiefelSubmersionMetric}, Any, Any, ShootingInverseRetraction}","page":"Stiefel","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(\n M::MetricManifold{ℝ,Stiefel{n,k,ℝ},<:StiefelSubmersionMetric},\n p,\n q,\n method::ShootingInverseRetraction,\n)\n\nCompute the inverse retraction using ShootingInverseRetraction.\n\nIn general the retraction is computed using the generic shooting method.\n\ninverse_retract(\n M::MetricManifold{ℝ,Stiefel{n,k,ℝ},<:StiefelSubmersionMetric},\n p,\n q,\n method::ShootingInverseRetraction{\n ExponentialRetraction,\n ProjectionInverseRetraction,\n <:Union{ProjectionTransport,ScaledVectorTransport{ProjectionTransport}},\n },\n)\n\nCompute the inverse retraction using ShootingInverseRetraction more efficiently.\n\nFor k fracn2 the retraction is computed more efficiently using StiefelFactorization.\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#Internal-types-and-functions","page":"Stiefel","title":"Internal types and functions","text":"","category":"section"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"Modules = [Manifolds]\nPages = [\"manifolds/StiefelSubmersionMetric.jl\"]\nOrder = [:type, :function]\nPublic = false\nPrivate = true","category":"page"},{"location":"manifolds/stiefel.html#Manifolds.StiefelFactorization","page":"Stiefel","title":"Manifolds.StiefelFactorization","text":"StiefelFactorization{UT,XT} <: AbstractManifoldPoint\n\nRepresent points (and vectors) on Stiefel(n, k) with 2k k factors.[ZimmermanHüper2022]\n\nGiven a point p mathrmSt(n k) and another matrix B ℝ^n k for k lfloorfracn2rfloor the factorization is\n\nbeginaligned\nB = UZ\nU = beginbmatrixp Qendbmatrix mathrmSt(n 2k)\nZ = beginbmatrixZ_1 Z_2endbmatrix quad Z_1Z_2 ℝ^k k\nendaligned\n\nIf B mathrmSt(n k), then Z mathrmSt(2k k). Note that not every matrix B can be factorized in this way.\n\nFor a fixed U, if r mathrmSt(n k) has the factor Z_r mathrmSt(2k k), then X_r T_r mathrmSt(n k) has the factor Z_X_r T_Z_r mathrmSt(2k k).\n\nQ is determined by choice of a second matrix A ℝ^n k with the decomposition\n\nbeginaligned\nA = UZ\nZ_1 = p^mathrmT A \nQ Z_2 = (I - p p^mathrmT) A\nendaligned\n\nwhere here Q Z_2 is the any decomposition that produces Q mathrmSt(n k), for which we choose the QR decomposition.\n\nThis factorization is useful because it is closed under addition, subtraction, scaling, projection, and the Riemannian exponential and logarithm under the StiefelSubmersionMetric. That is, if all matrices involved are factorized to have the same U, then all of these operations and any algorithm that depends only on them can be performed in terms of the 2k k matrices Z. For n k, this can be much more efficient than working with the full matrices.\n\nwarning: Warning\nThis type is intended strictly for internal use and should not be directly used.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/stiefel.html#Manifolds.stiefel_factorization-Tuple{Any, Any}","page":"Stiefel","title":"Manifolds.stiefel_factorization","text":"stiefel_factorization(p, x) -> StiefelFactorization\n\nCompute the StiefelFactorization of x relative to the point p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/stiefel.html#Literature","page":"Stiefel","title":"Literature","text":"","category":"section"},{"location":"manifolds/stiefel.html","page":"Stiefel","title":"Stiefel","text":"Pages = [\"manifolds/stiefel.md\"]\nCanonical=false","category":"page"},{"location":"manifolds/circle.html#Circle","page":"Circle","title":"Circle","text":"","category":"section"},{"location":"manifolds/circle.html","page":"Circle","title":"Circle","text":"Modules = [Manifolds]\nPages = [\"manifolds/Circle.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/circle.html#Manifolds.Circle","page":"Circle","title":"Manifolds.Circle","text":"Circle{𝔽} <: AbstractManifold{𝔽}\n\nThe circle 𝕊^1 is a manifold here represented by real-valued points in -ππ) or complex-valued points z ℂ of absolute value lvert zrvert = 1.\n\nConstructor\n\nCircle(𝔽=ℝ)\n\nGenerate the ℝ-valued Circle represented by angles, which alternatively can be set to use the AbstractNumbers 𝔽=ℂ to obtain the circle represented by ℂ-valued circle of unit numbers.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/circle.html#Base.exp-Tuple{Circle, Vararg{Any}}","page":"Circle","title":"Base.exp","text":"exp(M::Circle, p, X)\n\nCompute the exponential map on the Circle.\n\nexp_p X = (p+X)_2π\n\nwhere (cdot)_2π is the (symmetric) remainder with respect to division by 2π, i.e. in -ππ).\n\nFor the complex-valued case, the same formula as for the Sphere 𝕊^1 is applied to values in the complex plane.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#Base.log-Tuple{Circle, Vararg{Any}}","page":"Circle","title":"Base.log","text":"log(M::Circle, p, q)\n\nCompute the logarithmic map on the Circle M.\n\nlog_p q = (q-p)_2π\n\nwhere (cdot)_2π is the (symmetric) remainder with respect to division by 2π, i.e. in -ππ).\n\nFor the complex-valued case, the same formula as for the Sphere 𝕊^1 is applied to values in the complex plane.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#Base.rand-Tuple{Circle}","page":"Circle","title":"Base.rand","text":"Random.rand(M::Circle{ℝ}; vector_at = nothing, σ::Real=1.0)\n\nIf vector_at is nothing, return a random point on the Circle mathbb S^1 by picking a random element from -pipi) uniformly.\n\nIf vector_at is not nothing, return a random tangent vector from the tangent space of the point vector_at on the Circle by using a normal distribution with mean 0 and standard deviation σ.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#Manifolds.complex_dot-Tuple{Any, Any}","page":"Circle","title":"Manifolds.complex_dot","text":"complex_dot(a, b)\n\nCompute the inner product of two (complex) numbers with in the complex plane.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#Manifolds.sym_rem-Union{Tuple{N}, Tuple{N, Any}} where N<:Number","page":"Circle","title":"Manifolds.sym_rem","text":"sym_rem(x,[T=π])\n\nCompute symmetric remainder of x with respect to the interall 2*T, i.e. (x+T)%2T, where the default for T is π\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.check_point-Tuple{Circle, Vararg{Any}}","page":"Circle","title":"ManifoldsBase.check_point","text":"check_point(M::Circle, p)\n\nCheck whether p is a point on the Circle M. For the real-valued case, p is an angle and hence it checks that p -ππ). for the complex-valued case, it is a unit number, p ℂ with lvert p rvert = 1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.check_vector-Tuple{Circle{ℝ}, Vararg{Any}}","page":"Circle","title":"ManifoldsBase.check_vector","text":"check_vector(M::Circle, p, X; kwargs...)\n\nCheck whether X is a tangent vector in the tangent space of p on the Circle M. For the real-valued case represented by angles, all X are valid, since the tangent space is the whole real line. For the complex-valued case X has to lie on the line parallel to the tangent line at p in the complex plane, i.e. their inner product has to be zero.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.distance-Tuple{Circle, Vararg{Any}}","page":"Circle","title":"ManifoldsBase.distance","text":"distance(M::Circle, p, q)\n\nCompute the distance on the Circle M, which is the absolute value of the symmetric remainder of p and q for the real-valued case and the angle between both complex numbers in the Gaussian plane for the complex-valued case.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.embed-Tuple{Circle, Any, Any}","page":"Circle","title":"ManifoldsBase.embed","text":"embed(M::Circle, p, X)\n\nEmbed a tangent vector X at p on Circle M in the ambient space. It returns X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.embed-Tuple{Circle, Any}","page":"Circle","title":"ManifoldsBase.embed","text":"embed(M::Circle, p)\n\nEmbed a point p on Circle M in the ambient space. It returns p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.get_coordinates-Tuple{Circle{ℂ}, Any, Any, DefaultOrthonormalBasis{<:Any, ManifoldsBase.TangentSpaceType}}","page":"Circle","title":"ManifoldsBase.get_coordinates","text":"get_coordinates(M::Circle{ℂ}, p, X, B::DefaultOrthonormalBasis)\n\nReturn tangent vector coordinates in the Lie algebra of the Circle.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.get_vector_orthonormal-Tuple{Circle{ℂ}, Any, Any, ManifoldsBase.RealNumbers}","page":"Circle","title":"ManifoldsBase.get_vector_orthonormal","text":"get_vector(M::Circle{ℂ}, p, X, B::DefaultOrthonormalBasis)\n\nReturn tangent vector from the coordinates in the Lie algebra of the Circle.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.injectivity_radius-Tuple{Circle}","page":"Circle","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::Circle[, p])\n\nReturn the injectivity radius on the Circle M, i.e. π.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.inner-Tuple{Circle, Vararg{Any}}","page":"Circle","title":"ManifoldsBase.inner","text":"inner(M::Circle, p, X, Y)\n\nCompute the inner product of the two tangent vectors X,Y from the tangent plane at p on the Circle M using the restriction of the metric from the embedding, i.e.\n\ng_p(XY) = X*Y\n\nfor the real case and\n\ng_p(XY) = Y^mathrmTX\n\nfor the complex case interpreting complex numbers in the Gaussian plane.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.is_flat-Tuple{Circle}","page":"Circle","title":"ManifoldsBase.is_flat","text":"is_flat(::Circle)\n\nReturn true. Circle is a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.manifold_dimension-Tuple{Circle}","page":"Circle","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::Circle)\n\nReturn the dimension of the Circle M, i.e. dim(𝕊^1) = 1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.parallel_transport_to-Tuple{Circle, Any, Any, Any}","page":"Circle","title":"ManifoldsBase.parallel_transport_to","text":" parallel_transport_to(M::Circle, p, X, q)\n\nCompute the parallel transport of X from the tangent space at p to the tangent space at q on the Circle M. For the real-valued case this results in the identity. For the complex-valud case, the formula is the same as for the Sphere(1) in the complex plane.\n\nmathcal P_qp X = X - fraclog_p qX_pd^2_ℂ(pq)\nbigl(log_p q + log_q p bigr)\n\nwhere log denotes the logarithmic map on M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.project-Tuple{Circle, Any, Any}","page":"Circle","title":"ManifoldsBase.project","text":"project(M::Circle, p, X)\n\nProject a value X onto the tangent space of the point p on the Circle M.\n\nFor the real-valued case this is just the identity. For the complex valued case X is projected onto the line in the complex plane that is parallel to the tangent to p on the unit circle and contains 0.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#ManifoldsBase.project-Tuple{Circle, Any}","page":"Circle","title":"ManifoldsBase.project","text":"project(M::Circle, p)\n\nProject a point p onto the Circle M. For the real-valued case this is the remainder with respect to modulus 2π. For the complex-valued case the result is the projection of p onto the unit circle in the complex plane.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#Statistics.mean-Tuple{Circle{ℂ}, Any}","page":"Circle","title":"Statistics.mean","text":"mean(M::Circle{ℂ}, x::AbstractVector[, w::AbstractWeights])\n\nCompute the Riemannian mean of x of points on the Circle 𝕊^1, reprsented by complex numbers, i.e. embedded in the complex plane. Comuting the sum\n\ns = sum_i=1^n x_i\n\nthe mean is the angle of the complex number s, so represented in the complex plane as fracslvert s rvert, whenever s neq 0.\n\nIf the sum s=0, the mean is not unique. For example for opposite points or equally spaced angles.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/circle.html#Statistics.mean-Tuple{Circle{ℝ}, Any}","page":"Circle","title":"Statistics.mean","text":"mean(M::Circle{ℝ}, x::AbstractVector[, w::AbstractWeights])\n\nCompute the Riemannian mean of x of points on the Circle 𝕊^1, reprsented by real numbers, i.e. the angular mean\n\noperatornameatanBigl( sum_i=1^n w_isin(x_i) sum_i=1^n w_isin(x_i) Bigr)\n\n\n\n\n\n","category":"method"},{"location":"misc/about.html#About-Manifolds.jl","page":"About","title":"About Manifolds.jl","text":"","category":"section"},{"location":"misc/about.html#License","page":"About","title":"License","text":"","category":"section"},{"location":"misc/about.html","page":"About","title":"About","text":"MIT License","category":"page"},{"location":"misc/about.html#Core-Developers","page":"About","title":"Core Developers","text":"","category":"section"},{"location":"misc/about.html","page":"About","title":"About","text":"Seth Axen\nMateusz Baran\nRonny Bergmann","category":"page"},{"location":"misc/about.html#Contributors","page":"About","title":"Contributors","text":"","category":"section"},{"location":"misc/about.html","page":"About","title":"About","text":"See the GitHub contributors page.","category":"page"},{"location":"misc/about.html","page":"About","title":"About","text":"Contributions are welcome!","category":"page"},{"location":"features/testing.html#Testing","page":"Testing","title":"Testing","text":"","category":"section"},{"location":"features/testing.html","page":"Testing","title":"Testing","text":"Documentation for testing utilities for Manifolds.jl. The function test_manifold can be used to verify that your manifold correctly implements the Manifolds.jl interface. Similarly test_group and test_action can be used to verify implementation of groups and group actions.","category":"page"},{"location":"features/testing.html","page":"Testing","title":"Testing","text":"Manifolds.test_action\nManifolds.test_group\nManifolds.test_manifold\nManifolds.find_eps\nManifolds.test_parallel_transport","category":"page"},{"location":"features/testing.html#Manifolds.test_action","page":"Testing","title":"Manifolds.test_action","text":"test_action(\n A::AbstractGroupAction,\n a_pts::AbstractVector,\n m_pts::AbstractVector,\n X_pts = [];\n atol = 1e-10,\n atol_ident_compose = 0,\n test_optimal_alignment = false,\n test_mutating_group=true,\n test_mutating_action=true,\n test_diff = false,\n test_switch_direction = true,\n)\n\nTests general properties of the action A, given at least three different points that lie on it (contained in a_pts) and three different point that lie on the manifold it acts upon (contained in m_pts).\n\nArguments\n\natol_ident_compose = 0: absolute tolerance for the test that composition with identity doesn't change the group element.\n\n\n\n\n\n","category":"function"},{"location":"features/testing.html#Manifolds.test_group","page":"Testing","title":"Manifolds.test_group","text":"test_group(\n G,\n g_pts::AbstractVector,\n X_pts::AbstractVector = [],\n Xe_pts::AbstractVector = [];\n atol = 1e-10,\n test_mutating = true,\n test_exp_lie_log = true,\n test_diff = false,\n test_invariance = false,\n test_lie_bracket=false,\n test_adjoint_action=false,\n diff_convs = [(), (LeftForwardAction(),), (RightBackwardAction(),)],\n)\n\nTests general properties of the group G, given at least three different points elements of it (contained in g_pts). Optionally, specify test_diff to test differentials of translation, using X_pts, which must contain at least one tangent vector at g_pts[1], and the direction conventions specified in diff_convs. Xe_pts should contain tangent vectors at identity for testing Lie algebra operations. If the group is equipped with an invariant metric, test_invariance indicates that the invariance should be checked for the provided points.\n\n\n\n\n\n","category":"function"},{"location":"features/testing.html#Manifolds.test_manifold","page":"Testing","title":"Manifolds.test_manifold","text":"test_manifold(\n M::AbstractManifold,\n pts::AbstractVector;\n args,\n)\n\nTest general properties of manifold M, given at least three different points that lie on it (contained in pts).\n\nArguments\n\nbasis_has_specialized_diagonalizing_get = false: if true, assumes that DiagonalizingOrthonormalBasis given in basis_types has get_coordinates and get_vector that work without caching.\nbasis_types_to_from = (): basis types that will be tested based on get_coordinates and get_vector.\nbasis_types_vecs = () : basis types that will be tested based on get_vectors\ndefault_inverse_retraction_method = ManifoldsBase.LogarithmicInverseRetraction(): default method for inverse retractions (log.\ndefault_retraction_method = ManifoldsBase.ExponentialRetraction(): default method for retractions (exp).\nexp_log_atol_multiplier = 0: change absolute tolerance of exp/log tests (0 use default, i.e. deactivate atol and use rtol).\nexp_log_rtol_multiplier = 1: change the relative tolerance of exp/log tests (1 use default). This is deactivated if the exp_log_atol_multiplier is nonzero.\nexpected_dimension_type = Integer: expected type of value returned by manifold_dimension.\ninverse_retraction_methods = []: inverse retraction methods that will be tested.\nis_mutating = true: whether mutating variants of functions should be tested.\nis_point_atol_multiplier = 0: determines atol of is_point checks.\nis_tangent_atol_multiplier = 0: determines atol of is_vector checks.\nmid_point12 = test_exp_log ? shortest_geodesic(M, pts[1], pts[2], 0.5) : nothing: if not nothing, then check that mid_point(M, pts[1], pts[2]) is approximately equal to mid_point12. This is by default set to nothing if text_exp_log is set to false.\npoint_distributions = [] : point distributions to test.\nrand_tvector_atol_multiplier = 0 : chage absolute tolerance in testing random vectors (0 use default, i.e. deactivate atol and use rtol) random tangent vectors are tangent vectors.\nretraction_atol_multiplier = 0: change absolute tolerance of (inverse) retraction tests (0 use default, i.e. deactivate atol and use rtol).\nretraction_rtol_multiplier = 1: change the relative tolerance of (inverse) retraction tests (1 use default). This is deactivated if the exp_log_atol_multiplier is nonzero.\nretraction_methods = []: retraction methods that will be tested.\ntest_atlases = []: Vector or tuple of atlases that should be tested.\ntest_exp_log = true: if true, check that exp is the inverse of log.\ntest_injectivity_radius = true: whether implementation of injectivity_radius should be tested.\ntest_inplace = false : if true check if inplace variants work if they are activated, e.g. check that exp!(M, p, p, X) work if test_exp_log = true. This in general requires is_mutating to be true.\ntest_is_tangent: if true check that the default_inverse_retraction_method actually returns valid tangent vectors.\ntest_musical_isomorphisms = false : test musical isomorphisms.\ntest_mutating_rand = false : test the mutating random function for points on manifolds.\ntest_project_point = false: test projections onto the manifold.\ntest_project_tangent = false : test projections on tangent spaces.\ntest_representation_size = true : test repersentation size of points/tvectprs.\ntest_tangent_vector_broadcasting = true : test boradcasting operators on TangentSpace.\ntest_vector_spaces = true : test Vector bundle of this manifold.\ntest_default_vector_transport = false : test the default vector transport (usually parallel transport).\ntest_vee_hat = false: test vee and hat functions.\ntvector_distributions = [] : tangent vector distributions to test.\nvector_transport_methods = []: vector transport methods that should be tested.\nvector_transport_inverse_retractions = [default_inverse_retraction_method for _ in 1:length(vector_transport_methods)]` inverse retractions to use with the vector transport method (especially the differentiated ones)\nvector_transport_to = [ true for _ in 1:length(vector_transport_methods)]: whether to check the to variant of vector transport\nvector_transport_direction = [ true for _ in 1:length(vector_transport_methods)]: whether to check the direction variant of vector transport\n\n\n\n\n\n","category":"function"},{"location":"features/testing.html#Manifolds.find_eps","page":"Testing","title":"Manifolds.find_eps","text":"find_eps(x...)\n\nFind an appropriate tolerance for given points or tangent vectors, or their types.\n\n\n\n\n\n","category":"function"},{"location":"features/testing.html#Manifolds.test_parallel_transport","page":"Testing","title":"Manifolds.test_parallel_transport","text":"test_parallel_transport(M,P; along=false, to=true, diretion=true)\n\nGeneric tests for parallel transport on Mgiven at least two pointsin P.\n\nThe single functions to transport along (a curve), to (a point) or (towards a) direction are sub-tests that can be activated by the keywords arguemnts\n\n!!! Note Since the interface to specify curves is not yet provided, the along keyword does not have an effect yet\n\n\n\n\n\n","category":"function"},{"location":"misc/notation.html#Notation-overview","page":"Notation","title":"Notation overview","text":"","category":"section"},{"location":"misc/notation.html","page":"Notation","title":"Notation","text":"Since manifolds include a reasonable amount of elements and functions, the following list tries to keep an overview of used notation throughout Manifolds.jl. The order is alphabetical by name. They might be used in a plain form within the code or when referring to that code. This is for example the case with the calligraphic symbols.","category":"page"},{"location":"misc/notation.html","page":"Notation","title":"Notation","text":"Within the documented functions, the utf8 symbols are used whenever possible, as long as that renders correctly in TeX within this documentation.","category":"page"},{"location":"misc/notation.html","page":"Notation","title":"Notation","text":"Symbol Description Also used Comment\ntau_p action map by group element p mathrmL_p, mathrmR_p either left or right\noperatornameAd_p(X) adjoint action of element p of a Lie group on the element X of the corresponding Lie algebra \ntimes Cartesian product of two manifolds see ProductManifold\n^wedge (n-ary) Cartesian power of a manifold see PowerManifold\ncdot^mathrmH conjugate/Hermitian transpose \na coordinates of a point in a chart see get_parameters\nfracmathrmDmathrmdt covariant derivative of a vector field X(t) \nT^*_p mathcal M the cotangent space at p \nξ a cotangent vector from T^*_p mathcal M ξ_1 ξ_2 ηzeta sometimes written with base point ξ_p.\nmathrmdphi_p(q) Differential of a map phi mathcal M to mathcal N with respect to p at a point q. For functions of multiple variables, for example phi(p p_1) where p in mathcal M and p_1 in mathcal M_1, variable p is explicitly stated to specify with respect to which argument the differential is calculated. mathrmdphi_q, (mathrmdphi)_q, (phi_*)_q, D_pphi(q) pushes tangent vectors X in T_q mathcal M forward to mathrmdphi_p(q)X in T_phi(q) mathcal N\nn dimension (of a manifold) n_1n_2ldotsm dim(mathcal M) for the real dimension sometimes also dim_mathbb R(mathcal M)\nd(cdotcdot) (Riemannian) distance d_mathcal M(cdotcdot) \nexp_p X exponential map at p in mathcal M of a vector X in T_p mathcal M exp_p(X) \nF a fiber see VectorBundleFibers\nmathbb F a field, usually mathbb F in mathbb Rmathbb C mathbb H, i.e. the real, complex, and quaternion numbers, respectively. field a manifold or a basis is based on\ngamma a geodesic gamma_pq, gamma_pX connecting two points pq or starting in p with velocity X.\noperatornamegrad f(p) (Riemannian) gradient of function f colon mathcalM to mathbbR at p in mathcalM \nnabla f(p) (Euclidean) gradient of function f colon mathcalM to mathbbR at p in mathcalM but thought of as evaluated in the embedding G \ncirc a group operation \ncdot^mathrmH Hermitian or conjugate transposed for both complex or quaternion matrices \noperatornameHess f(p) (Riemannian) Hessian of function f colon T_pmathcalM to T_pmathcal M (i.e. the 1-1-tensor form) at p in mathcalM \nnabla^2 f(p) (Euclidean) Hessian of function f in the embedding H ","category":"page"},{"location":"misc/notation.html","page":"Notation","title":"Notation","text":"| e | identity element of a group | | | I_k | identity matrix of size ktimes k | | | k | indices | ij | | | langlecdotcdotrangle | inner product (in T_p mathcal M) | langlecdotcdotrangle_p g_p(cdotcdot) | | operatornameretr^-1_pq| an inverse retraction | | | mathfrak g | a Lie algebra | | | mathcalG | a (Lie) group | | | log_p q | logarithmic map at p in mathcal M of a point q in mathcal M | log_p(q) | | | mathcal M | a manifold | mathcal M_1 mathcal M_2ldotsmathcal N | | | N_p mathcal M | the normal space of the tangent space T_p mathcal M in some embedding mathcal E that should be clear from context | | V | a normal vector from N_p mathcal M | W | | | operatornameExp | the matrix exponential | | | operatornameLog | the matrix logarithm | | | mathcal P_qgets pX | parallel transport | | of the vector X from T_pmathcal M to T_qmathcal M | mathcal P_pYX | parallel transport in direction Y | | of the vector X from T_pmathcal M to T_qmathcal M, q = exp_pY | mathcal P_t_1gets t_0^cX | parallel transport along the curve c| mathcal P^cX=mathcal P_1gets 0^cX | of the vector X from p=c(0) to c(1) | p | a point on mathcal M | p_1 p_2 ldotsq | for 3 points one might use xyz | | operatornameretr_pX| a retraction | | | ξ | a set of tangent vectors | X_1ldotsX_n | | | T_p mathcal M | the tangent space at p | | | | X | a tangent vector from T_p mathcal M | X_1X_2ldotsYZ | sometimes written with base point X_p | | operatornametr | trace (of a matrix) | | | cdot^mathrmT | transposed | | | e_i in mathbb R^n | the ith unit vector | e_i^n | the space dimension (n) is omited, when clear from context | B | a vector bundle | | | mathcal T_qgets pX | vector transport | | of the vector X from T_pmathcal M to T_qmathcal M | mathcal T_pYX | vector transport in direction Y | | of the vector X from T_pmathcal M to T_qmathcal M, where q is deretmined by Y, for example using the exponential map or some retraction. | | mathcal W | the Weingarten map mathcal W T_pmathcal M N_pmathcal M T_pmathcal M | mathcal W_p | the second notation to emphasize the dependency of the point pinmathcal M | | 0_k | the ktimes k zero matrix. | |","category":"page"},{"location":"manifolds/symmetricpsdfixedrank.html#Symmetric-Positive-Semidefinite-Matrices-of-Fixed-Rank","page":"Symmetric positive semidefinite fixed rank","title":"Symmetric Positive Semidefinite Matrices of Fixed Rank","text":"","category":"section"},{"location":"manifolds/symmetricpsdfixedrank.html","page":"Symmetric positive semidefinite fixed rank","title":"Symmetric positive semidefinite fixed rank","text":"Modules = [Manifolds]\nPages = [\"manifolds/SymmetricPositiveSemidefiniteFixedRank.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/symmetricpsdfixedrank.html#Manifolds.SymmetricPositiveSemidefiniteFixedRank","page":"Symmetric positive semidefinite fixed rank","title":"Manifolds.SymmetricPositiveSemidefiniteFixedRank","text":"SymmetricPositiveSemidefiniteFixedRank{n,k,𝔽} <: AbstractDecoratorManifold{𝔽}\n\nThe AbstractManifold $ \\operatorname{SPS}_k(n)$ consisting of the real- or complex-valued symmetric positive semidefinite matrices of size n n and rank k, i.e. the set\n\noperatornameSPS_k(n) = bigl\np 𝔽^n n big p^mathrmH = p\napa^mathrmH geq 0 text for all a 𝔽\ntext and operatornamerank(p) = kbigr\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transpose, and the field 𝔽 ℝ ℂ. We sometimes operatornameSPS_k𝔽(n), when distinguishing the real- and complex-valued manifold is important.\n\nAn element is represented by q 𝔽^n k from the factorization p = qq^mathrmH. Note that since for any unitary (orthogonal) A 𝔽^n n we have (Aq)(Aq)^mathrmH = qq^mathrmH = p, the representation is not unique, or in other words, the manifold is a quotient manifold of 𝔽^n k.\n\nThe tangent space at p, T_poperatornameSPS_k(n), is also represented by matrices Y 𝔽^n k and reads as\n\nT_poperatornameSPS_k(n) = bigl\nX 𝔽^n nX = qY^mathrmH + Yq^mathrmH\ntext ie X = X^mathrmH\nbigr\n\nNote that the metric used yields a non-complete manifold. The metric was used in[JourneeBachAbsilSepulchre2010][MassartAbsil2020].\n\nConstructor\n\nSymmetricPositiveSemidefiniteFixedRank(n::Int, k::Int, field::AbstractNumbers=ℝ)\n\nGenerate the manifold of n n symmetric positive semidefinite matrices of rank k over the field of real numbers ℝ or complex numbers ℂ.\n\n[JourneeBachAbsilSepulchre2010]: Journée, M., Bach, F., Absil, P.-A., and Sepulchre, R.: “Low-Rank Optimization on the Cone of Positive Semidefinite Matrices”, SIAM Journal on Optimization (20)5, pp. 2327–2351, 2010. doi: 10.1137/080731359, arXiv: 0807.4423.\n\n[MassartAbsil2020]: Massart, E., Absil, P.-A.: \"Quotient Geometry with Simple Geodesics for the AbstractManifold of Fixed-Rank Positive-Semidefinite Matrices\", SIAM Journal on Matrix Analysis and Applications (41)1, pp. 171–198, 2020. doi: 10.1137/18m1231389, preprint: sites.uclouvain.be/absil/2018.06.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symmetricpsdfixedrank.html#Base.exp-Tuple{SymmetricPositiveSemidefiniteFixedRank, Any, Any}","page":"Symmetric positive semidefinite fixed rank","title":"Base.exp","text":"exp(M::SymmetricPositiveSemidefiniteFixedRank, q, Y)\n\nCompute the exponential map on the SymmetricPositiveSemidefiniteFixedRank, which just reads\n\n exp_q Y = q+Y\n\nnote: Note\nSince the manifold is represented in the embedding and is a quotient manifold, the exponential and logarithmic map are a bijection only with respect to the equivalence classes. Computing q_2 = exp_p(log_pq)might yield a matrix q_2neq q, but they represent the same point on the quotient manifold, i.e. d_operatornameSPS_k(n)(q_2q) = 0.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpsdfixedrank.html#Base.log-Tuple{SymmetricPositiveSemidefiniteFixedRank, Any, Any}","page":"Symmetric positive semidefinite fixed rank","title":"Base.log","text":"log(M::SymmetricPositiveSemidefiniteFixedRank, q, p)\n\nCompute the logarithmic map on the SymmetricPositiveSemidefiniteFixedRank manifold by minimizing lVert p - qYrVert with respect to Y.\n\nnote: Note\nSince the manifold is represented in the embedding and is a quotient manifold, the exponential and logarithmic map are a bijection only with respect to the equivalence classes. Computing q_2 = exp_p(log_pq)might yield a matrix q_2neq q, but they represent the same point on the quotient manifold, i.e. d_operatornameSPS_k(n)(q_2q) = 0.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpsdfixedrank.html#ManifoldsBase._isapprox-Tuple{SymmetricPositiveSemidefiniteFixedRank, Any, Any}","page":"Symmetric positive semidefinite fixed rank","title":"ManifoldsBase._isapprox","text":"isapprox(M::SymmetricPositiveSemidefiniteFixedRank, p, q; kwargs...)\n\ntest, whether two points p, q are (approximately) nearly the same. Since this is a quotient manifold in the embedding, the test is performed by checking their distance, if they are not the same, i.e. that d_mathcal M(pq) approx 0, where the comparison is performed with the classical isapprox. The kwargs... are passed on to this accordingly.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpsdfixedrank.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{SymmetricPositiveSemidefiniteFixedRank{n, k, 𝔽}, Any}} where {n, k, 𝔽}","page":"Symmetric positive semidefinite fixed rank","title":"ManifoldsBase.check_point","text":"check_point(M::SymmetricPositiveSemidefiniteFixedRank{n,𝔽}, q; kwargs...)\n\nCheck whether q is a valid manifold point on the SymmetricPositiveSemidefiniteFixedRank M, i.e. whether p=q*q' is a symmetric matrix of size (n,n) with values from the corresponding AbstractNumbers 𝔽. The symmetry of p is not explicitly checked since by using q p is symmetric by construction. The tolerance for the symmetry of p can and the rank of q*q' be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpsdfixedrank.html#ManifoldsBase.check_vector-Tuple{SymmetricPositiveSemidefiniteFixedRank, Any, Any}","page":"Symmetric positive semidefinite fixed rank","title":"ManifoldsBase.check_vector","text":"check_vector(M::SymmetricPositiveSemidefiniteFixedRank{n,k,𝔽}, p, X; kwargs... )\n\nCheck whether X is a tangent vector to manifold point p on the SymmetricPositiveSemidefiniteFixedRank M, i.e. X has to be a symmetric matrix of size (n,n) and its values have to be from the correct AbstractNumbers.\n\nDue to the reduced representation this is fulfilled as soon as the matrix is of correct size.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpsdfixedrank.html#ManifoldsBase.distance-Tuple{SymmetricPositiveSemidefiniteFixedRank, Any, Any}","page":"Symmetric positive semidefinite fixed rank","title":"ManifoldsBase.distance","text":"distance(M::SymmetricPositiveSemidefiniteFixedRank, p, q)\n\nCompute the distance between two points p, q on the SymmetricPositiveSemidefiniteFixedRank, which is the Frobenius norm of Y which minimizes lVert p - qYrVert with respect to Y.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpsdfixedrank.html#ManifoldsBase.is_flat-Tuple{SymmetricPositiveSemidefiniteFixedRank}","page":"Symmetric positive semidefinite fixed rank","title":"ManifoldsBase.is_flat","text":"is_flat(::SymmetricPositiveSemidefiniteFixedRank)\n\nReturn false. SymmetricPositiveSemidefiniteFixedRank is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpsdfixedrank.html#ManifoldsBase.manifold_dimension-Tuple{SymmetricPositiveSemidefiniteFixedRank}","page":"Symmetric positive semidefinite fixed rank","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::SymmetricPositiveSemidefiniteFixedRank{n,k,𝔽})\n\nReturn the dimension of the SymmetricPositiveSemidefiniteFixedRank matrix M over the number system 𝔽, i.e.\n\nbeginaligned\ndim operatornameSPS_kℝ(n) = kn - frack(k-1)2\ndim operatornameSPS_kℂ(n) = 2kn - k^2\nendaligned\n\nwhere the last k^2 is due to the zero imaginary part for Hermitian matrices diagonal\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpsdfixedrank.html#ManifoldsBase.vector_transport_to-Tuple{SymmetricPositiveSemidefiniteFixedRank, Any, Any, Any, ProjectionTransport}","page":"Symmetric positive semidefinite fixed rank","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::SymmetricPositiveSemidefiniteFixedRank, p, X, q)\n\ntransport the tangent vector X at p to q by projecting it onto the tangent space at q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpsdfixedrank.html#ManifoldsBase.zero_vector-Tuple{SymmetricPositiveSemidefiniteFixedRank, Vararg{Any}}","page":"Symmetric positive semidefinite fixed rank","title":"ManifoldsBase.zero_vector","text":" zero_vector(M::SymmetricPositiveSemidefiniteFixedRank, p)\n\nreturns the zero tangent vector in the tangent space of the symmetric positive definite matrix p on the SymmetricPositiveSemidefiniteFixedRank manifold M.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#atlases_and_charts","page":"Atlases and charts","title":"Atlases and charts","text":"","category":"section"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"Atlases on an n-dimensional manifold mathcal M are collections of charts mathcal A = (U_i φ_i) colon i in I, where I is a (finite or infinte) index family, such that U_i subseteq mathcal M is an open set and each chart φ_i U_i to mathbbR^n is a homeomorphism. This means, that φ_i is bijective – sometimes also called one-to-one and onto - and continuous, and its inverse φ_i^-1 is continuous as well. The inverse φ_i^-1 is called (local) parametrization. The resulting parameters a=φ(p) of p (with respect to the chart φ) are in the literature also called “(local) coordinates”. To distinguish the parameter a from get_coordinates in a basis, we use the terminology parameter in this package.","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"For an atlas mathcal A we further require that","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"displaystylebigcup_iin I U_i = mathcal M","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"We say that φ_i is a chart about p, if pin U_i. An atlas provides a connection between a manifold and the Euclidean space mathbbR^n, since locally, a chart about p can be used to identify its neighborhood (as long as you stay in U_i) with a subset of a Euclidean space. Most manifolds we consider are smooth, i.e. any change of charts φ_i circ φ_j^-1 mathbbR^ntomathbbR^n, where ijin I, is a smooth function. These changes of charts are also called transition maps.","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"Most operations on manifolds in Manifolds.jl avoid operating in a chart through appropriate embeddings and formulas derived for particular manifolds, though atlases provide the most general way of working with manifolds. Compared to these approaches, using an atlas is often more technical and time-consuming. They are extensively used in metric-related functions on MetricManifolds.","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"Atlases are represented by objects of subtypes of AbstractAtlas. There are no type restrictions for indices of charts in atlases.","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"Operations using atlases and charts are available through the following functions:","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"get_chart_index can be used to select an appropriate chart for the neighborhood of a given point p. This function should work deterministically, i.e. for a fixed p always return the same chart.\nget_parameters converts a point to its parameters with respect to the chart in a chart.\nget_point converts parameters (local coordinates) in a chart to the point that corresponds to them.\ninduced_basis returns a basis of a given vector space at a point induced by a chart φ.\ntransition_map converts coordinates of a point between two charts, e.g. computes φ_icirc φ_j^-1 mathbbR^ntomathbbR^n, ijin I.","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"While an atlas could store charts as explicit functions, it is favourable, that the [get_parameters] actually implements a chart φ, get_point its inverse, the prametrization φ^-1.","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"Modules = [Manifolds,ManifoldsBase]\nPages = [\"atlases.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"features/atlases.html#Manifolds.AbstractAtlas","page":"Atlases and charts","title":"Manifolds.AbstractAtlas","text":"AbstractAtlas{𝔽}\n\nAn abstract class for atlases whith charts that have values in the vector space 𝔽ⁿ for some value of n. 𝔽 is a number system determined by an AbstractNumbers object.\n\n\n\n\n\n","category":"type"},{"location":"features/atlases.html#Manifolds.InducedBasis","page":"Atlases and charts","title":"Manifolds.InducedBasis","text":"InducedBasis(vs::VectorSpaceType, A::AbstractAtlas, i)\n\nThe basis induced by chart with index i from an AbstractAtlas A of vector space of type vs.\n\nFor the vs a TangentSpace this works as follows:\n\nLet n denote the dimension of the manifold mathcal M.\n\nLet the parameter a=φ_i(p) mathbb R^n and j1n. We can look at the jth parameter curve b_j(t) = a + te_j, where e_j denotes the jth unit vector. Using the parametrisation we obtain a curve c_j(t) = φ_i^-1(b_j(t)) which fulfills c(0) = p.\n\nNow taking the derivative(s) with respect to t (and evaluate at t=0), we obtain a tangent vector for each j corresponding to an equivalence class of curves (having the same derivative) as\n\nX_j = c_j = fracmathrmdmathrmdt c_i(t) Bigl_t=0\n\nand the set X_1ldotsX_n is the chart-induced basis of T_pmathcal M.\n\nSee also\n\nVectorSpaceType, AbstractBasis\n\n\n\n\n\n","category":"type"},{"location":"features/atlases.html#Manifolds.RetractionAtlas","page":"Atlases and charts","title":"Manifolds.RetractionAtlas","text":"RetractionAtlas{\n 𝔽,\n TRetr<:AbstractRetractionMethod,\n TInvRetr<:AbstractInverseRetractionMethod,\n TBasis<:AbstractBasis,\n} <: AbstractAtlas{𝔽}\n\nAn atlas indexed by points on a manifold, mathcal M = I and parameters (local coordinates) are given in T_pmathcal M. This means that a chart φ_p = mathrmcordcircmathrmretr_p^-1 is only locally defined (around p), where mathrmcord is the decomposition of the tangent vector into coordinates with respect to the given basis of the tangent space, cf. get_coordinates. The parametrization is given by φ_p^-1=mathrmretr_pcircmathrmvec, where mathrmvec turns the basis coordinates into a tangent vector, cf. get_vector.\n\nIn short: The coordinates with respect to a basis are used together with a retraction as a parametrization.\n\nSee also\n\nAbstractAtlas, AbstractInverseRetractionMethod, AbstractRetractionMethod, AbstractBasis\n\n\n\n\n\n","category":"type"},{"location":"features/atlases.html#LinearAlgebra.norm-Tuple{AbstractManifold, AbstractAtlas, Any, Any, Any}","page":"Atlases and charts","title":"LinearAlgebra.norm","text":"norm(M::AbstractManifold, A::AbstractAtlas, i, a, Xc)\n\nCalculate norm on manifold M at point with parameters a in chart i of an AbstractAtlas A of vector with coefficients Xc in induced basis.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.affine_connection!-Tuple{AbstractManifold, Any, AbstractAtlas, Vararg{Any, 4}}","page":"Atlases and charts","title":"Manifolds.affine_connection!","text":"affine_connection!(M::AbstractManifold, Zc, A::AbstractAtlas, i, a, Xc, Yc)\n\nCalculate affine connection on manifold M at point with parameters a in chart i of an an AbstractAtlas A of vectors with coefficients Zc and Yc in induced basis and save the result in Zc.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.affine_connection-Tuple{AbstractManifold, Vararg{Any, 5}}","page":"Atlases and charts","title":"Manifolds.affine_connection","text":"affine_connection(M::AbstractManifold, A::AbstractAtlas, i, a, Xc, Yc)\n\nCalculate affine connection on manifold M at point with parameters a in chart i of AbstractAtlas A of vectors with coefficients Xc and Yc in induced basis.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.check_chart_switch-Tuple{AbstractManifold, AbstractAtlas, Any, Any}","page":"Atlases and charts","title":"Manifolds.check_chart_switch","text":"check_chart_switch(M::AbstractManifold, A::AbstractAtlas, i, a)\n\nDetermine whether chart should be switched when an operation in chart i from an AbstractAtlas A reaches parameters a in that chart.\n\nBy default false is returned.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.get_chart_index-Tuple{AbstractManifold, AbstractAtlas, Any, Any}","page":"Atlases and charts","title":"Manifolds.get_chart_index","text":"get_chart_index(M::AbstractManifold, A::AbstractAtlas, i, a)\n\nSelect a chart from an AbstractAtlas A for manifold M that is suitable for representing the neighborhood of point with parametrization a in chart i. This selection should be deterministic, although different charts may be selected for arbitrarily close but distinct points.\n\nSee also\n\nget_default_atlas\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.get_chart_index-Tuple{AbstractManifold, AbstractAtlas, Any}","page":"Atlases and charts","title":"Manifolds.get_chart_index","text":"get_chart_index(M::AbstractManifold, A::AbstractAtlas, p)\n\nSelect a chart from an AbstractAtlas A for manifold M that is suitable for representing the neighborhood of point p. This selection should be deterministic, although different charts may be selected for arbitrarily close but distinct points.\n\nSee also\n\nget_default_atlas\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.get_default_atlas-Tuple{AbstractManifold}","page":"Atlases and charts","title":"Manifolds.get_default_atlas","text":"get_default_atlas(::AbstractManifold)\n\nDetermine the default real-valued atlas for the given manifold.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.get_parameters-Tuple{AbstractManifold, AbstractAtlas, Any, Any}","page":"Atlases and charts","title":"Manifolds.get_parameters","text":"get_parameters(M::AbstractManifold, A::AbstractAtlas, i, p)\n\nCalculate parameters (local coordinates) of point p on manifold M in chart from an AbstractAtlas A at index i. This function is hence an implementation of the chart φ_i(p) iin I. The parameters are in the number system determined by A. If the point pnotin U_i is not in the domain of the chart, this method should throw an error.\n\nSee also\n\nget_point, get_chart_index\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.get_point-Tuple{AbstractManifold, AbstractAtlas, Any, Any}","page":"Atlases and charts","title":"Manifolds.get_point","text":"get_point(M::AbstractManifold, A::AbstractAtlas, i, a)\n\nCalculate point at parameters (local coordinates) a on manifold M in chart from an AbstractAtlas A at index i. This function is hence an implementation of the inverse φ_i^-1(a) iin I of a chart, also called a parametrization.\n\nSee also\n\nget_parameters, get_chart_index\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.induced_basis-Tuple{AbstractManifold, AbstractAtlas, Any, VectorSpaceType}","page":"Atlases and charts","title":"Manifolds.induced_basis","text":"induced_basis(M::AbstractManifold, A::AbstractAtlas, i, p, VST::VectorSpaceType)\n\nBasis of vector space of type VST at point p from manifold M induced by chart (A, i).\n\nSee also\n\nVectorSpaceType, AbstractAtlas\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.induced_basis-Union{Tuple{𝔽}, Tuple{AbstractManifold{𝔽}, AbstractAtlas, Any}, Tuple{AbstractManifold{𝔽}, AbstractAtlas, Any, VectorSpaceType}} where 𝔽","page":"Atlases and charts","title":"Manifolds.induced_basis","text":"induced_basis(::AbstractManifold, A::AbstractAtlas, i, VST::VectorSpaceType = TangentSpace)\n\nGet the basis induced by chart with index i from an AbstractAtlas A of vector space of type vs. Returns an object of type InducedBasis.\n\nSee also\n\nVectorSpaceType, AbstractBasis\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.inverse_chart_injectivity_radius-Tuple{AbstractManifold, AbstractAtlas, Any}","page":"Atlases and charts","title":"Manifolds.inverse_chart_injectivity_radius","text":"inverse_chart_injectivity_radius(M::AbstractManifold, A::AbstractAtlas, i)\n\nInjectivity radius of get_point for chart i from an AbstractAtlas A of a manifold M.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.local_metric-Tuple{AbstractManifold, Any, InducedBasis}","page":"Atlases and charts","title":"Manifolds.local_metric","text":"local_metric(M::AbstractManifold, p, B::InducedBasis)\n\nCompute the local metric tensor for vectors expressed in terms of coordinates in basis B on manifold M. The point p is not checked.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.transition_map-Tuple{AbstractManifold, AbstractAtlas, Any, AbstractAtlas, Any, Any}","page":"Atlases and charts","title":"Manifolds.transition_map","text":"transition_map(M::AbstractManifold, A_from::AbstractAtlas, i_from, A_to::AbstractAtlas, i_to, a)\ntransition_map(M::AbstractManifold, A::AbstractAtlas, i_from, i_to, a)\n\nGiven coordinates a in chart (A_from, i_from) of a point on manifold M, returns coordinates of that point in chart (A_to, i_to). If A_from and A_to are equal, A_to can be omitted.\n\nMathematically this function is the transition map or change of charts, but it might even be between two atlases A_textfrom = (U_iφ_i)_iin I and A_textto = (V_jpsi_j)_jin J, and hence I J are their index sets. We have i_textfromin I, i_texttoin J.\n\nThis method then computes\n\nbigl(psi_i_texttocirc φ_i_textfrom^-1bigr)(a)\n\nNote that, similarly to get_parameters, this method should fail the same way if V_i_texttocap U_i_textfrom=emptyset.\n\nSee also\n\nAbstractAtlas, get_parameters, get_point\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.transition_map_diff!-Tuple{AbstractManifold, Any, AbstractAtlas, Vararg{Any, 4}}","page":"Atlases and charts","title":"Manifolds.transition_map_diff!","text":"transition_map_diff!(M::AbstractManifold, c_out, A::AbstractAtlas, i_from, a, c, i_to)\n\nCompute transition_map_diff on given arguments and save the result in c_out.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.transition_map_diff-Tuple{AbstractManifold, AbstractAtlas, Vararg{Any, 4}}","page":"Atlases and charts","title":"Manifolds.transition_map_diff","text":"transition_map_diff(M::AbstractManifold, A::AbstractAtlas, i_from, a, c, i_to)\n\nCompute differential of transition map from chart i_from to chart i_to from an AbstractAtlas A on manifold M at point with parameters a on tangent vector with coordinates c in the induced basis.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#ManifoldsBase.inner-Tuple{AbstractManifold, AbstractAtlas, Vararg{Any, 4}}","page":"Atlases and charts","title":"ManifoldsBase.inner","text":"inner(M::AbstractManifold, A::AbstractAtlas, i, a, Xc, Yc)\n\nCalculate inner product on manifold M at point with parameters a in chart i of an atlas A of vectors with coefficients Xc and Yc in induced basis.\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Cotangent-space-and-musical-isomorphisms","page":"Atlases and charts","title":"Cotangent space and musical isomorphisms","text":"","category":"section"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"Related to atlases, there is also support for the cotangent space and coefficients of cotangent vectors in bases of the cotangent space.","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"Functions sharp and flat implement musical isomorphisms for arbitrary vector bundles.","category":"page"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"Modules = [Manifolds,ManifoldsBase]\nPages = [\"cotangent_space.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"features/atlases.html#Manifolds.RieszRepresenterCotangentVector","page":"Atlases and charts","title":"Manifolds.RieszRepresenterCotangentVector","text":"RieszRepresenterCotangentVector(M::AbstractManifold, p, X)\n\nCotangent vector in Riesz representer form on manifold M at point p with Riesz representer X.\n\n\n\n\n\n","category":"type"},{"location":"features/atlases.html#Manifolds.flat-Tuple{AbstractManifold, Any, Any}","page":"Atlases and charts","title":"Manifolds.flat","text":"flat(M::AbstractManifold, p, X)\n\nCompute the flat isomorphism (one of the musical isomorphisms) of tangent vector X from the vector space of type M at point p from the underlying AbstractManifold.\n\nThe function can be used for example to transform vectors from the tangent bundle to vectors from the cotangent bundle Tmathcal M T^*mathcal M\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Manifolds.sharp-Tuple{AbstractManifold, Any, Any}","page":"Atlases and charts","title":"Manifolds.sharp","text":"sharp(M::AbstractManifold, p, ξ)\n\nCompute the sharp isomorphism (one of the musical isomorphisms) of vector ξ from the vector space M at point p from the underlying AbstractManifold.\n\nThe function can be used for example to transform vectors from the cotangent bundle to vectors from the tangent bundle T^*mathcal M Tmathcal M\n\n\n\n\n\n","category":"method"},{"location":"features/atlases.html#Computations-in-charts","page":"Atlases and charts","title":"Computations in charts","text":"","category":"section"},{"location":"features/atlases.html","page":"Atlases and charts","title":"Atlases and charts","text":"Manifolds.IntegratorTerminatorNearChartBoundary\nManifolds.estimate_distance_from_bvp\nManifolds.solve_chart_exp_ode\nManifolds.solve_chart_log_bvp\nManifolds.solve_chart_parallel_transport_ode","category":"page"},{"location":"features/atlases.html#Manifolds.IntegratorTerminatorNearChartBoundary","page":"Atlases and charts","title":"Manifolds.IntegratorTerminatorNearChartBoundary","text":"IntegratorTerminatorNearChartBoundary{TKwargs}\n\nAn object for determining the point at which integration of a differential equation in a chart on a manifold should be terminated for the purpose of switching a chart.\n\nThe value stored in check_chart_switch_kwargs will be passed as keyword arguments to check_chart_switch. By default an empty tuple is stored.\n\n\n\n\n\n","category":"type"},{"location":"features/atlases.html#Manifolds.estimate_distance_from_bvp","page":"Atlases and charts","title":"Manifolds.estimate_distance_from_bvp","text":"estimate_distance_from_bvp(\n M::AbstractManifold,\n a1,\n a2,\n A::AbstractAtlas,\n i;\n solver=GeneralMIRK4(),\n dt=0.05,\n kwargs...,\n)\n\nEstimate distance between points on AbstractManifold M with parameters a1 and a2 in chart i of AbstractAtlas A using solver solver, employing solve_chart_log_bvp to solve the geodesic BVP.\n\n\n\n\n\n","category":"function"},{"location":"features/atlases.html#Manifolds.solve_chart_exp_ode","page":"Atlases and charts","title":"Manifolds.solve_chart_exp_ode","text":"solve_chart_exp_ode(\n M::AbstractManifold,\n a,\n Xc,\n A::AbstractAtlas,\n i0;\n solver=AutoVern9(Rodas5()),\n final_time=1.0,\n check_chart_switch_kwargs=NamedTuple(),\n kwargs...,\n)\n\nSolve geodesic ODE on a manifold M from point of coordinates a in chart i0 from an AbstractAtlas A in direction of coordinates Xc in the induced basis.\n\n\n\n\n\n","category":"function"},{"location":"features/atlases.html#Manifolds.solve_chart_log_bvp","page":"Atlases and charts","title":"Manifolds.solve_chart_log_bvp","text":"solve_chart_log_bvp(\n M::AbstractManifold,\n a1,\n a2,\n A::AbstractAtlas,\n i;\n solver=GeneralMIRK4(),\n dt=0.05,\n kwargs...,\n)\n\nSolve the BVP corresponding to geodesic calculation on AbstractManifold M, between points with parameters a1 and a2 in a chart i of an AbstractAtlas A using solver solver. Geodesic γ is sampled at time interval dt, with γ(0) = a1 and γ(1) = a2.\n\n\n\n\n\n","category":"function"},{"location":"features/atlases.html#Manifolds.solve_chart_parallel_transport_ode","page":"Atlases and charts","title":"Manifolds.solve_chart_parallel_transport_ode","text":"solve_chart_parallel_transport_ode(\n M::AbstractManifold,\n a,\n Xc,\n A::AbstractAtlas,\n i0,\n Yc;\n solver=AutoVern9(Rodas5()),\n check_chart_switch_kwargs=NamedTuple(),\n final_time=1.0,\n kwargs...,\n)\n\nParallel transport vector with coordinates Yc along geodesic on a manifold M from point of coordinates a in a chart i0 from an AbstractAtlas A in direction of coordinates Xc in the induced basis.\n\n\n\n\n\n","category":"function"},{"location":"features/differentiation.html#Differentiation","page":"Differentiation","title":"Differentiation","text":"","category":"section"},{"location":"features/differentiation.html","page":"Differentiation","title":"Differentiation","text":"Documentation for Manifolds.jl's methods and types for finite differences and automatic differentiation.","category":"page"},{"location":"features/differentiation.html#Differentiation-backends","page":"Differentiation","title":"Differentiation backends","text":"","category":"section"},{"location":"features/differentiation.html","page":"Differentiation","title":"Differentiation","text":"Modules = [Manifolds]\nPages = [\"differentiation/differentiation.jl\"]\nOrder = [:type, :function, :constant]","category":"page"},{"location":"features/differentiation.html","page":"Differentiation","title":"Differentiation","text":"Further differentiation backends and features are available in ManifoldDiff.jl.","category":"page"},{"location":"features/differentiation.html#FiniteDifferenes.jl","page":"Differentiation","title":"FiniteDifferenes.jl","text":"","category":"section"},{"location":"features/differentiation.html","page":"Differentiation","title":"Differentiation","text":"Modules = [Manifolds]\nPages = [\"differentiation/finite_differences.jl\"]\nOrder = [:type, :function, :constant]","category":"page"},{"location":"features/differentiation.html#Riemannian-differentiation-backends","page":"Differentiation","title":"Riemannian differentiation backends","text":"","category":"section"},{"location":"features/differentiation.html","page":"Differentiation","title":"Differentiation","text":"Modules = [Manifolds]\nPages = [\"differentiation/riemannian_diff.jl\"]\nOrder = [:type, :function, :constant]","category":"page"},{"location":"features/differentiation.html","page":"Differentiation","title":"Differentiation","text":"Modules = [Manifolds]\nPages = [\"differentiation/embedded_diff.jl\"]\nOrder = [:type, :function, :constant]","category":"page"},{"location":"manifolds/flag.html#Flag-manifold","page":"Flag","title":"Flag manifold","text":"","category":"section"},{"location":"manifolds/flag.html","page":"Flag","title":"Flag","text":"Modules = [Manifolds]\nPages = [\"manifolds/Flag.jl\"]\nOrder = [:type,:function]","category":"page"},{"location":"manifolds/flag.html#Manifolds.Flag","page":"Flag","title":"Manifolds.Flag","text":"Flag{N,d} <: AbstractDecoratorManifold{ℝ}\n\nFlag manifold of d subspaces of ℝ^N[YeWongLim2022]. By default the manifold uses the Stiefel coordinates representation, embedding it in the Stiefel manifold. The other available representation is an embedding in OrthogonalMatrices. It can be utilized using OrthogonalPoint and OrthogonalTVector wrappers.\n\nTangent space is represented in the block-skew-symmetric form.\n\nConstructor\n\nFlag(N, n1, n2, ..., nd)\n\nGenerate the manifold operatornameFlag(n_1 n_2 n_d N) of subspaces\n\n𝕍_1 𝕍_2 V_d quad operatornamedim(𝕍_i) = n_i\n\nwhere 𝕍_i for i 1 2 d are subspaces of ℝ^N of dimension operatornamedim 𝕍_i = n_i.\n\n[YeWongLim2022]: K. Ye, K. S.-W. Wong, and L.-H. Lim, “Optimization on flag manifolds,” Math. Program., vol. 194, no. 1, pp. 621–660, Jul. 2022, doi: 10.1007/s10107-021-01640-3.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/flag.html#Manifolds.OrthogonalPoint","page":"Flag","title":"Manifolds.OrthogonalPoint","text":"OrthogonalPoint <: AbstractManifoldPoint\n\nA type to represent points on a manifold Flag in the orthogonal coordinates representation, i.e. a rotation matrix.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/flag.html#Manifolds.OrthogonalTVector","page":"Flag","title":"Manifolds.OrthogonalTVector","text":"OrthogonalTVector <: TVector\n\nA type to represent tangent vectors to points on a Flag manifold in the orthogonal coordinates representation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/flag.html#Manifolds.ZeroTuple","page":"Flag","title":"Manifolds.ZeroTuple","text":"ZeroTuple\n\nInternal structure for representing shape of a Flag manifold. Behaves like a normal tuple, except at index zero returns value 0.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/flag.html#Base.convert-Tuple{Type{AbstractMatrix}, Flag, Manifolds.OrthogonalPoint, Manifolds.OrthogonalTVector}","page":"Flag","title":"Base.convert","text":"convert(::Type{AbstractMatrix}, M::Flag, p::OrthogonalPoint, X::OrthogonalTVector)\n\nConvert tangent vector from Flag manifold M from orthogonal representation to Stiefel representation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#Base.convert-Tuple{Type{AbstractMatrix}, Flag, Manifolds.OrthogonalPoint}","page":"Flag","title":"Base.convert","text":"convert(::Type{AbstractMatrix}, M::Flag, p::OrthogonalPoint)\n\nConvert point p from Flag manifold M from orthogonal representation to Stiefel representation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#Base.convert-Tuple{Type{Manifolds.OrthogonalPoint}, Flag, AbstractMatrix}","page":"Flag","title":"Base.convert","text":"convert(::Type{OrthogonalPoint}, M::Flag, p::AbstractMatrix)\n\nConvert point p from Flag manifold M from Stiefel representation to orthogonal representation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#Base.convert-Tuple{Type{Manifolds.OrthogonalTVector}, Flag, AbstractMatrix, AbstractMatrix}","page":"Flag","title":"Base.convert","text":"convert(::Type{OrthogonalTVector}, M::Flag, p::AbstractMatrix, X::AbstractMatrix)\n\nConvert tangent vector from Flag manifold M from Stiefel representation to orthogonal representation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.get_embedding-Union{Tuple{Flag{N, dp1}}, Tuple{dp1}, Tuple{N}} where {N, dp1}","page":"Flag","title":"ManifoldsBase.get_embedding","text":"get_embedding(M::Flag)\n\nGet the embedding of the Flag manifold M, i.e. the Stiefel manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.injectivity_radius-Tuple{Flag}","page":"Flag","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::Flag)\ninjectivity_radius(M::Flag, p)\n\nReturn the injectivity radius on the Flag M, which is fracπ2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.manifold_dimension-Union{Tuple{Flag{N, dp1}}, Tuple{dp1}, Tuple{N}} where {N, dp1}","page":"Flag","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::Flag)\n\nReturn dimension of flag manifold operatornameFlag(n_1 n_2 n_d N). The formula reads sum_i=1^d (n_i-n_i-1)(N-n_i).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#The-flag-manifold-represented-as-points-on-the-[Stiefel](@ref)-manifold","page":"Flag","title":"The flag manifold represented as points on the Stiefel manifold","text":"","category":"section"},{"location":"manifolds/flag.html","page":"Flag","title":"Flag","text":"Modules = [Manifolds]\nPages = [\"manifolds/FlagStiefel.jl\"]\nOrder = [:type,:function]","category":"page"},{"location":"manifolds/flag.html#ManifoldsBase.check_vector-Union{Tuple{dp1}, Tuple{N}, Tuple{Flag{N, dp1}, AbstractMatrix, AbstractMatrix}} where {N, dp1}","page":"Flag","title":"ManifoldsBase.check_vector","text":"check_vector(M::Flag, p::AbstractMatrix, X::AbstractMatrix; kwargs... )\n\nCheck whether X is a tangent vector to point p on the Flag manifold M operatornameFlag(n_1 n_2 n_d N) in the Stiefel representation, i.e. that X is a matrix of the form\n\nX = beginbmatrix\n0 B_12 cdots B_1d \n-B_12^mathrmT 0 cdots B_2d \nvdots vdots ddots vdots \n-B_1d^mathrmT -B_2d^mathrmT cdots 0 \n-B_1d+1^mathrmT -B_2d+1^mathrmT cdots -B_dd+1^mathrmT\nendbmatrix\n\nwhere B_ij ℝ^(n_i - n_i-1) (n_j - n_j-1), for 1 i j d+1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.default_inverse_retraction_method-Tuple{Flag}","page":"Flag","title":"ManifoldsBase.default_inverse_retraction_method","text":"default_inverse_retraction_method(M::Flag)\n\nReturn PolarInverseRetraction as the default inverse retraction for the Flag manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.default_retraction_method-Tuple{Flag}","page":"Flag","title":"ManifoldsBase.default_retraction_method","text":"default_retraction_method(M::Flag)\n\nReturn PolarRetraction as the default retraction for the Flag manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.default_vector_transport_method-Tuple{Flag}","page":"Flag","title":"ManifoldsBase.default_vector_transport_method","text":"default_vector_transport_method(M::Flag)\n\nReturn the ProjectionTransport as the default vector transport method for the Flag manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.inverse_retract-Tuple{Flag, Any, Any, PolarInverseRetraction}","page":"Flag","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::Flag, p, q, ::PolarInverseRetraction)\n\nCompute the inverse retraction for the PolarRetraction, on the Flag manifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.project-Tuple{Flag, Any, Any}","page":"Flag","title":"ManifoldsBase.project","text":"project(::Flag, p, X)\n\nProject vector X in the Euclidean embedding to the tangent space at point p on Flag manifold. The formula reads[YeWongLim2022]:\n\nY_i = X_i - (p_i p_i^mathrmT) X_i + sum_j neq i p_j X_j^mathrmT p_i\n\nfor i from 1 to d where the resulting vector is Y = Y_1 Y_2 Y_d and X = X_1 X_2 X_d, p = p_1 p_2 p_d are decompositions into basis vector matrices for consecutive subspaces of the flag.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.retract-Tuple{Flag, Any, Any, PolarRetraction}","page":"Flag","title":"ManifoldsBase.retract","text":"retract(M::Flag, p, X, ::PolarRetraction)\n\nCompute the SVD-based retraction PolarRetraction on the Flag M. With USV = p + X the retraction reads\n\noperatornameretr_p X = UV^mathrmH\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#The-flag-manifold-represented-as-orthogonal-matrices","page":"Flag","title":"The flag manifold represented as orthogonal matrices","text":"","category":"section"},{"location":"manifolds/flag.html","page":"Flag","title":"Flag","text":"Modules = [Manifolds]\nPages = [\"manifolds/FlagOrthogonal.jl\"]\nOrder = [:type,:function]","category":"page"},{"location":"manifolds/flag.html#ManifoldsBase.check_vector-Union{Tuple{dp1}, Tuple{N}, Tuple{Flag{N, dp1}, Manifolds.OrthogonalPoint, Manifolds.OrthogonalTVector}} where {N, dp1}","page":"Flag","title":"ManifoldsBase.check_vector","text":"check_vector(M::Flag, p::OrthogonalPoint, X::OrthogonalTVector; kwargs... )\n\nCheck whether X is a tangent vector to point p on the Flag manifold M operatornameFlag(n_1 n_2 n_d N) in the orthogonal matrix representation, i.e. that X is block-skew-symmetric with zero diagonal:\n\nX = beginbmatrix\n0 B_12 cdots B_1d+1 \n-B_12^mathrmT 0 cdots B_2d+1 \nvdots vdots ddots vdots \n-B_1d+1^mathrmT -B_2d+1^mathrmT cdots 0 \nendbmatrix\n\nwhere B_ij ℝ^(n_i - n_i-1) (n_j - n_j-1), for 1 i j d+1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.get_embedding-Union{Tuple{N}, Tuple{Flag{N}, Manifolds.OrthogonalPoint}} where N","page":"Flag","title":"ManifoldsBase.get_embedding","text":"get_embedding(M::Flag, p::OrthogonalPoint)\n\nGet embedding of Flag manifold M, i.e. the manifold OrthogonalMatrices.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.project-Union{Tuple{dp1}, Tuple{N}, Tuple{Flag{N, dp1}, Manifolds.OrthogonalPoint, Manifolds.OrthogonalTVector}} where {N, dp1}","page":"Flag","title":"ManifoldsBase.project","text":"project(M::Flag, p::OrthogonalPoint, X::OrthogonalTVector)\n\nProject vector X to tangent space at point p from Flag manifold M operatornameFlag(n_1 n_2 n_d N), in the orthogonal matrix representation. It works by first projecting X to the space of SkewHermitianMatrices and then setting diagonal blocks to 0:\n\nX = beginbmatrix\n0 B_12 cdots B_1d+1 \n-B_12^mathrmT 0 cdots B_2d+1 \nvdots vdots ddots vdots \n-B_1d+1^mathrmT -B_2d+1^mathrmT cdots 0 \nendbmatrix\n\nwhere B_ij ℝ^(n_i - n_i-1) (n_j - n_j-1), for 1 i j d+1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/flag.html#ManifoldsBase.retract-Tuple{Flag, Manifolds.OrthogonalPoint, Manifolds.OrthogonalTVector, QRRetraction}","page":"Flag","title":"ManifoldsBase.retract","text":"retract(M::Flag, p::OrthogonalPoint, X::OrthogonalTVector, ::QRRetraction)\n\nCompute the QR retraction on the Flag in the orthogonal matrix representation as the first order approximation to the exponential map. Similar to QR retraction for [GeneralUnitaryMatrices].\n\n\n\n\n\n","category":"method"},{"location":"tutorials/working-in-charts.html#Working-in-charts","page":"work in charts","title":"Working in charts","text":"","category":"section"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"In this tutorial we will learn how to use charts for basic geometric operations like exponential map, logarithmic map and parallel transport.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"There are two conceptually different approaches to working on a manifold: working in charts and chart-free representations.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"The first one, widespread in differential geometry textbooks, is based on defining an atlas on the manifold and performing computations in selected charts. This approach, while generic, is not ideally suitable in all circumstances. For example, working in charts that do not cover the entire manifold causes issues with having to switch charts when operating on a manifold.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"The second one is beneficital, if there exist a representation of points and tangent vectors for a manifold, which allow for efficient closed-form formulas for standard functions like the exponential map or Riemannian distance in this representation. These computations are then chart-free. Manifolds.jl supports both approaches, although the chart-free approach is the main focus of the library.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"In this tutorial we focus on chart-based computation.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"using Manifolds, RecursiveArrayTools, OrdinaryDiffEq, DiffEqCallbacks, BoundaryValueDiffEq","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"The manifold we consider is the M is the torus in form of the EmbeddedTorus, that is the representation defined as a surface of revolution of a circle of radius 2 around a circle of radius 3. The atlas we will perform computations in is its DefaultTorusAtlas A, consistting of a family of charts indexed by two angles, that specify the base point of the chart.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"We will draw geodesics time between 0 and t_end, and then sample the solution at multiples of dt and draw a line connecting sampled points.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"M = Manifolds.EmbeddedTorus(3, 2)\nA = Manifolds.DefaultTorusAtlas()","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"Manifolds.DefaultTorusAtlas()","category":"page"},{"location":"tutorials/working-in-charts.html#Setup","page":"work in charts","title":"Setup","text":"","category":"section"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"We will first set up our plot with an empty torus. param_points are points on the surface of the torus that will be used for basic surface shape in Makie.jl. The torus will be colored according to its Gaussian curvature stored in gcs. We later want to have a color scale that has negative curvature blue, zero curvature white and positive curvature red so gcs_mm is the largest absolute value of the curvature that will be needed to properly set range of curvature values.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"In the documentation this tutorial represents a static situation (without interactivity). Makie.jl rendering is turned off.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"# using GLMakie, Makie\n# GLMakie.activate!()\n\n\"\"\"\n torus_figure()\n\nThis function generates a simple plot of a torus and returns the new figure containing the plot.\n\"\"\"\nfunction torus_figure()\n fig = Figure(resolution=(1400, 1000), fontsize=16)\n ax = LScene(fig[1, 1], show_axis=true)\n ϴs, φs = LinRange(-π, π, 50), LinRange(-π, π, 50)\n param_points = [Manifolds._torus_param(M, θ, φ) for θ in ϴs, φ in φs]\n X1, Y1, Z1 = [[p[i] for p in param_points] for i in 1:3]\n gcs = [gaussian_curvature(M, p) for p in param_points]\n gcs_mm = max(abs(minimum(gcs)), abs(maximum(gcs)))\n pltobj = surface!(\n ax,\n X1,\n Y1,\n Z1;\n shading=true,\n ambient=Vec3f(0.65, 0.65, 0.65),\n backlight=1.0f0,\n color=gcs,\n colormap=Reverse(:RdBu),\n colorrange=(-gcs_mm, gcs_mm),\n transparency=true,\n )\n wireframe!(ax, X1, Y1, Z1; transparency=true, color=:gray, linewidth=0.5)\n zoom!(ax.scene, cameracontrols(ax.scene), 0.98)\n Colorbar(fig[1, 2], pltobj, height=Relative(0.5), label=\"Gaussian curvature\")\n return ax, fig\nend","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"torus_figure","category":"page"},{"location":"tutorials/working-in-charts.html#Values-for-the-geodesic","page":"work in charts","title":"Values for the geodesic","text":"","category":"section"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"solve_for is a helper function that solves a parallel transport along geodesic problem on the torus M. p0x is the (theta varphi) parametrization of the point from which we will transport the vector. We first calculate the coordinates in the embedding of p0x and store it as p, and then get the initial chart from atlas A appropriate for starting working at point p. The vector we transport has coordinates Y_transp in the induced tangent space basis of chart i_p0x. The function returns the full solution to the parallel transport problem, containing the sequence of charts that was used and solutions of differential equations computed using OrdinaryDiffEq.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"bvp_i is needed later for a different purpose, it is the chart index we will use for solving the logarithmic map boundary value problem in.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"Next we solve the vector transport problem solve_for([θₚ, φₚ], [θₓ, φₓ], [θy, φy]), sample the result at the selected time steps and store the result in geo. The solution includes the geodesic which we extract and convert to a sequence of points digestible by Makie.jl, geo_ps. [θₚ, φₚ] is the parametrization in chart (0, 0) of the starting point of the geodesic. The direction of the geodesic is determined by [θₓ, φₓ], coordinates of the tangent vector at the starting point expressed in the induced basis of chart i_p0x (which depends on the initial point). Finally, [θy, φy] are the coordinates of the tangent vector that will be transported along the geodesic, which are also expressed in same basis as [θₓ, φₓ].","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"We won’t draw the transported vector at every point as there would be too many arrows, which is why we select every 100th point only for that purpose with pt_indices. Then, geo_ps_pt contains points at which the transported vector is tangent to and geo_Ys the transported vector at that point, represented in the embedding.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"The logarithmic map will be solved between points with parametrization bvp_a1 and bvp_a2 in chart bvp_i. The result is assigned to variable bvp_sol and then sampled with time step 0.05. The result of this sampling is converted from parameters in chart bvp_i to point in the embedding and stored in geo_r.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"function solve_for(p0x, X_p0x, Y_transp, T)\n p = [Manifolds._torus_param(M, p0x...)...]\n i_p0x = Manifolds.get_chart_index(M, A, p)\n p_exp = Manifolds.solve_chart_parallel_transport_ode(\n M,\n [0.0, 0.0],\n X_p0x,\n A,\n i_p0x,\n Y_transp;\n final_time=T,\n )\n return p_exp\nend;","category":"page"},{"location":"tutorials/working-in-charts.html#Solving-parallel-Transport-ODE","page":"work in charts","title":"Solving parallel Transport ODE","text":"","category":"section"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"We set the end time t_end and time step dt.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"t_end = 2.0\ndt = 1e-1","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"0.1","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"We also parametrise the start point and direction.","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"θₚ = π/10\nφₚ = -π/4\nθₓ = π/2\nφₓ = 0.7\nθy = 0.2\nφy = -0.1\n\ngeo = solve_for([θₚ, φₚ], [θₓ, φₓ], [θy, φy], t_end)(0.0:dt:t_end);\n# geo_ps = [Point3f(s[1]) for s in geo]\n# pt_indices = 1:div(length(geo), 10):length(geo)\n# geo_ps_pt = [Point3f(s[1]) for s in geo[pt_indices]]\n# geo_Ys = [Point3f(s[3]) for s in geo[pt_indices]]\n\n# ax1, fig1 = torus_figure()\n# arrows!(ax1, geo_ps_pt, geo_Ys, linewidth=0.05, color=:blue)\n# lines!(geo_ps; linewidth=4.0, color=:green)\n# fig1","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"(Image: fig-pt)","category":"page"},{"location":"tutorials/working-in-charts.html#Solving-the-logairthmic-map-ODE","page":"work in charts","title":"Solving the logairthmic map ODE","text":"","category":"section"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"θ₁=π/2\nφ₁=-1.0\nθ₂=-π/8\nφ₂=π/2\n\nbvp_i = (0, 0)\nbvp_a1 = [θ₁, φ₁]\nbvp_a2 = [θ₂, φ₂]\nbvp_sol = Manifolds.solve_chart_log_bvp(M, bvp_a1, bvp_a2, A, bvp_i);\n# geo_r = [Point3f(get_point(M, A, bvp_i, p[1:2])) for p in bvp_sol(0.0:0.05:1.0)]\n\n# ax2, fig2 = torus_figure()\n# lines!(geo_r; linewidth=4.0, color=:green)\n# fig2","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"(Image: fig-geodesic)","category":"page"},{"location":"tutorials/working-in-charts.html","page":"work in charts","title":"work in charts","text":"An interactive Pluto version of this tutorial is available in file tutorials/working-in-charts.jl.","category":"page"},{"location":"tutorials/getstarted.html#Get-Started-with-Manifolds.jl","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"This is a short overview of Manifolds.jl and how to get started working with your first Manifold. we first need to install the package, using for example","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"using Pkg; Pkg.add(\"Manifolds\")","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Then you can load the package with","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"using Manifolds","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"[ Info: Precompiling ManifoldsRecipesBaseExt [37da849e-34ab-54fd-a5a4-b22599bd6cb0]","category":"page"},{"location":"tutorials/getstarted.html#Using-the-Library-of-Manifolds","page":"🚀 Get Started with Manifolds.jl","title":"Using the Library of Manifolds","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Manifolds.jl is first of all a library of manifolds, see the list in the menu here under “basic manifolds”.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Let’s look at three examples together with the first few functions on manifolds.","category":"page"},{"location":"tutorials/getstarted.html#.-[The-Euclidean-space](https://juliamanifolds.github.io/Manifolds.jl/latest/manifolds/euclidean.html)","page":"🚀 Get Started with Manifolds.jl","title":"1. The Euclidean space","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"The Euclidean Space Euclidean brings us (back) into linear case of vectors, so in terms of manifolds, this is a very simple one. It is often useful to compare to classical algorithms, or implementations.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₁ = Euclidean(3)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Euclidean(3; field = ℝ)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Since a manifold is a type in Julia, we write it in CamelCase. Its parameters are first a dimension or size parameter of the manifold, sometimes optional is a field the manifold is defined over.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"For example the above definition is the same as the real-valued case","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₁ === Euclidean(3, field=ℝ)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"true","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"But we even introduced a short hand notation, since ℝ is also just a symbol/variable to use”","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₁ === ℝ^3","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"true","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"And similarly here are two ways to create the manifold of vectors of length two with complex entries – or mathematically the space mathbb C^2","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Euclidean(2, field=ℂ) === ℂ^2","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"true","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"The easiest to check is the dimension of a manifold. Here we have three “directions to walk into” at every point pin mathbb R ^3 so 🔗 manifold_dimension) is","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"manifold_dimension(M₁)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"3","category":"page"},{"location":"tutorials/getstarted.html#.-[The-hyperpolic-space](@ref-HyperbolicSpace)","page":"🚀 Get Started with Manifolds.jl","title":"2. The hyperpolic space","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"The d-dimensional hyperbolic space is usually represented in mathbb R^d+1 as the set of points pinmathbb R^3 fulfilling","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"p_1^2+p_2^2+cdots+p_d^2-p_d+1^2 = -1","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"We define the manifold using","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₂ = Hyperbolic(2)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Hyperbolic(2)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"And we can again just start with looking at the manifold dimension of M₂","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"manifold_dimension(M₂)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"2","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"A next useful function is to check, whether some pmathbb R^3 is a point on the manifold M₂. We can check","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"is_point(M₂, [0, 0, 1])","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"true","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"or","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"is_point(M₂, [1, 0, 1])","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"false","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Keyword arguments are passed on to any numerical checks, for example an absolute tolerance when checking the above equiality.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"But in an interactive session an error message might be helpful. A positional (third) argument is present to activate this. Setting this parameter to true, we obtain an error message that gives insight into why the point is not a point on M₂. Note that the LoadError: is due to quarto, on REPL you would just get the DomainError.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"is_point(M₂, [0, 0, 1.001], true)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"LoadError: DomainError with -1.0020009999999997:\nThe point [0.0, 0.0, 1.001] does not lie on Hyperbolic(2) since its Minkowski inner product is not -1.","category":"page"},{"location":"tutorials/getstarted.html#.-[The-sphere](@ref-SphereSection)","page":"🚀 Get Started with Manifolds.jl","title":"3. The sphere","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"The sphere mathbb S^d is the d-dimensional sphere represented in its embedded form, that is unit vectors p in mathbb R^d+1 with unit norm lVert p rVert_2 = 1.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₃ = Sphere(2)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Sphere(2, ℝ)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"If we only have a point that is approximately on the manifold, we can allow for a tolerance. Usually these are the same values of atol and rtol alowed in isapprox, i.e. we get","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"is_point(M₃, [0, 0, 1.001]; atol=1e-3)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"true","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Here we can show a last nice check: 🔗 is_vector to check whether a tangent vector X is a representation of a tangent vector XT_pmathcal M to a point p on the manifold.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"This function has two positional asrguments, the first to again indicate whether to throw an error, the second to disable the check that p is a valid point on the manifold. Usually this validity is essential for the tangent check, but if it was for example performed before, it can be turned off to spare time.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"For example in our first example the point is not of unit norm","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"is_vector(M₃, [2, 0, 0], [0, 1, 1])","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"false","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"But the orthogonality of p and X is still valid, we can disable the point check, but even setting the error to true we get here","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"is_vector(M₃, [2, 0, 0], [0, 1, 1], true, false)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"true","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"But of course it is better to use a valid point in the first place","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"is_vector(M₃, [1, 0, 0], [0, 1, 1])","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"true","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"and for these we again get informative error messages","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"@expect_error is_vector(M₃, [1, 0, 0], [0.1, 1, 1], true) DomainError","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"LoadError: LoadError: UndefVarError: `@expect_error` not defined\nin expression starting at In[19]:1","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"To learn about how to define a manifold youself check out the 🔗 How to define your own manifold tutorial of 🔗 ManifoldsBase.jl.”","category":"page"},{"location":"tutorials/getstarted.html#Building-more-advanced-manifolds","page":"🚀 Get Started with Manifolds.jl","title":"Building more advanced manifolds","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Based on these basic manifolds we can directly build more advanced manifolds.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"The first one concerns vectors or matrices of data on a manifold, the PowerManifold.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₄ = M₂^2","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"PowerManifold(Hyperbolic(2), 2)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Then points are represented by arrays, where the power manifold dimension is added in the end. In other words – for the hyperbolic manifold here, we have a matrix with 2 columns, where each column is a valid point on hyperbolic space.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"p = [0 0; 0 1; 1 sqrt(2)]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"3×2 Matrix{Float64}:\n 0.0 0.0\n 0.0 1.0\n 1.0 1.41421","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"[is_point(M₂, p[:, 1]), is_point(M₂, p[:, 2])]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"2-element Vector{Bool}:\n 1\n 1","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"But of course the method we used previously also works for power manifolds:","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"is_point(M₄, p)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"true","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Note that nested power manifolds are combined into one as in","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₄₂ = M₄^4","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"PowerManifold(Hyperbolic(2), 2, 4)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"which represents 2times 4 – matrices of hyperbolic points represented in 3times 2times 4 arrays.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"We can – alternatively – use a power manifold with nested arrays","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₅ = PowerManifold(M₃, NestedPowerRepresentation(), 2)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"PowerManifold(Sphere(2, ℝ), NestedPowerRepresentation(), 2)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"which emphasizes that we have vectors of length 2 that contain points, so we store them that way.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"p₂ = [[0.0, 0.0, 1.0], [0.0, 1.0, 0.0]]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"2-element Vector{Vector{Float64}}:\n [0.0, 0.0, 1.0]\n [0.0, 1.0, 0.0]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"To unify both representations, elements of the power manifold can also be accessed in the classical indexing fashion, if we start with the corresponding manifold first. This way one can implement algorithms also independent of which representation is used.”","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"p[M₄, 1]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"3-element Vector{Float64}:\n 0.0\n 0.0\n 1.0","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"p₂[M₅, 2]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"3-element Vector{Float64}:\n 0.0\n 1.0\n 0.0","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Another construtor is the ProductManifold to combine different manifolds. Here of course the order matters. First we construct these using ","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₆ = M₂ × M₃","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"ProductManifold with 2 submanifolds:\n Hyperbolic(2)\n Sphere(2, ℝ)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Since now the representations might differ from element to element, we have to encapsulate these in their own type.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"p₃ = Manifolds.ArrayPartition([0, 0, 1], [0, 1, 0])","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"([0, 0, 1], [0, 1, 0])","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Here ArrayPartition taken from 🔗 RecursiveArrayTools.jl to store the point on the product manifold efficiently in one array, still allowing efficient access to the product elements.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"is_point(M₆, p₃, true)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"true","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"But accessing single components still works the same.”","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"p₃[M₆, 1]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"3-element Vector{Int64}:\n 0\n 0\n 1","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Finally, also the TangentBundle, the manifold collecting all tangent spaces on a manifold is available as”","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₇ = TangentBundle(M₃)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"TangentBundle(Sphere(2, ℝ))","category":"page"},{"location":"tutorials/getstarted.html#Implementing-generic-Functions","page":"🚀 Get Started with Manifolds.jl","title":"Implementing generic Functions","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"In this section we take a look how to implement generic functions on manifolds.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"For our example here, we want to implement the so-called 📖 Bézier curve using the so-called 📖 de-Casteljau algorithm. The linked algorithm can easily be generalised to manifolds by replacing lines with geodesics. This was for example used in [1] and the following example is an extended version of an example from [2].","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"The algorithm works recursively. For the case that we have a Bézier curve with just two points, the algorithm just evaluates the geodesic connecting both at some time point t01. The function to evaluate a shortest geodesic (it might not be unique, but then a deterministic choice is taken) between two points p and q on a manifold M 🔗 shortest_geodesic(M, p, q, t).","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"function de_Casteljau(M::AbstractManifold, t, pts::NTuple{2})\n return shortest_geodesic(M, pts[1], pts[2], t)\nend","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"de_Casteljau (generic function with 1 method)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"function de_Casteljau(M::AbstractManifold, t, pts::NTuple)\n p = de_Casteljau(M, t, pts[1:(end - 1)])\n q = de_Casteljau(M, t, pts[2:end])\n return shortest_geodesic(M, p, q, t)\nend","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"de_Casteljau (generic function with 2 methods)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Which can now be used on any manifold where the shortest geodesic is implemented","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Now on several manifolds the 📖 exponential map and its (locally defined) inverse, the logarithmic map might not be available in an implementation. So one way to generalise this, is the use of a retraction (see [3], Def. 4.1.1 for details) and its (local) inverse.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"The function itself is quite similar to the expponential map, just that 🔗 retract(M, p, X, m) has one further parameter, the type of retraction to take, so m is a subtype of AbstractRetractionMethod m, the same for the 🔗 inverse_retract(M, p, q, n) with an AbstractInverseRetractionMethod n.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Thinking of a generic implementation, we would like to have a way to specify one, that is available. This can be done by using 🔗 default_retraction_method and 🔗 default_inverse_retraction_method, respectively. We implement","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"function generic_de_Casteljau(\n M::AbstractManifold,\n t,\n pts::NTuple{2};\n m::AbstractRetractionMethod=default_retraction_method(M),\n n::AbstractInverseRetractionMethod=default_inverse_retraction_method(M),\n)\n X = inverse_retract(M, pts[1], pts[2], n)\n return retract(M, pts[1], X, t, m)\nend","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"generic_de_Casteljau (generic function with 1 method)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"and for the recursion","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"function generic_de_Casteljau(\n M::AbstractManifold,\n t,\n pts::NTuple;\n m::AbstractRetractionMethod=default_retraction_method(M),\n n::AbstractInverseRetractionMethod=default_inverse_retraction_method(M),\n)\n p = generic_de_Casteljau(M, t, pts[1:(end - 1)]; m=m, n=n)\n q = generic_de_Casteljau(M, t, pts[2:end]; m=m, n=n)\n X = inverse_retract(M, p, q, n)\n return retract(M, p, X, t, m)\nend","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"generic_de_Casteljau (generic function with 2 methods)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Note that on a manifold M where the exponential map is implemented, the default_retraction_method(M) returns 🔗 ExponentialRetraction, which yields that the retract function falls back to calling exp.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"The same mechanism exists for 🔗 parallel_transport_to(M, p, X, q) and the more general 🔗 vector_transport_to(M, p, X, q, m) whose 🔗 AbstractVectorTransportMethod m has a default defined by 🔗 default_vector_transport_method(M).","category":"page"},{"location":"tutorials/getstarted.html#Allocating-and-in-place-computations","page":"🚀 Get Started with Manifolds.jl","title":"Allocating and in-place computations","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Memory allocation is a 🔗 critical performace issue when programming in Julia. To take this into account, Manifolds.jl provides special functions to reduce the amount of allocations.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"We again look at the 📖 exponential map. On a manifold M the exponential map needs a point p (to start from) and a tangent vector X, which can be seen as direction to “walk into” as well as the length to walk into this direction. In Manifolds.jl the function can then be called with q = exp(M, p, X) (see 🔗 exp(M, p, X)). This function returns the resulting point q, which requires to allocate new memory.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"To avoid this allocation, the function 🔗 exp!(M, q, p, X) can be called. Here q is allocated beforehand and is passed as the memory, where the result is returned in. It might be used even for interims computations, as long as it does not introduce side effects. Thas means that even with exp!(M, p, p, X) the result is correct.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Let’s look at an example.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"We take another look at the Sphere, but now a high-dimensional one. We can also illustrate how to generate radnom points and tangent vectors.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M = Sphere(10000)\np₄ = rand(M)\nX = rand(M; vector_at=p₄)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Looking at the allocations required we get","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"@allocated exp(M, p₄, X)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"9921279","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"While if we have already allocated memory for the resulting point on the manifold, for example","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"q₂ = zero(p₄);","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"There are no new memory allocations necessary if we use the in-place function.”","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"@allocated exp!(M, q₂, p₄, X)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"0","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"This methodology is used for all functions that compute a new point or tangent vector. By default all allocating functions allocate memory and call the in-place function. This also means that if you implement a new manifold, you just have to implement the in-place version.","category":"page"},{"location":"tutorials/getstarted.html#Decorating-a-manifold","page":"🚀 Get Started with Manifolds.jl","title":"Decorating a manifold","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"As you saw until now, an 🔗 AbstractManifold describes a Riemannian manifold. For completeness, this also includes the chosen 📖 Riemannian metric tensor or inner product on the tangent spaces.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"In Manifolds.jl these are assumed to be a “reasonable default”. For example on the Sphere(n) we used above, the default metric is the one inherited from restricting the inner product from the embedding space onto each tangent space.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Consider a manifold like","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₈ = SymmetricPositiveDefinite(3)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"SymmetricPositiveDefinite(3)","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"which is the manifold of 33 matrices that are symmetric and positive definite. which has a default as well, the affine invariant AffineInvariantMetric, but also has several different metrics.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"To switch the metric, we use the idea of a 📖 decorator pattern approach. Defining","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"M₈₂ = MetricManifold(M₈, BuresWassersteinMetric())","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"MetricManifold(SymmetricPositiveDefinite(3), BuresWassersteinMetric())","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"changes the manifold to use the BuresWassersteinMetric.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"This changes all functions that depend on the metric, most prominently the Riemannian matric, but also the exponential and logarithmic map and hence also geodesics.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"All functions that are not dependent on a metric – for example the manifold dimension, the tests of points and vectors we already looked at, but also all retractions – stay unchanged. This means that for example","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"[manifold_dimension(M₈₂), manifold_dimension(M₈)]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"2-element Vector{Int64}:\n 6\n 6","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"both calls the same underlying function. On the other hand with","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"p₅, X₅ = one(zeros(3, 3)), [1.0 0.0 1.0; 0.0 1.0 0.0; 1.0 0.0 1.0]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"([1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0], [1.0 0.0 1.0; 0.0 1.0 0.0; 1.0 0.0 1.0])","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"but for example the exponential map and the norm yield different results","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"[exp(M₈, p₅, X₅), exp(M₈₂, p₅, X₅)]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"2-element Vector{Matrix{Float64}}:\n [4.194528049465325 0.0 3.194528049465325; 0.0 2.718281828459045 0.0; 3.194528049465325 0.0 4.194528049465328]\n [2.5 0.0 1.5; 0.0 2.25 0.0; 1.5 0.0 2.5]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"[norm(M₈, p₅, X₅), norm(M₈₂, p₅, X₅)]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"2-element Vector{Float64}:\n 2.23606797749979\n 1.118033988749895","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Technically this done using Traits – the trait here is the IsMetricManifold trait. Our trait system allows to combine traits but also to inherit properties in a hierarchical way, see 🔗 here for the technical details.","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"The same approach is used for","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"specifying a different connection\nspecifying a manifold as a certain quotient manifold\nspecifying a certain 🔗 embeddings\nspecify a certain group action","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Again, for all of these, the concrete types only have to be used if you want to do a second, different from the details, property, for example a second way to embed a manfiold. If a manifold is (in its usual representation) an embedded manifold, this works with the default manifold type already, since then it is again set as the reasonable default.","category":"page"},{"location":"tutorials/getstarted.html#References","page":"🚀 Get Started with Manifolds.jl","title":"References","text":"","category":"section"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"[1]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Bergmann, R. and Gousenbourger, P.-Y.: A variational model for data fitting on manifolds by minimizing the acceleration of a Bézier curve. Frontiers in Applied Mathematics and Statistics, 2018. doi: 10.3389/fams.2018.00059, arXiv: 1807.10090","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"[2]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Axen, S. D., Baran, M., Bergmann, R. and Rzecki, K: Manifolds.jl: An Extensible Julia Framework for Data Analysis on Manifolds, arXiv preprint, 2022, 2106.08777","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"[3]","category":"page"},{"location":"tutorials/getstarted.html","page":"🚀 Get Started with Manifolds.jl","title":"🚀 Get Started with Manifolds.jl","text":"Absil, P.-A., Mahony, R. and Sepulchre R., Optimization Algorithms on Matrix Manifolds Princeton University Press, 2008, doi: 10.1515/9781400830244 open access","category":"page"},{"location":"manifolds/hyperbolic.html#HyperbolicSpace","page":"Hyperbolic space","title":"Hyperbolic space","text":"","category":"section"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"The hyperbolic space can be represented in three different models.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"Hyperboloid which is the default model, i.e. is used when using arbitrary array types for points and tangent vectors\nPoincaré ball with separate types for points and tangent vectors and a visualization for the two-dimensional case\nPoincaré half space with separate types for points and tangent vectors and a visualization for the two-dimensional cae.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"In the following the common functions are collected.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"A function in this general section uses vectors interpreted as if in the hyperboloid model, and other representations usually just convert to this representation to use these general functions.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"Modules = [Manifolds]\nPages = [\"manifolds/Hyperbolic.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/hyperbolic.html#Manifolds.Hyperbolic","page":"Hyperbolic space","title":"Manifolds.Hyperbolic","text":"Hyperbolic{N} <: AbstractDecoratorManifold{ℝ}\n\nThe hyperbolic space mathcal H^n represented by n+1-Tuples, i.e. embedded in the Lorentzian manifold equipped with the MinkowskiMetric cdotcdot_mathrmM. The space is defined as\n\nmathcal H^n = Biglp ℝ^n+1 Big pp_mathrmM= -p_n+1^2\n + displaystylesum_k=1^n p_k^2 = -1 p_n+1 0Bigr\n\nThe tangent space T_p mathcal H^n is given by\n\nT_p mathcal H^n = bigl\nX ℝ^n+1 pX_mathrmM = 0\nbigr\n\nNote that while the MinkowskiMetric renders the Lorentz manifold (only) pseudo-Riemannian, on the tangent bundle of the Hyperbolic space it induces a Riemannian metric. The corresponding sectional curvature is -1.\n\nIf p and X are Vectors of length n+1 they are assumed to be a HyperboloidPoint and a HyperboloidTVector, respectively\n\nOther models are the Poincaré ball model, see PoincareBallPoint and PoincareBallTVector, respectiely and the Poincaré half space model, see PoincareHalfSpacePoint and PoincareHalfSpaceTVector, respectively.\n\nConstructor\n\nHyperbolic(n)\n\nGenerate the Hyperbolic manifold of dimension n.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/hyperbolic.html#Manifolds.HyperboloidPoint","page":"Hyperbolic space","title":"Manifolds.HyperboloidPoint","text":"HyperboloidPoint <: AbstractManifoldPoint\n\nIn the Hyperboloid model of the Hyperbolic mathcal H^n points are represented as vectors in ℝ^n+1 with MinkowskiMetric equal to -1.\n\nThis representation is the default, i.e. AbstractVectors are assumed to have this repesentation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/hyperbolic.html#Manifolds.HyperboloidTVector","page":"Hyperbolic space","title":"Manifolds.HyperboloidTVector","text":"HyperboloidTVector <: TVector\n\nIn the Hyperboloid model of the Hyperbolic mathcal H^n tangent vctors are represented as vectors in ℝ^n+1 with MinkowskiMetric pX_mathrmM=0 to their base point p.\n\nThis representation is the default, i.e. vectors are assumed to have this repesentation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/hyperbolic.html#Manifolds.PoincareBallPoint","page":"Hyperbolic space","title":"Manifolds.PoincareBallPoint","text":"PoincareBallPoint <: AbstractManifoldPoint\n\nA point on the Hyperbolic manifold mathcal H^n can be represented as a vector of norm less than one in mathbb R^n.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/hyperbolic.html#Manifolds.PoincareBallTVector","page":"Hyperbolic space","title":"Manifolds.PoincareBallTVector","text":"PoincareBallTVector <: TVector\n\nIn the Poincaré ball model of the Hyperbolic mathcal H^n tangent vectors are represented as vectors in ℝ^n.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/hyperbolic.html#Manifolds.PoincareHalfSpacePoint","page":"Hyperbolic space","title":"Manifolds.PoincareHalfSpacePoint","text":"PoincareHalfSpacePoint <: AbstractManifoldPoint\n\nA point on the Hyperbolic manifold mathcal H^n can be represented as a vector in the half plane, i.e. x ℝ^n with x_d 0.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/hyperbolic.html#Manifolds.PoincareHalfSpaceTVector","page":"Hyperbolic space","title":"Manifolds.PoincareHalfSpaceTVector","text":"PoincareHalfPlaneTVector <: TVector\n\nIn the Poincaré half plane model of the Hyperbolic mathcal H^n tangent vectors are represented as vectors in ℝ^n.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/hyperbolic.html#Base.exp-Tuple{Hyperbolic, Vararg{Any}}","page":"Hyperbolic space","title":"Base.exp","text":"exp(M::Hyperbolic, p, X)\n\nCompute the exponential map on the Hyperbolic space mathcal H^n emanating from p towards X. The formula reads\n\nexp_p X = cosh(sqrtXX_mathrmM)p\n+ sinh(sqrtXX_mathrmM)fracXsqrtXX_mathrmM\n\nwhere cdotcdot_mathrmM denotes the MinkowskiMetric on the embedding, the Lorentzian manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.log-Tuple{Hyperbolic, Vararg{Any}}","page":"Hyperbolic space","title":"Base.log","text":"log(M::Hyperbolic, p, q)\n\nCompute the logarithmic map on the Hyperbolic space mathcal H^n, the tangent vector representing the geodesic starting from p reaches q after time 1. The formula reads for p q\n\nlog_p q = d_mathcal H^n(pq)\nfracq-pq_mathrmM plVert q-pq_mathrmM p rVert_2\n\nwhere cdotcdot_mathrmM denotes the MinkowskiMetric on the embedding, the Lorentzian manifold. For p=q the logarihmic map is equal to the zero vector.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.check_point-Tuple{Hyperbolic, Any}","page":"Hyperbolic space","title":"ManifoldsBase.check_point","text":"check_point(M::Hyperbolic, p; kwargs...)\n\nCheck whether p is a valid point on the Hyperbolic M.\n\nFor the HyperboloidPoint or plain vectors this means that, p is a vector of length n+1 with inner product in the embedding of -1, see MinkowskiMetric. The tolerance for the last test can be set using the kwargs....\n\nFor the PoincareBallPoint a valid point is a vector p ℝ^n with a norm stricly less than 1.\n\nFor the PoincareHalfSpacePoint a valid point is a vector from p ℝ^n with a positive last entry, i.e. p_n0\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.check_vector-Tuple{Hyperbolic, Any, Any}","page":"Hyperbolic space","title":"ManifoldsBase.check_vector","text":"check_vector(M::Hyperbolic{n}, p, X; kwargs... )\n\nCheck whether X is a tangent vector to p on the Hyperbolic M, i.e. after check_point(M,p), X has to be of the same dimension as p. The tolerance for the last test can be set using the kwargs....\n\nFor a the hyperboloid model or vectors, X has to be orthogonal to p with respect to the inner product from the embedding, see MinkowskiMetric.\n\nFor a the Poincaré ball as well as the Poincaré half plane model, X has to be a vector from ℝ^n.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.injectivity_radius-Tuple{Hyperbolic}","page":"Hyperbolic space","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::Hyperbolic)\ninjectivity_radius(M::Hyperbolic, p)\n\nReturn the injectivity radius on the Hyperbolic, which is .\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.is_flat-Tuple{Hyperbolic}","page":"Hyperbolic space","title":"ManifoldsBase.is_flat","text":"is_flat(::Hyperbolic)\n\nReturn false. Hyperbolic is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.manifold_dimension-Union{Tuple{Hyperbolic{N}}, Tuple{N}} where N","page":"Hyperbolic space","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::Hyperbolic)\n\nReturn the dimension of the hyperbolic space manifold mathcal H^n, i.e. dim(mathcal H^n) = n.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.parallel_transport_to-Tuple{Hyperbolic, Any, Any, Any}","page":"Hyperbolic space","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::Hyperbolic, p, X, q)\n\nCompute the paralllel transport of the X from the tangent space at p on the Hyperbolic space mathcal H^n to the tangent at q along the geodesic connecting p and q. The formula reads\n\nmathcal P_qpX = X - fraclog_p qX_pd^2_mathcal H^n(pq)\nbigl(log_p q + log_qp bigr)\n\nwhere cdotcdot_p denotes the inner product in the tangent space at p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.project-Tuple{Hyperbolic, Any, Any}","page":"Hyperbolic space","title":"ManifoldsBase.project","text":"project(M::Hyperbolic, p, X)\n\nPerform an orthogonal projection with respect to the Minkowski inner product of X onto the tangent space at p of the Hyperbolic space M.\n\nThe formula reads\n\nY = X + pX_mathrmM p\n\nwhere cdot cdot_mathrmM denotes the MinkowskiMetric on the embedding, the Lorentzian manifold.\n\nnote: Note\nProjection is only available for the (default) HyperboloidTVector representation, the others don't have such an embedding\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Statistics.mean-Tuple{Hyperbolic, Vararg{Any}}","page":"Hyperbolic space","title":"Statistics.mean","text":"mean(\n M::Hyperbolic,\n x::AbstractVector,\n [w::AbstractWeights,]\n method = CyclicProximalPointEstimation();\n kwargs...,\n)\n\nCompute the Riemannian mean of x on the Hyperbolic space using CyclicProximalPointEstimation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#hyperboloid_model","page":"Hyperbolic space","title":"hyperboloid model","text":"","category":"section"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"Modules = [Manifolds]\nPrivate = false\nPages = [\"manifolds/HyperbolicHyperboloid.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{HyperboloidPoint}, PoincareBallPoint}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{HyperboloidPoint}, p::PoincareBallPoint)\nconvert(::Type{AbstractVector}, p::PoincareBallPoint)\n\nconvert a point PoincareBallPoint x (from ℝ^n) from the Poincaré ball model of the Hyperbolic manifold mathcal H^n to a HyperboloidPoint π(p) ℝ^n+1. The isometry is defined by\n\nπ(p) = frac11-lVert p rVert^2\nbeginpmatrix2p_12p_n1+lVert p rVert^2endpmatrix\n\nNote that this is also used, when the type to convert to is a vector.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{HyperboloidPoint}, PoincareHalfSpacePoint}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{HyperboloidPoint}, p::PoincareHalfSpacePoint)\nconvert(::Type{AbstractVector}, p::PoincareHalfSpacePoint)\n\nconvert a point PoincareHalfSpacePoint p (from ℝ^n) from the Poincaré half plane model of the Hyperbolic manifold mathcal H^n to a HyperboloidPoint π(p) ℝ^n+1.\n\nThis is done in two steps, namely transforming it to a Poincare ball point and from there further on to a Hyperboloid point.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{HyperboloidTVector}, PoincareBallPoint, PoincareBallTVector}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{HyperboloidTVector}, p::PoincareBallPoint, X::PoincareBallTVector)\nconvert(::Type{AbstractVector}, p::PoincareBallPoint, X::PoincareBallTVector)\n\nConvert the PoincareBallTVector X from the tangent space at p to a HyperboloidTVector by computing the push forward of the isometric map, cf. convert(::Type{HyperboloidPoint}, p::PoincareBallPoint).\n\nThe push forward π_*(p) maps from ℝ^n to a subspace of ℝ^n+1, the formula reads\n\nπ_*(p)X = beginpmatrix\n frac2X_11-lVert p rVert^2 + frac4(1-lVert p rVert^2)^2Xpp_1\n \n frac2X_n1-lVert p rVert^2 + frac4(1-lVert p rVert^2)^2Xpp_n\n frac4(1-lVert p rVert^2)^2Xp\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{HyperboloidTVector}, PoincareHalfSpacePoint, PoincareHalfSpaceTVector}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{HyperboloidTVector}, p::PoincareHalfSpacePoint, X::PoincareHalfSpaceTVector)\nconvert(::Type{AbstractVector}, p::PoincareHalfSpacePoint, X::PoincareHalfSpaceTVector)\n\nconvert a point PoincareHalfSpaceTVector X (from ℝ^n) at p from the Poincaré half plane model of the Hyperbolic manifold mathcal H^n to a HyperboloidTVector π(p) ℝ^n+1.\n\nThis is done in two steps, namely transforming it to a Poincare ball point and from there further on to a Hyperboloid point.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{Tuple{HyperboloidPoint, HyperboloidTVector}}, Tuple{PoincareBallPoint, PoincareBallTVector}}","page":"Hyperbolic space","title":"Base.convert","text":"convert(\n ::Type{Tuple{HyperboloidPoint,HyperboloidTVector}}.\n (p,X)::Tuple{PoincareBallPoint,PoincareBallTVector}\n)\nconvert(\n ::Type{Tuple{P,T}},\n (p, X)::Tuple{PoincareBallPoint,PoincareBallTVector},\n) where {P<:AbstractVector, T <: AbstractVector}\n\nConvert a PoincareBallPoint p and a PoincareBallTVector X to a HyperboloidPoint and a HyperboloidTVector simultaneously, see convert(::Type{HyperboloidPoint}, ::PoincareBallPoint) and convert(::Type{HyperboloidTVector}, ::PoincareBallPoint, ::PoincareBallTVector) for the formulae.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{Tuple{HyperboloidPoint, HyperboloidTVector}}, Tuple{PoincareHalfSpacePoint, PoincareHalfSpaceTVector}}","page":"Hyperbolic space","title":"Base.convert","text":"convert(\n ::Type{Tuple{HyperboloidPoint,HyperboloidTVector},\n (p,X)::Tuple{PoincareHalfSpacePoint, PoincareHalfSpaceTVector}\n)\nconvert(\n ::Type{Tuple{T,T},\n (p,X)::Tuple{PoincareHalfSpacePoint, PoincareHalfSpaceTVector}\n) where {T<:AbstractVector}\n\nconvert a point PoincareHalfSpaceTVector X (from ℝ^n) at p from the Poincaré half plane model of the Hyperbolic manifold mathcal H^n to a tuple of a HyperboloidPoint and a HyperboloidTVector π(p) ℝ^n+1 simultaneously.\n\nThis is done in two steps, namely transforming it to the Poincare ball model and from there further on to a Hyperboloid.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldDiff.riemannian_Hessian-Tuple{Hyperbolic, Vararg{Any, 4}}","page":"Hyperbolic space","title":"ManifoldDiff.riemannian_Hessian","text":"riemannian_Hessian(M::Hyperbolic, p, G, H, X)\n\nThe Riemannian Hessian can be computed by adopting Remark 4.1 in [Ngu23]. Let nabla f(p) denote the Euclidean gradient G, nabla^2 f(p)X the Euclidean Hessian H, and mathbfg = mathbfg^-1 = operatornamediag(11-1). The formula reads\n\n operatornameHessf(p)X\n =\n operatornameproj_T_pmathcal Mbigl( mathbfg^-1nabla^2f(p)X + Xpmathbfg^-1f(p)_pbigr)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.change_representer-Tuple{Hyperbolic, EuclideanMetric, Any, Any}","page":"Hyperbolic space","title":"ManifoldsBase.change_representer","text":"change_representer(M::Hyperbolic{n}, ::EuclideanMetric, p, X)\n\nChange the Eucliden representer X of a cotangent vector at point p. We only have to correct for the metric, which means that the sign of the last entry changes, since for the result Y we are looking for a tangent vector such that\n\n g_p(YZ) = -y_n+1z_n+1 + sum_i=1^n y_iz_i = sum_i=1^n+1 z_ix_i\n\nholds, which directly yields y_i=x_i for i=1ldotsn and y_n+1=-x_n+1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.distance-Tuple{Hyperbolic, Any, Any}","page":"Hyperbolic space","title":"ManifoldsBase.distance","text":"distance(M::Hyperbolic, p, q)\ndistance(M::Hyperbolic, p::HyperboloidPoint, q::HyperboloidPoint)\n\nCompute the distance on the Hyperbolic M, which reads\n\nd_mathcal H^n(pq) = operatornameacosh( - p q_mathrmM)\n\nwhere cdotcdot_mathrmM denotes the MinkowskiMetric on the embedding, the Lorentzian manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.get_coordinates-Tuple{Hyperbolic, Any, Any, DefaultOrthonormalBasis}","page":"Hyperbolic space","title":"ManifoldsBase.get_coordinates","text":"get_coordinates(M::Hyperbolic, p, X, ::DefaultOrthonormalBasis)\n\nCompute the coordinates of the vector X with respect to the orthogonalized version of the unit vectors from ℝ^n, where n is the manifold dimension of the Hyperbolic M, utting them intop the tangent space at p and orthonormalizing them.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.get_vector-Tuple{Hyperbolic, Any, Any, DefaultOrthonormalBasis}","page":"Hyperbolic space","title":"ManifoldsBase.get_vector","text":"get_vector(M::Hyperbolic, p, c, ::DefaultOrthonormalBasis)\n\nCompute the vector from the coordinates with respect to the orthogonalized version of the unit vectors from ℝ^n, where n is the manifold dimension of the Hyperbolic M, utting them intop the tangent space at p and orthonormalizing them.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.inner-Tuple{Hyperbolic, Any, Any, Any}","page":"Hyperbolic space","title":"ManifoldsBase.inner","text":"inner(M::Hyperbolic{n}, p, X, Y)\ninner(M::Hyperbolic{n}, p::HyperboloidPoint, X::HyperboloidTVector, Y::HyperboloidTVector)\n\nCmpute the inner product in the Hyperboloid model, i.e. the minkowski_metric in the embedding. The formula reads\n\ng_p(XY) = XY_mathrmM = -X_nY_n + displaystylesum_k=1^n-1 X_kY_k\n\nThis employs the metric of the embedding, see Lorentz space.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#hyperboloid_plot","page":"Hyperbolic space","title":"Visualization of the Hyperboloid","text":"","category":"section"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"For the case of Hyperbolic(2) there is plotting available based on a PlottingRecipe. You can easily plot points, connecting geodesics as well as tangent vectors.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"note: Note\nThe recipes are only loaded if Plots.jl or RecipesBase.jl is loaded.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"If we consider a set of points, we can first plot these and their connecting geodesics using the geodesic_interpolation for the points. This variable specifies with how many points a geodesic between two successive points is sampled (per default it's -1, which deactivates geodesics) and the line style is set to be a path.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"In general you can plot the surface of the hyperboloid either as wireframe (wireframe=true) additionally specifying wires (or wires_x and wires_y) to change the density of wires and a wireframe_color. The same holds for the plot as a surface (which is false by default) and its surface_resolution (or surface_resolution_x or surface_resolution_y) and a surface_color.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"using Manifolds, Plots\nM = Hyperbolic(2)\npts = [ [0.85*cos(φ), 0.85*sin(φ), sqrt(0.85^2+1)] for φ ∈ range(0,2π,length=11) ]\nscene = plot(M, pts; geodesic_interpolation=100)","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"To just plot the points atop, we can just omit the geodesic_interpolation parameter to obtain a scatter plot. Note that we avoid redrawing the wireframe in the following plot! calls.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"plot!(scene, M, pts; wireframe=false)","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"We can further generate tangent vectors in these spaces and use a plot for there. Keep in mind that a tangent vector in plotting always requires its base point.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"pts2 = [ [0.45 .*cos(φ + 6π/11), 0.45 .*sin(φ + 6π/11), sqrt(0.45^2+1) ] for φ ∈ range(0,2π,length=11)]\nvecs = log.(Ref(M),pts,pts2)\nplot!(scene, M, pts, vecs; wireframe=false)","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"Just to illustrate, for the first point the tangent vector is pointing along the following geodesic","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"plot!(scene, M, [pts[1], pts2[1]]; geodesic_interpolation=100, wireframe=false)","category":"page"},{"location":"manifolds/hyperbolic.html#Internal-functions","page":"Hyperbolic space","title":"Internal functions","text":"","category":"section"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"The following functions are available for internal use to construct points in the hyperboloid model","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"Modules = [Manifolds]\nPublic = false\nPages = [\"manifolds/HyperbolicHyperboloid.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/hyperbolic.html#Manifolds._hyperbolize-Tuple{Hyperbolic, Any, Any}","page":"Hyperbolic space","title":"Manifolds._hyperbolize","text":"_hyperbolize(M, p, Y)\n\nGiven the Hyperbolic(n) manifold using the hyperboloid model and a point p thereon, we can put a vector Yin ℝ^n into the tangent space by computing its last component such that for the resulting p we have that its minkowski_metric is pX_mathrmM = 0, i.e. X_n+1 = fractilde p Yp_n+1, where tilde p = (p_1ldotsp_n).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Manifolds._hyperbolize-Tuple{Hyperbolic, Any}","page":"Hyperbolic space","title":"Manifolds._hyperbolize","text":"_hyperbolize(M, q)\n\nGiven the Hyperbolic(n) manifold using the hyperboloid model, a point from the qin ℝ^n can be set onto the manifold by computing its last component such that for the resulting p we have that its minkowski_metric is pp_mathrmM = - 1, i.e. p_n+1 = sqrtlVert q rVert^2 - 1\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#poincare_ball","page":"Hyperbolic space","title":"Poincaré ball model","text":"","category":"section"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"Modules = [Manifolds]\nPages = [\"manifolds/HyperbolicPoincareBall.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{PoincareBallPoint}, Any}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{PoincareBallPoint}, p::HyperboloidPoint)\nconvert(::Type{PoincareBallPoint}, p::T) where {T<:AbstractVector}\n\nconvert a HyperboloidPoint pℝ^n+1 from the hyperboloid model of the Hyperbolic manifold mathcal H^n to a PoincareBallPoint π(p)ℝ^n in the Poincaré ball model. The isometry is defined by\n\nπ(p) = frac11+p_n+1 beginpmatrixp_1p_nendpmatrix\n\nNote that this is also used, when x is a vector.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{PoincareBallPoint}, PoincareHalfSpacePoint}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{PoincareBallPoint}, p::PoincareHalfSpacePoint)\n\nconvert a point PoincareHalfSpacePoint p (from ℝ^n) from the Poincaré half plane model of the Hyperbolic manifold mathcal H^n to a PoincareBallPoint π(p) ℝ^n. Denote by tilde p = (p_1ldotsp_d-1)^mathrmT. Then the isometry is defined by\n\nπ(p) = frac1lVert tilde p rVert^2 + (p_n+1)^2\nbeginpmatrix2p_12p_n-1lVert prVert^2 - 1endpmatrix\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{PoincareBallTVector}, Any}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{PoincareBallTVector}, p::HyperboloidPoint, X::HyperboloidTVector)\nconvert(::Type{PoincareBallTVector}, p::P, X::T) where {P<:AbstractVector, T<:AbstractVector}\n\nconvert a HyperboloidTVector X at p to a PoincareBallTVector on the Hyperbolic manifold mathcal H^n by computing the push forward π_*(p)X of the isometry π that maps from the Hyperboloid to the Poincaré ball, cf. convert(::Type{PoincareBallPoint}, ::HyperboloidPoint).\n\nThe formula reads\n\nπ_*(p)X = frac1p_n+1+1Bigl(tilde X - fracX_n+1p_n+1+1tilde p Bigl)\n\nwhere tilde X = beginpmatrixX_1X_nendpmatrix and tilde p = beginpmatrixp_1p_nendpmatrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{PoincareBallTVector}, PoincareHalfSpacePoint, PoincareHalfSpaceTVector}","page":"Hyperbolic space","title":"Base.convert","text":"convert(\n ::Type{PoincareBallTVector},\n p::PoincareHalfSpacePoint,\n X::PoincareHalfSpaceTVector\n)\n\nconvert a PoincareHalfSpaceTVector X at p to a PoincareBallTVector on the Hyperbolic manifold mathcal H^n by computing the push forward π_*(p)X of the isometry π that maps from the Poincaré half space to the Poincaré ball, cf. convert(::Type{PoincareBallPoint}, ::PoincareHalfSpacePoint).\n\nThe formula reads\n\nπ_*(p)X =\nfrac1lVert tilde prVert^2 + (1+p_n)^2\nbeginpmatrix\n2X_1\n\n2X_n-1\n2Xp\nendpmatrix\n-\nfrac2(lVert tilde prVert^2 + (1+p_n)^2)^2\nbeginpmatrix\n2p_1(Xp+X_n)\n\n2p_n-1(Xp+X_n)\n(lVert p rVert^2-1)(Xp+X_n)\nendpmatrix\n\nwhere tilde p = beginpmatrixp_1p_n-1endpmatrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{Tuple{PoincareBallPoint, PoincareBallTVector}}, Tuple{HyperboloidPoint, HyperboloidTVector}}","page":"Hyperbolic space","title":"Base.convert","text":"convert(\n ::Type{Tuple{PoincareBallPoint,PoincareBallTVector}},\n (p,X)::Tuple{HyperboloidPoint,HyperboloidTVector}\n)\nconvert(\n ::Type{Tuple{PoincareBallPoint,PoincareBallTVector}},\n (p, X)::Tuple{P,T},\n) where {P<:AbstractVector, T <: AbstractVector}\n\nConvert a HyperboloidPoint p and a HyperboloidTVector X to a PoincareBallPoint and a PoincareBallTVector simultaneously, see convert(::Type{PoincareBallPoint}, ::HyperboloidPoint) and convert(::Type{PoincareBallTVector}, ::HyperboloidPoint, ::HyperboloidTVector) for the formulae.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{Tuple{PoincareBallPoint, PoincareBallTVector}}, Tuple{PoincareHalfSpacePoint, PoincareHalfSpaceTVector}}","page":"Hyperbolic space","title":"Base.convert","text":"convert(\n ::Type{Tuple{PoincareBallPoint,PoincareBallTVector}},\n (p,X)::Tuple{HyperboloidPoint,HyperboloidTVector}\n)\nconvert(\n ::Type{Tuple{PoincareBallPoint,PoincareBallTVector}},\n (p, X)::Tuple{T,T},\n) where {T <: AbstractVector}\n\nConvert a PoincareHalfSpacePoint p and a PoincareHalfSpaceTVector X to a PoincareBallPoint and a PoincareBallTVector simultaneously, see convert(::Type{PoincareBallPoint}, ::PoincareHalfSpacePoint) and convert(::Type{PoincareBallTVector}, ::PoincareHalfSpacePoint, ::PoincareHalfSpaceTVector) for the formulae.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.change_metric-Tuple{Hyperbolic, EuclideanMetric, PoincareBallPoint, PoincareBallTVector}","page":"Hyperbolic space","title":"ManifoldsBase.change_metric","text":"change_metric(M::Hyperbolic{n}, ::EuclideanMetric, p::PoincareBallPoint, X::PoincareBallTVector)\n\nSince in the metric we always have the term α = frac21-sum_i=1^n p_i^2 per element, the correction for the metric reads Z = frac1αX.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.change_representer-Tuple{Hyperbolic, EuclideanMetric, PoincareBallPoint, PoincareBallTVector}","page":"Hyperbolic space","title":"ManifoldsBase.change_representer","text":"change_representer(M::Hyperbolic{n}, ::EuclideanMetric, p::PoincareBallPoint, X::PoincareBallTVector)\n\nSince in the metric we have the term α = frac21-sum_i=1^n p_i^2 per element, the correction for the gradient reads Y = frac1α^2X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.distance-Tuple{Hyperbolic, PoincareBallPoint, PoincareBallPoint}","page":"Hyperbolic space","title":"ManifoldsBase.distance","text":"distance(::Hyperbolic, p::PoincareBallPoint, q::PoincareBallPoint)\n\nCompute the distance on the Hyperbolic manifold mathcal H^n represented in the Poincaré ball model. The formula reads\n\nd_mathcal H^n(pq) =\noperatornameacoshBigl(\n 1 + frac2lVert p - q rVert^2(1-lVert prVert^2)(1-lVert qrVert^2)\nBigr)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.inner-Tuple{Hyperbolic, PoincareBallPoint, PoincareBallTVector, PoincareBallTVector}","page":"Hyperbolic space","title":"ManifoldsBase.inner","text":"inner(::Hyperbolic, p::PoincareBallPoint, X::PoincareBallTVector, Y::PoincareBallTVector)\n\nCompute the inner producz in the Poincaré ball model. The formula reads\n\ng_p(XY) = frac4(1-lVert p rVert^2)^2 X Y \n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.project-Tuple{Hyperbolic, PoincareBallPoint, PoincareBallTVector}","page":"Hyperbolic space","title":"ManifoldsBase.project","text":"project(::Hyperbolic, ::PoincareBallPoint, ::PoincareBallTVector)\n\nprojction of tangent vectors in the Poincaré ball model is just the identity, since the tangent space consists of all ℝ^n.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#poincare_ball_plot","page":"Hyperbolic space","title":"Visualization of the Poincaré ball","text":"","category":"section"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"For the case of Hyperbolic(2) there is a plotting available based on a PlottingRecipe you can easily plot points, connecting geodesics as well as tangent vectors.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"note: Note\nThe recipes are only loaded if Plots.jl or RecipesBase.jl is loaded.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"If we consider a set of points, we can first plot these and their connecting geodesics using the geodesic_interpolation For the points. This variable specifies with how many points a geodesic between two successive points is sampled (per default it's -1, which deactivates geodesics) and the line style is set to be a path. Another keyword argument added is the border of the Poincaré disc, namely circle_points = 720 resolution of the drawn boundary (every hlaf angle) as well as its color, hyperbolic_border_color = RGBA(0.0, 0.0, 0.0, 1.0).","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"using Manifolds, Plots\nM = Hyperbolic(2)\npts = PoincareBallPoint.( [0.85 .* [cos(φ), sin(φ)] for φ ∈ range(0,2π,length=11)])\nscene = plot(M, pts, geodesic_interpolation = 100)","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"To just plot the points atop, we can just omit the geodesic_interpolation parameter to obtain a scatter plot","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"plot!(scene, M, pts)","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"We can further generate tangent vectors in these spaces and use a plot for there. Keep in mind, that a tangent vector in plotting always requires its base point","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"pts2 = PoincareBallPoint.( [0.45 .* [cos(φ + 6π/11), sin(φ + 6π/11)] for φ ∈ range(0,2π,length=11)])\nvecs = log.(Ref(M),pts,pts2)\nplot!(scene, M, pts,vecs)","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"Just to illustrate, for the first point the tangent vector is pointing along the following geodesic","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"plot!(scene, M, [pts[1], pts2[1]], geodesic_interpolation=100)","category":"page"},{"location":"manifolds/hyperbolic.html#poincare_halfspace","page":"Hyperbolic space","title":"Poincaré half space model","text":"","category":"section"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"Modules = [Manifolds]\nPages = [\"manifolds/HyperbolicPoincareHalfspace.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{PoincareHalfSpacePoint}, Any}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{PoincareHalfSpacePoint}, p::Hyperboloid)\nconvert(::Type{PoincareHalfSpacePoint}, p)\n\nconvert a HyperboloidPoint or Vectorp (from ℝ^n+1) from the Hyperboloid model of the Hyperbolic manifold mathcal H^n to a PoincareHalfSpacePoint π(x) ℝ^n.\n\nThis is done in two steps, namely transforming it to a Poincare ball point and from there further on to a PoincareHalfSpacePoint point.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{PoincareHalfSpacePoint}, PoincareBallPoint}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{PoincareHalfSpacePoint}, p::PoincareBallPoint)\n\nconvert a point PoincareBallPoint p (from ℝ^n) from the Poincaré ball model of the Hyperbolic manifold mathcal H^n to a PoincareHalfSpacePoint π(p) ℝ^n. Denote by tilde p = (p_1ldotsp_n-1). Then the isometry is defined by\n\nπ(p) = frac1lVert tilde p rVert^2 - (p_n-1)^2\nbeginpmatrix2p_12p_n-11-lVert prVert^2endpmatrix\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{PoincareHalfSpaceTVector}, Any}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{PoincareHalfSpaceTVector}, p::HyperboloidPoint, ::HyperboloidTVector)\nconvert(::Type{PoincareHalfSpaceTVector}, p::P, X::T) where {P<:AbstractVector, T<:AbstractVector}\n\nconvert a HyperboloidTVector X at p to a PoincareHalfSpaceTVector on the Hyperbolic manifold mathcal H^n by computing the push forward π_*(p)X of the isometry π that maps from the Hyperboloid to the Poincaré half space, cf. convert(::Type{PoincareHalfSpacePoint}, ::HyperboloidPoint).\n\nThis is done similarly to the approach there, i.e. by using the Poincaré ball model as an intermediate step.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{PoincareHalfSpaceTVector}, PoincareBallPoint, PoincareBallTVector}","page":"Hyperbolic space","title":"Base.convert","text":"convert(::Type{PoincareHalfSpaceTVector}, p::PoincareBallPoint, X::PoincareBallTVector)\n\nconvert a PoincareBallTVector X at p to a PoincareHalfSpacePoint on the Hyperbolic manifold mathcal H^n by computing the push forward π_*(p)X of the isometry π that maps from the Poincaré ball to the Poincaré half space, cf. convert(::Type{PoincareHalfSpacePoint}, ::PoincareBallPoint).\n\nThe formula reads\n\nπ_*(p)X =\nfrac1lVert tilde prVert^2 + (1-p_n)^2\nbeginpmatrix\n2X_1\n\n2X_n-1\n-2Xp\nendpmatrix\n-\nfrac2(lVert tilde prVert^2 + (1-p_n)^2)^2\nbeginpmatrix\n2p_1(Xp-X_n)\n\n2p_n-1(Xp-X_n)\n(lVert p rVert^2-1)(Xp-X_n)\nendpmatrix\n\nwhere tilde p = beginpmatrixp_1p_n-1endpmatrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{Tuple{PoincareHalfSpacePoint, PoincareHalfSpaceTVector}}, Tuple{HyperboloidPoint, HyperboloidTVector}}","page":"Hyperbolic space","title":"Base.convert","text":"convert(\n ::Type{Tuple{PoincareHalfSpacePoint,PoincareHalfSpaceTVector}},\n (p,X)::Tuple{HyperboloidPoint,HyperboloidTVector}\n)\nconvert(\n ::Type{Tuple{PoincareHalfSpacePoint,PoincareHalfSpaceTVector}},\n (p, X)::Tuple{P,T},\n) where {P<:AbstractVector, T <: AbstractVector}\n\nConvert a HyperboloidPoint p and a HyperboloidTVector X to a PoincareHalfSpacePoint and a PoincareHalfSpaceTVector simultaneously, see convert(::Type{PoincareHalfSpacePoint}, ::HyperboloidPoint) and convert(::Type{PoincareHalfSpaceTVector}, ::Tuple{HyperboloidPoint,HyperboloidTVector}) for the formulae.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#Base.convert-Tuple{Type{Tuple{PoincareHalfSpacePoint, PoincareHalfSpaceTVector}}, Tuple{PoincareBallPoint, PoincareBallTVector}}","page":"Hyperbolic space","title":"Base.convert","text":"convert(\n ::Type{Tuple{PoincareHalfSpacePoint,PoincareHalfSpaceTVector}},\n (p,X)::Tuple{PoincareBallPoint,PoincareBallTVector}\n)\n\nConvert a PoincareBallPoint p and a PoincareBallTVector X to a PoincareHalfSpacePoint and a PoincareHalfSpaceTVector simultaneously, see convert(::Type{PoincareHalfSpacePoint}, ::PoincareBallPoint) and convert(::Type{PoincareHalfSpaceTVector}, ::PoincareBallPoint,::PoincareBallTVector) for the formulae.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.distance-Tuple{Hyperbolic, PoincareHalfSpacePoint, PoincareHalfSpacePoint}","page":"Hyperbolic space","title":"ManifoldsBase.distance","text":"distance(::Hyperbolic, p::PoincareHalfSpacePoint, q::PoincareHalfSpacePoint)\n\nCompute the distance on the Hyperbolic manifold mathcal H^n represented in the Poincaré half space model. The formula reads\n\nd_mathcal H^n(pq) = operatornameacoshBigl( 1 + fraclVert p - q rVert^22 p_n q_n Bigr)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.inner-Tuple{Hyperbolic, PoincareHalfSpacePoint, PoincareHalfSpaceTVector, PoincareHalfSpaceTVector}","page":"Hyperbolic space","title":"ManifoldsBase.inner","text":"inner(\n ::Hyperbolic{n},\n p::PoincareHalfSpacePoint,\n X::PoincareHalfSpaceTVector,\n Y::PoincareHalfSpaceTVector\n)\n\nCompute the inner product in the Poincaré half space model. The formula reads\n\ng_p(XY) = fracXYp_n^2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#ManifoldsBase.project-Tuple{Hyperbolic, PoincareHalfSpaceTVector}","page":"Hyperbolic space","title":"ManifoldsBase.project","text":"project(::Hyperbolic, ::PoincareHalfSpacePoint ::PoincareHalfSpaceTVector)\n\nprojction of tangent vectors in the Poincaré half space model is just the identity, since the tangent space consists of all ℝ^n.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/hyperbolic.html#poincare_half_plane_plot","page":"Hyperbolic space","title":"Visualization on the Poincaré half plane","text":"","category":"section"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"For the case of Hyperbolic(2) there is a plotting available based on a PlottingRecipe you can easily plot points, connecting geodesics as well as tangent vectors.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"note: Note\nThe recipes are only loaded if Plots.jl or RecipesBase.jl is loaded.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"We again have two different recipes, one for points, one for tangent vectors, where the first one again can be equipped with geodesics between the points. In the following example we generate 7 points on an ellipse in the Hyperboloid model.","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"using Manifolds, Plots\nM = Hyperbolic(2)\npre_pts = [2.0 .* [5.0*cos(φ), sin(φ)] for φ ∈ range(0,2π,length=7)]\npts = convert.(\n Ref(PoincareHalfSpacePoint),\n Manifolds._hyperbolize.(Ref(M), pre_pts)\n)\nscene = plot(M, pts, geodesic_interpolation = 100)","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"To just plot the points atop, we can just omit the geodesic_interpolation parameter to obtain a scatter plot","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"plot!(scene, M, pts)","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"We can further generate tangent vectors in these spaces and use a plot for there. Keep in mind, that a tangent vector in plotting always requires its base point. Here we would like to look at the tangent vectors pointing to the origin","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"origin = PoincareHalfSpacePoint([0.0,1.0])\nvecs = [log(M,p,origin) for p ∈ pts]\nscene = plot!(scene, M, pts, vecs)","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"And we can again look at the corresponding geodesics, for example","category":"page"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"plot!(scene, M, [pts[1], origin], geodesic_interpolation=100)\nplot!(scene, M, [pts[2], origin], geodesic_interpolation=100)","category":"page"},{"location":"manifolds/hyperbolic.html#Literature","page":"Hyperbolic space","title":"Literature","text":"","category":"section"},{"location":"manifolds/hyperbolic.html","page":"Hyperbolic space","title":"Hyperbolic space","text":"Pages = [\"manifolds/hyperbolic.md\"]\nCanonical=false","category":"page"},{"location":"manifolds/projectivespace.html#Projective-space","page":"Projective space","title":"Projective space","text":"","category":"section"},{"location":"manifolds/projectivespace.html","page":"Projective space","title":"Projective space","text":"Modules = [Manifolds]\nPages = [\"manifolds/ProjectiveSpace.jl\"]\nOrder = [:type,:function]","category":"page"},{"location":"manifolds/projectivespace.html#Manifolds.AbstractProjectiveSpace","page":"Projective space","title":"Manifolds.AbstractProjectiveSpace","text":"AbstractProjectiveSpace{𝔽} <: AbstractDecoratorManifold{𝔽}\n\nAn abstract type to represent a projective space over 𝔽 that is represented isometrically in the embedding.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/projectivespace.html#Manifolds.ArrayProjectiveSpace","page":"Projective space","title":"Manifolds.ArrayProjectiveSpace","text":"ArrayProjectiveSpace{T<:Tuple,𝔽} <: AbstractProjectiveSpace{𝔽}\n\nThe projective space 𝔽ℙ^n₁n₂nᵢ is the manifold of all lines in 𝔽^n₁n₂nᵢ. The default representation is in the embedding, i.e. as unit (Frobenius) norm matrices in 𝔽^n₁n₂nᵢ:\n\n𝔽ℙ^n_1 n_2 n_i = bigl p 𝔽^n_1 n_2 n_i big lVert p rVert_mathrmF = 1 λ 𝔽 λ = 1 p p λ bigr\n\nwhere p is an equivalence class of points p, sim indicates equivalence, and lVert rVert_mathrmF is the Frobenius norm. Note that unlike ProjectiveSpace, the argument for ArrayProjectiveSpace is given by the size of the embedding. This means that ProjectiveSpace(2) and ArrayProjectiveSpace(3) are the same manifold. Additionally, ArrayProjectiveSpace(n,1;field=𝔽) and Grassmann(n,1;field=𝔽) are the same.\n\nThe tangent space at point p is given by\n\nT_p 𝔽ℙ^n_1 n_2 n_i = bigl X 𝔽^n_1 n_2 n_i pX_mathrmF = 0 bigr \n\nwhere _mathrmF denotes the (Frobenius) inner product in the embedding 𝔽^n_1 n_2 n_i.\n\nConstructor\n\nArrayProjectiveSpace(n₁,n₂,...,nᵢ; field=ℝ)\n\nGenerate the projective space 𝔽ℙ^n_1 n_2 n_i, defaulting to the real projective space, where field can also be used to generate the complex- and right-quaternionic projective spaces.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/projectivespace.html#Manifolds.ProjectiveSpace","page":"Projective space","title":"Manifolds.ProjectiveSpace","text":"ProjectiveSpace{n,𝔽} <: AbstractProjectiveSpace{𝔽}\n\nThe projective space 𝔽ℙ^n is the manifold of all lines in 𝔽^n+1. The default representation is in the embedding, i.e. as unit norm vectors in 𝔽^n+1:\n\n𝔽ℙ^n = bigl p 𝔽^n+1 big lVert p rVert = 1 λ 𝔽 λ = 1 p p λ bigr\n\nwhere p is an equivalence class of points p, and indicates equivalence. For example, the real projective space ℝℙ^n is represented as the unit sphere 𝕊^n, where antipodal points are considered equivalent.\n\nThe tangent space at point p is given by\n\nT_p 𝔽ℙ^n = bigl X 𝔽^n+1 big pX = 0 bigr \n\nwhere denotes the inner product in the embedding 𝔽^n+1.\n\nWhen 𝔽 = ℍ, this implementation of ℍℙ^n is the right-quaternionic projective space.\n\nConstructor\n\nProjectiveSpace(n[, field=ℝ])\n\nGenerate the projective space 𝔽ℙ^n 𝔽^n+1, defaulting to the real projective space ℝℙ^n, where field can also be used to generate the complex- and right-quaternionic projective spaces.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/projectivespace.html#Base.log-Tuple{AbstractProjectiveSpace, Any, Any}","page":"Projective space","title":"Base.log","text":"log(M::AbstractProjectiveSpace, p, q)\n\nCompute the logarithmic map on AbstractProjectiveSpace M$ = 𝔽ℙ^n$, i.e. the tangent vector whose corresponding geodesic starting from p reaches q after time 1 on M. The formula reads\n\nlog_p q = (q λ - cos θ p) fracθsin θ\n\nwhere θ = arccosq p_mathrmF is the distance between p and q, _mathrmF is the Frobenius inner product, and λ = fracq p_mathrmFq p_mathrmF 𝔽 is the unit scalar that minimizes d_𝔽^n+1(p - q λ). That is, q λ is the member of the equivalence class q that is closest to p in the embedding. As a result, exp_p circ log_p colon q q λ.\n\nThe logarithmic maps for the real AbstractSphere 𝕊^n and the real projective space ℝℙ^n are identical when p and q are in the same hemisphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#Manifolds.uniform_distribution-Union{Tuple{n}, Tuple{ProjectiveSpace{n, ℝ}, Any}} where n","page":"Projective space","title":"Manifolds.uniform_distribution","text":"uniform_distribution(M::ProjectiveSpace{n,ℝ}, p) where {n}\n\nUniform distribution on given ProjectiveSpace M. Generated points will be of similar type as p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase._isapprox-Tuple{AbstractProjectiveSpace, Any, Any}","page":"Projective space","title":"ManifoldsBase._isapprox","text":"isapprox(M::AbstractProjectiveSpace, p, q; kwargs...)\n\nCheck that points p and q on the AbstractProjectiveSpace M=𝔽ℙ^n are members of the same equivalence class, i.e. that p = q λ for some element λ 𝔽 with unit absolute value, that is, λ = 1. This is equivalent to the Riemannian distance being 0.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.check_point-Tuple{AbstractProjectiveSpace, Any}","page":"Projective space","title":"ManifoldsBase.check_point","text":"check_point(M::AbstractProjectiveSpace, p; kwargs...)\n\nCheck whether p is a valid point on the AbstractProjectiveSpace M, i.e. that it has the same size as elements of the embedding and has unit Frobenius norm. The tolerance for the norm check can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.check_vector-Tuple{AbstractProjectiveSpace, Any, Any}","page":"Projective space","title":"ManifoldsBase.check_vector","text":"check_vector(M::AbstractProjectiveSpace, p, X; kwargs... )\n\nCheck whether X is a tangent vector in the tangent space of p on the AbstractProjectiveSpace M, i.e. that X has the same size as elements of the tangent space of the embedding and that the Frobenius inner product p X_mathrmF = 0.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.distance-Tuple{AbstractProjectiveSpace, Any, Any}","page":"Projective space","title":"ManifoldsBase.distance","text":"distance(M::AbstractProjectiveSpace, p, q)\n\nCompute the Riemannian distance on AbstractProjectiveSpace M=𝔽ℙ^n between points p and q, i.e.\n\nd_𝔽ℙ^n(p q) = arccosbigl p q_mathrmF bigr\n\nNote that this definition is similar to that of the AbstractSphere. However, the absolute value ensures that all equivalent p and q have the same pairwise distance.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.get_coordinates-Tuple{AbstractProjectiveSpace{ℝ}, Any, Any, DefaultOrthonormalBasis}","page":"Projective space","title":"ManifoldsBase.get_coordinates","text":"get_coordinates(M::AbstractProjectiveSpace, p, X, B::DefaultOrthonormalBasis{ℝ})\n\nRepresent the tangent vector X at point p from the AbstractProjectiveSpace M = 𝔽ℙ^n in an orthonormal basis by unitarily transforming the hyperplane containing X, whose normal is p, to the hyperplane whose normal is the x-axis.\n\nGiven q = p overlineλ + x, where λ = fracx p_mathrmFx p_mathrmF, _mathrmF denotes the Frobenius inner product, and overline denotes complex or quaternionic conjugation, the formula for Y is\n\nbeginpmatrix0 Yendpmatrix = left(X - qfrac2 q X_mathrmFq q_mathrmFright)overlineλ\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.get_vector-Tuple{AbstractProjectiveSpace, Any, Any, DefaultOrthonormalBasis{ℝ}}","page":"Projective space","title":"ManifoldsBase.get_vector","text":"get_vector(M::AbstractProjectiveSpace, p, X, B::DefaultOrthonormalBasis{ℝ})\n\nConvert a one-dimensional vector of coefficients X in the basis B of the tangent space at p on the AbstractProjectiveSpace M=𝔽ℙ^n to a tangent vector Y at p by unitarily transforming the hyperplane containing X, whose normal is the x-axis, to the hyperplane whose normal is p.\n\nGiven q = p overlineλ + x, where λ = fracx p_mathrmFx p_mathrmF, _mathrmF denotes the Frobenius inner product, and overline denotes complex or quaternionic conjugation, the formula for Y is\n\nY = left(X - qfrac2 leftlangle q beginpmatrix0 Xendpmatrixrightrangle_mathrmFq q_mathrmFright) λ\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.inverse_retract-Tuple{AbstractProjectiveSpace, Any, Any, Union{PolarInverseRetraction, ProjectionInverseRetraction, QRInverseRetraction}}","page":"Projective space","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::AbstractProjectiveSpace, p, q, method::ProjectionInverseRetraction)\ninverse_retract(M::AbstractProjectiveSpace, p, q, method::PolarInverseRetraction)\ninverse_retract(M::AbstractProjectiveSpace, p, q, method::QRInverseRetraction)\n\nCompute the equivalent inverse retraction ProjectionInverseRetraction, PolarInverseRetraction, and QRInverseRetraction on the AbstractProjectiveSpace manifold M=𝔽ℙ^n, i.e.\n\noperatornameretr_p^-1 q = q frac1p q_mathrmF - p\n\nwhere _mathrmF is the Frobenius inner product.\n\nNote that this inverse retraction is equivalent to the three corresponding inverse retractions on Grassmann(n+1,1,𝔽), where the three inverse retractions in this case coincide. For ℝℙ^n, it is the same as the ProjectionInverseRetraction on the real Sphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.is_flat-Tuple{AbstractProjectiveSpace}","page":"Projective space","title":"ManifoldsBase.is_flat","text":"is_flat(M::AbstractProjectiveSpace)\n\nReturn true if AbstractProjectiveSpace is of dimension 1 and false otherwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.manifold_dimension-Union{Tuple{AbstractProjectiveSpace{𝔽}}, Tuple{𝔽}} where 𝔽","page":"Projective space","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::AbstractProjectiveSpace{𝔽}) where {𝔽}\n\nReturn the real dimension of the AbstractProjectiveSpace M, respectively i.e. the real dimension of the embedding minus the real dimension of the field 𝔽.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.parallel_transport_direction-Tuple{AbstractProjectiveSpace, Any, Any, Any}","page":"Projective space","title":"ManifoldsBase.parallel_transport_direction","text":"parallel_transport_direction(M::AbstractProjectiveSpace, p, X, d)\n\nParallel transport a vector X from the tangent space at a point p on the AbstractProjectiveSpace M along the geodesic in the direction indicated by the tangent vector d, i.e.\n\nmathcalP_exp_p (d) p(X) = X - left(p fracsin θθ + d frac1 - cos θθ^2right) d X_p\n\nwhere θ = lVert d rVert, and _p is the inner product at the point p. For the real projective space, this is equivalent to the same vector transport on the real AbstractSphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.parallel_transport_to-Tuple{AbstractProjectiveSpace, Any, Any, Any}","page":"Projective space","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::AbstractProjectiveSpace, p, X, q)\n\nParallel transport a vector X from the tangent space at a point p on the AbstractProjectiveSpace M=𝔽ℙ^n to the tangent space at another point q.\n\nThis implementation proceeds by transporting X to T_q λ M using the same approach as parallel_transport_direction, where λ = fracq p_mathrmFq p_mathrmF 𝔽 is the unit scalar that takes q to the member q λ of its equivalence class q closest to p in the embedding. It then maps the transported vector from T_q λ M to T_q M. The resulting transport to T_q M is\n\nmathcalP_q p(X) = left(X - left(p fracsin θθ + d frac1 - cos θθ^2right) d X_pright) overlineλ\n\nwhere d = log_p q is the direction of the transport, θ = lVert d rVert_p is the distance between p and q, and overline denotes complex or quaternionic conjugation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.project-Tuple{AbstractProjectiveSpace, Any, Any}","page":"Projective space","title":"ManifoldsBase.project","text":"project(M::AbstractProjectiveSpace, p, X)\n\nOrthogonally project the point X onto the tangent space at p on the AbstractProjectiveSpace M:\n\noperatornameproj_p (X) = X - pp X_mathrmF\n\nwhere _mathrmF denotes the Frobenius inner product. For the real AbstractSphere and AbstractProjectiveSpace, this projection is the same.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.project-Tuple{AbstractProjectiveSpace, Any}","page":"Projective space","title":"ManifoldsBase.project","text":"project(M::AbstractProjectiveSpace, p)\n\nOrthogonally project the point p from the embedding onto the AbstractProjectiveSpace M:\n\noperatornameproj(p) = fracplVert p rVert_mathrmF\n\nwhere lVert rVert_mathrmF denotes the Frobenius norm. This is identical to projection onto the AbstractSphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.representation_size-Union{Tuple{ArrayProjectiveSpace{N}}, Tuple{N}} where N","page":"Projective space","title":"ManifoldsBase.representation_size","text":"representation_size(M::AbstractProjectiveSpace)\n\nReturn the size points on the AbstractProjectiveSpace M are represented as, i.e., the representation size of the embedding.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#ManifoldsBase.retract-Tuple{AbstractProjectiveSpace, Any, Any, Union{PolarRetraction, ProjectionRetraction, QRRetraction}}","page":"Projective space","title":"ManifoldsBase.retract","text":"retract(M::AbstractProjectiveSpace, p, X, method::ProjectionRetraction)\nretract(M::AbstractProjectiveSpace, p, X, method::PolarRetraction)\nretract(M::AbstractProjectiveSpace, p, X, method::QRRetraction)\n\nCompute the equivalent retraction ProjectionRetraction, PolarRetraction, and QRRetraction on the AbstractProjectiveSpace manifold M=𝔽ℙ^n, i.e.\n\noperatornameretr_p X = operatornameproj_p(p + X)\n\nNote that this retraction is equivalent to the three corresponding retractions on Grassmann(n+1,1,𝔽), where in this case they coincide. For ℝℙ^n, it is the same as the ProjectionRetraction on the real Sphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/projectivespace.html#Statistics.mean-Tuple{AbstractProjectiveSpace, Vararg{Any}}","page":"Projective space","title":"Statistics.mean","text":"mean(\n M::AbstractProjectiveSpace,\n x::AbstractVector,\n [w::AbstractWeights,]\n method = GeodesicInterpolationWithinRadius(π/4);\n kwargs...,\n)\n\nCompute the Riemannian mean of points in vector x using GeodesicInterpolationWithinRadius.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#VectorBundleSection","page":"Vector bundle","title":"Vector bundles","text":"","category":"section"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"Vector bundle E is a manifold that is built on top of another manifold mathcal M (base space). It is characterized by a continuous function Π E mathcal M, such that for each point p mathcal M the preimage of p by Π, Π^-1(p), has a structure of a vector space. These vector spaces are called fibers. Bundle projection can be performed using function bundle_projection.","category":"page"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"Tangent bundle is a simple example of a vector bundle, where each fiber is the tangent space at the specified point x. An object representing a tangent bundle can be obtained using the constructor called TangentBundle.","category":"page"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"Fibers of a vector bundle are represented by the type VectorBundleFibers. The important difference between functions operating on VectorBundle and VectorBundleFibers is that in the first case both a point on the underlying manifold and the vector are represented together (by a single argument) while in the second case only the vector part is present, while the point is supplied in a different argument where needed.","category":"page"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"VectorBundleFibers refers to the whole set of fibers of a vector bundle. There is also another type, VectorSpaceAtPoint, that represents a specific fiber at a given point. This distinction is made to reduce the need to repeatedly construct objects of type VectorSpaceAtPoint in certain usage scenarios. This is also considered a manifold.","category":"page"},{"location":"manifolds/vector_bundle.html#FVector","page":"Vector bundle","title":"FVector","text":"","category":"section"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"For cases where confusion between different types of vectors is possible, the type FVector can be used to express which type of vector space the vector belongs to. It is used for example in musical isomorphisms (the flat and sharp functions) that are used to go from a tangent space to cotangent space and vice versa.","category":"page"},{"location":"manifolds/vector_bundle.html#Documentation","page":"Vector bundle","title":"Documentation","text":"","category":"section"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/VectorBundle.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.TangentSpace-Tuple{AbstractManifold, Any}","page":"Vector bundle","title":"ManifoldsBase.TangentSpace","text":"TangentSpace(M::AbstractManifold, p)\n\nReturn a TangentSpaceAtPoint representing tangent space at p on the AbstractManifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Manifolds.CotangentSpaceAtPoint-Tuple{AbstractManifold, Any}","page":"Vector bundle","title":"Manifolds.CotangentSpaceAtPoint","text":"CotangentSpaceAtPoint(M::AbstractManifold, p)\n\nReturn an object of type VectorSpaceAtPoint representing cotangent space at p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Manifolds.SasakiRetraction","page":"Vector bundle","title":"Manifolds.SasakiRetraction","text":"struct SasakiRetraction <: AbstractRetractionMethod end\n\nExponential map on TangentBundle computed via Euler integration as described in [Muralidharan2012]. The system of equations for gamma ℝ to Tmathcal M such that gamma(1) = exp_pX(X_M X_F) and gamma(0)=(p X) reads\n\ndotgamma(t) = (dotp(t) dotX(t)) = (R(X(t) dotX(t))dotp(t) 0)\n\nwhere R is the Riemann curvature tensor (see riemann_tensor).\n\nConstructor\n\nSasakiRetraction(L::Int)\n\nIn this constructor L is the number of integration steps.\n\n[Muralidharan2012]: P. Muralidharan and P. T. Fletcher, “Sasaki Metrics for Analysis of Longitudinal Data on Manifolds,” Proc IEEE Comput Soc Conf Comput Vis Pattern Recognit, vol. 2012, pp. 1027–1034, Jun. 2012, doi: 10.1109/CVPR.2012.6247780.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.TangentBundle","page":"Vector bundle","title":"Manifolds.TangentBundle","text":"TangentBundle{𝔽,M} = VectorBundle{𝔽,TangentSpaceType,M} where {𝔽,M<:AbstractManifold{𝔽}}\n\nTangent bundle for manifold of type M, as a manifold with the Sasaki metric [Sasaki1958].\n\nExact retraction and inverse retraction can be approximated using VectorBundleProductRetraction, VectorBundleInverseProductRetraction and SasakiRetraction. VectorBundleProductVectorTransport can be used as a vector transport.\n\n[Sasaki1958]: S. Sasaki, “On the differential geometry of tangent bundles of Riemannian manifolds,” Tohoku Math. J. (2), vol. 10, no. 3, pp. 338–354, 1958, doi: 10.2748/tmj/1178244668.\n\nConstructors\n\nTangentBundle(M::AbstractManifold)\nTangentBundle(M::AbstractManifold, vtm::VectorBundleProductVectorTransport)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.TangentSpaceAtPoint","page":"Vector bundle","title":"Manifolds.TangentSpaceAtPoint","text":"TangentSpaceAtPoint{M}\n\nAlias for VectorSpaceAtPoint for the tangent space at a point.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.TangentSpaceAtPoint-Tuple{AbstractManifold, Any}","page":"Vector bundle","title":"Manifolds.TangentSpaceAtPoint","text":"TangentSpaceAtPoint(M::AbstractManifold, p)\n\nReturn an object of type VectorSpaceAtPoint representing tangent space at p on the AbstractManifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Manifolds.TensorProductType","page":"Vector bundle","title":"Manifolds.TensorProductType","text":"TensorProductType(spaces::VectorSpaceType...)\n\nVector space type corresponding to the tensor product of given vector space types.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.VectorBundle","page":"Vector bundle","title":"Manifolds.VectorBundle","text":"VectorBundle{𝔽,TVS<:VectorSpaceType,TM<:AbstractManifold{𝔽}} <: AbstractManifold{𝔽}\n\nVector bundle on a AbstractManifold M of type VectorSpaceType.\n\nConstructor\n\nVectorBundle(M::AbstractManifold, type::VectorSpaceType)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.VectorBundleFibers","page":"Vector bundle","title":"Manifolds.VectorBundleFibers","text":"VectorBundleFibers(fiber::VectorSpaceType, M::AbstractManifold)\n\nType representing a family of vector spaces (fibers) of a vector bundle over M with vector spaces of type fiber. In contrast with VectorBundle, operations on VectorBundleFibers expect point-like and vector-like parts to be passed separately instead of being bundled together. It can be thought of as a representation of vector spaces from a vector bundle but without storing the point at which a vector space is attached (which is specified separately in various functions).\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.VectorBundleInverseProductRetraction","page":"Vector bundle","title":"Manifolds.VectorBundleInverseProductRetraction","text":"struct VectorBundleInverseProductRetraction <: AbstractInverseRetractionMethod end\n\nInverse retraction of the point y at point p from vector bundle B over manifold B.fiber (denoted mathcal M). The inverse retraction is derived as a product manifold-style approximation to the logarithmic map in the Sasaki metric. The considered product manifold is the product between the manifold mathcal M and the topological vector space isometric to the fiber.\n\nNotation:\n\nThe point p = (x_p V_p) where x_p mathcal M and V_p belongs to the fiber F=π^-1(x_p) of the vector bundle B where π is the canonical projection of that vector bundle B. Similarly, q = (x_q V_q).\n\nThe inverse retraction is calculated as\n\noperatornameretr^-1_p q = (operatornameretr^-1_x_p(x_q) V_operatornameretr^-1 - V_p)\n\nwhere V_operatornameretr^-1 is the result of vector transport of V_q to the point x_p. The difference V_operatornameretr^-1 - V_p corresponds to the logarithmic map in the vector space F.\n\nSee also VectorBundleProductRetraction.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.VectorBundleProductRetraction","page":"Vector bundle","title":"Manifolds.VectorBundleProductRetraction","text":"struct VectorBundleProductRetraction <: AbstractRetractionMethod end\n\nProduct retraction map of tangent vector X at point p from vector bundle B over manifold B.fiber (denoted mathcal M). The retraction is derived as a product manifold-style approximation to the exponential map in the Sasaki metric. The considered product manifold is the product between the manifold mathcal M and the topological vector space isometric to the fiber.\n\nNotation:\n\nThe point p = (x_p V_p) where x_p mathcal M and V_p belongs to the fiber F=π^-1(x_p) of the vector bundle B where π is the canonical projection of that vector bundle B.\nThe tangent vector X = (V_XM V_XF) T_pB where V_XM is a tangent vector from the tangent space T_x_pmathcal M and V_XF is a tangent vector from the tangent space T_V_pF (isomorphic to F).\n\nThe retraction is calculated as\n\noperatornameretr_p(X) = (exp_x_p(V_XM) V_exp)\n\nwhere V_exp is the result of vector transport of V_p + V_XF to the point exp_x_p(V_XM). The sum V_p + V_XF corresponds to the exponential map in the vector space F.\n\nSee also VectorBundleInverseProductRetraction.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.VectorBundleProductVectorTransport","page":"Vector bundle","title":"Manifolds.VectorBundleProductVectorTransport","text":"VectorBundleProductVectorTransport{\n TMP<:AbstractVectorTransportMethod,\n TMV<:AbstractVectorTransportMethod,\n} <: AbstractVectorTransportMethod\n\nVector transport type on VectorBundle. method_point is used for vector transport of the point part and method_vector is used for transport of the vector part.\n\nThe vector transport is derived as a product manifold-style vector transport. The considered product manifold is the product between the manifold mathcal M and the topological vector space isometric to the fiber.\n\nConstructor\n\nVectorBundleProductVectorTransport(\n method_point::AbstractVectorTransportMethod,\n method_vector::AbstractVectorTransportMethod,\n)\nVectorBundleProductVectorTransport()\n\nBy default both methods are set to ParallelTransport.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.VectorBundleVectorTransport","page":"Vector bundle","title":"Manifolds.VectorBundleVectorTransport","text":"const VectorBundleVectorTransport = VectorBundleProductVectorTransport\n\nDeprecated: an alias for VectorBundleProductVectorTransport.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Manifolds.VectorSpaceAtPoint","page":"Vector bundle","title":"Manifolds.VectorSpaceAtPoint","text":"VectorSpaceAtPoint{\n 𝔽,\n TFiber<:VectorBundleFibers{<:VectorSpaceType,<:AbstractManifold{𝔽}},\n TX,\n} <: AbstractManifold{𝔽}\n\nA vector space at a point p on the manifold. This is modelled using VectorBundleFibers with only a vector-like part and fixing the point-like part to be just p.\n\nThis vector space itself is also a manifold. Especially, it's flat and hence isometric to the Euclidean manifold.\n\nConstructor\n\nVectorSpaceAtPoint(fiber::VectorBundleFibers, p)\n\nA vector space (fiber type fiber of a vector bundle) at point p from the manifold fiber.manifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/vector_bundle.html#Base.exp-Tuple{TangentSpaceAtPoint{𝔽} where 𝔽, Any, Any}","page":"Vector bundle","title":"Base.exp","text":"exp(M::TangentSpaceAtPoint, p, X)\n\nExponential map of tangent vectors X and p from the tangent space M. It is calculated as their sum.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Base.getindex-Tuple{ArrayPartition, VectorBundle, Symbol}","page":"Vector bundle","title":"Base.getindex","text":"getindex(p::ArrayPartition, M::VectorBundle, s::Symbol)\np[M::VectorBundle, s]\n\nAccess the element(s) at index s of a point p on a VectorBundle M by using the symbols :point and :vector for the base and vector component, respectively.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Base.getindex-Tuple{ProductRepr, VectorBundle, Symbol}","page":"Vector bundle","title":"Base.getindex","text":"getindex(p::ProductRepr, M::VectorBundle, s::Symbol)\np[M::VectorBundle, s]\n\nAccess the element(s) at index s of a point p on a VectorBundle M by using the symbols :point and :vector for the base and vector component, respectively.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Base.log-Tuple{TangentSpaceAtPoint{𝔽} where 𝔽, Vararg{Any}}","page":"Vector bundle","title":"Base.log","text":"log(M::TangentSpaceAtPoint, p, q)\n\nLogarithmic map on the tangent space manifold M, calculated as the difference of tangent vectors q and p from M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Base.setindex!-Tuple{ArrayPartition, Any, VectorBundle, Symbol}","page":"Vector bundle","title":"Base.setindex!","text":"setindex!(p::ArrayPartition, val, M::VectorBundle, s::Symbol)\np[M::VectorBundle, s] = val\n\nSet the element(s) at index s of a point p on a VectorBundle M to val by using the symbols :point and :vector for the base and vector component, respectively.\n\nnote: Note\nThe content of element of p is replaced, not the element itself.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Base.setindex!-Tuple{ProductRepr, Any, VectorBundle, Symbol}","page":"Vector bundle","title":"Base.setindex!","text":"setindex!(p::ProductRepr, val, M::VectorBundle, s::Symbol)\np[M::VectorBundle, s] = val\n\nSet the element(s) at index s of a point p on a VectorBundle M to val by using the symbols :point and :vector for the base and vector component, respectively.\n\nnote: Note\nThe content of element of p is replaced, not the element itself.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#LinearAlgebra.norm-Tuple{VectorBundleFibers, Any, Any}","page":"Vector bundle","title":"LinearAlgebra.norm","text":"norm(B::VectorBundleFibers, p, q)\n\nNorm of the vector X from the vector space of type B.fiber at point p from manifold B.manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Manifolds.bundle_projection-Tuple{VectorBundle, Any}","page":"Vector bundle","title":"Manifolds.bundle_projection","text":"bundle_projection(B::VectorBundle, p::ArrayPartition)\n\nProjection of point p from the bundle M to the base manifold. Returns the point on the base manifold B.manifold at which the vector part of p is attached.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Manifolds.inverse_retract_product-Tuple{VectorBundle, Any, Any}","page":"Vector bundle","title":"Manifolds.inverse_retract_product","text":"inverse_retract_product(M::VectorBundle, p, q)\n\nCompute the allocating variant of the VectorBundleInverseProductRetraction, which by default allocates and calls inverse_retract_product!.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Manifolds.retract_product-Tuple{VectorBundle, Any, Any, Number}","page":"Vector bundle","title":"Manifolds.retract_product","text":"retract_product(M::VectorBundle, p, q, t::Number)\n\nCompute the allocating variant of the VectorBundleProductRetraction, which by default allocates and calls retract_product!.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Manifolds.retract_sasaki-Tuple{AbstractManifold, Any, Any, Number, SasakiRetraction}","page":"Vector bundle","title":"Manifolds.retract_sasaki","text":"retract_sasaki(M::AbstractManifold, p, X, t::Number, m::SasakiRetraction)\n\nCompute the allocating variant of the SasakiRetraction, which by default allocates and calls retract_sasaki!.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Manifolds.vector_bundle_transport-Tuple{VectorSpaceType, AbstractManifold}","page":"Vector bundle","title":"Manifolds.vector_bundle_transport","text":"vector_bundle_transport(fiber::VectorSpaceType, M::AbstractManifold)\n\nDetermine the vector tranport used for exp and log maps on a vector bundle with vector space type fiber and manifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.allocate_result-Union{Tuple{TF}, Tuple{VectorBundleFibers, TF, Vararg{Any}}} where TF","page":"Vector bundle","title":"ManifoldsBase.allocate_result","text":"allocate_result(B::VectorBundleFibers, f, x...)\n\nAllocates an array for the result of function f that is an element of the vector space of type B.fiber on manifold B.manifold and arguments x... for implementing the non-modifying operation using the modifying operation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.allocate_result_type-Union{Tuple{N}, Tuple{TF}, Tuple{VectorBundleFibers, TF, Tuple{Vararg{Any, N}}}} where {TF, N}","page":"Vector bundle","title":"ManifoldsBase.allocate_result_type","text":"allocate_result_type(B::VectorBundleFibers, f, args::NTuple{N,Any}) where N\n\nReturn type of element of the array that will represent the result of function f for representing an operation with result in the vector space fiber for manifold M on given arguments (passed at a tuple).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.distance-Tuple{TangentSpaceAtPoint{𝔽} where 𝔽, Any, Any}","page":"Vector bundle","title":"ManifoldsBase.distance","text":"distance(M::TangentSpaceAtPoint, p, q)\n\nDistance between vectors p and q from the vector space M. It is calculated as the norm of their difference.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.distance-Tuple{VectorBundleFibers, Any, Any, Any}","page":"Vector bundle","title":"ManifoldsBase.distance","text":"distance(B::VectorBundleFibers, p, X, Y)\n\nDistance between vectors X and Y from the vector space at point p from the manifold B.manifold, that is the base manifold of M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.injectivity_radius-Tuple{TangentBundle{𝔽} where 𝔽}","page":"Vector bundle","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::TangentBundle)\n\nInjectivity radius of TangentBundle manifold is infinite if the base manifold is flat and 0 otherwise. See https://mathoverflow.net/questions/94322/injectivity-radius-of-the-sasaki-metric.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.injectivity_radius-Tuple{TangentSpaceAtPoint{𝔽} where 𝔽}","page":"Vector bundle","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::TangentSpaceAtPoint)\n\nReturn the injectivity radius on the TangentSpaceAtPoint M, which is .\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.inner-Tuple{TangentSpaceAtPoint{𝔽} where 𝔽, Any, Any, Any}","page":"Vector bundle","title":"ManifoldsBase.inner","text":"inner(M::TangentSpaceAtPoint, p, X, Y)\n\nInner product of vectors X and Y from the tangent space at M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.inner-Tuple{VectorBundle, Any, Any, Any}","page":"Vector bundle","title":"ManifoldsBase.inner","text":"inner(B::VectorBundle, p, X, Y)\n\nInner product of tangent vectors X and Y at point p from the vector bundle B over manifold B.fiber (denoted mathcal M).\n\nNotation:\n\nThe point p = (x_p V_p) where x_p mathcal M and V_p belongs to the fiber F=π^-1(x_p) of the vector bundle B where π is the canonical projection of that vector bundle B.\nThe tangent vector v = (V_XM V_XF) T_xB where V_XM is a tangent vector from the tangent space T_x_pmathcal M and V_XF is a tangent vector from the tangent space T_V_pF (isomorphic to F). Similarly for the other tangent vector w = (V_YM V_YF) T_xB.\n\nThe inner product is calculated as\n\nX Y_p = V_XM V_YM_x_p + V_XF V_YF_V_p\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.inner-Tuple{VectorBundleFibers, Any, Any, Any}","page":"Vector bundle","title":"ManifoldsBase.inner","text":"inner(B::VectorBundleFibers, p, X, Y)\n\nInner product of vectors X and Y from the vector space of type B.fiber at point p from manifold B.manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.is_flat-Tuple{TangentSpaceAtPoint{𝔽} where 𝔽}","page":"Vector bundle","title":"ManifoldsBase.is_flat","text":"is_flat(::TangentSpaceAtPoint)\n\nReturn true. TangentSpaceAtPoint is a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.is_flat-Tuple{VectorBundle}","page":"Vector bundle","title":"ManifoldsBase.is_flat","text":"is_flat(::VectorBundle)\n\nReturn true if the underlying manifold of VectorBundle M is flat.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.project-Tuple{TangentSpaceAtPoint{𝔽} where 𝔽, Any, Any}","page":"Vector bundle","title":"ManifoldsBase.project","text":"project(M::TangentSpaceAtPoint, p, X)\n\nProject the vector X from the tangent space M, that is project the vector X tangent at M.point.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.project-Tuple{TangentSpaceAtPoint{𝔽} where 𝔽, Any}","page":"Vector bundle","title":"ManifoldsBase.project","text":"project(M::TangentSpaceAtPoint, p)\n\nProject the point p from the tangent space M, that is project the vector p tangent at M.point.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.project-Tuple{VectorBundle, Any, Any}","page":"Vector bundle","title":"ManifoldsBase.project","text":"project(B::VectorBundle, p, X)\n\nProject the element X of the ambient space of the tangent space T_p B to the tangent space T_p B.\n\nNotation:\n\nThe point p = (x_p V_p) where x_p mathcal M and V_p belongs to the fiber F=π^-1(x_p) of the vector bundle B where π is the canonical projection of that vector bundle B.\nThe vector x = (V_XM V_XF) where x_p belongs to the ambient space of T_x_pmathcal M and V_XF belongs to the ambient space of the fiber F=π^-1(x_p) of the vector bundle B where π is the canonical projection of that vector bundle B.\n\nThe projection is calculated by projecting V_XM to tangent space T_x_pmathcal M and then projecting the vector V_XF to the fiber F.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.project-Tuple{VectorBundle, Any}","page":"Vector bundle","title":"ManifoldsBase.project","text":"project(B::VectorBundle, p)\n\nProject the point p from the ambient space of the vector bundle B over manifold B.fiber (denoted mathcal M) to the vector bundle.\n\nNotation:\n\nThe point p = (x_p V_p) where x_p belongs to the ambient space of mathcal M and V_p belongs to the ambient space of the fiber F=π^-1(x_p) of the vector bundle B where π is the canonical projection of that vector bundle B.\n\nThe projection is calculated by projecting the point x_p to the manifold mathcal M and then projecting the vector V_p to the tangent space T_x_pmathcal M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.project-Tuple{VectorBundleFibers, Any, Any}","page":"Vector bundle","title":"ManifoldsBase.project","text":"project(B::VectorBundleFibers, p, X)\n\nProject vector X from the vector space of type B.fiber at point p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.vector_transport_to-Tuple{VectorBundle, Any, Any, Any, Manifolds.VectorBundleProductVectorTransport}","page":"Vector bundle","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::VectorBundle, p, X, q, m::VectorBundleProductVectorTransport)\n\nCompute the vector transport the tangent vector Xat p to q on the VectorBundle M using the VectorBundleProductVectorTransport m.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.zero_vector!-Tuple{VectorBundleFibers, Any, Any}","page":"Vector bundle","title":"ManifoldsBase.zero_vector!","text":"zero_vector!(B::VectorBundleFibers, X, p)\n\nSave the zero vector from the vector space of type B.fiber at point p from manifold B.manifold to X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.zero_vector-Tuple{TangentSpaceAtPoint{𝔽} where 𝔽, Vararg{Any}}","page":"Vector bundle","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::TangentSpaceAtPoint, p)\n\nZero tangent vector at point p from the tangent space M, that is the zero tangent vector at point M.point.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.zero_vector-Tuple{VectorBundle, Vararg{Any}}","page":"Vector bundle","title":"ManifoldsBase.zero_vector","text":"zero_vector(B::VectorBundle, p)\n\nZero tangent vector at point p from the vector bundle B over manifold B.fiber (denoted mathcal M). The zero vector belongs to the space T_pB\n\nNotation:\n\nThe point p = (x_p V_p) where x_p mathcal M and V_p belongs to the fiber F=π^-1(x_p) of the vector bundle B where π is the canonical projection of that vector bundle B.\n\nThe zero vector is calculated as\n\nmathbf0_p = (mathbf0_x_p mathbf0_F)\n\nwhere mathbf0_x_p is the zero tangent vector from T_x_pmathcal M and mathbf0_F is the zero element of the vector space F.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#ManifoldsBase.zero_vector-Tuple{VectorBundleFibers, Any}","page":"Vector bundle","title":"ManifoldsBase.zero_vector","text":"zero_vector(B::VectorBundleFibers, p)\n\nCompute the zero vector from the vector space of type B.fiber at point p from manifold B.manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/vector_bundle.html#Example","page":"Vector bundle","title":"Example","text":"","category":"section"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"The following code defines a point on the tangent bundle of the sphere S^2 and a tangent vector to that point.","category":"page"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"using Manifolds\nM = Sphere(2)\nTB = TangentBundle(M)\np = ProductRepr([1.0, 0.0, 0.0], [0.0, 1.0, 3.0])\nX = ProductRepr([0.0, 1.0, 0.0], [0.0, 0.0, -2.0])","category":"page"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"An approximation of the exponential in the Sasaki metric using 1000 steps can be calculated as follows.","category":"page"},{"location":"manifolds/vector_bundle.html","page":"Vector bundle","title":"Vector bundle","text":"q = retract(TB, p, X, SasakiRetraction(1000))\nprintln(\"Approximation of the exponential map: \", q)","category":"page"},{"location":"manifolds/spheresymmetricmatrices.html#Unit-norm-symmetric-matrices","page":"Unit-norm symmetric matrices","title":"Unit-norm symmetric matrices","text":"","category":"section"},{"location":"manifolds/spheresymmetricmatrices.html","page":"Unit-norm symmetric matrices","title":"Unit-norm symmetric matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/SphereSymmetricMatrices.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/spheresymmetricmatrices.html#Manifolds.SphereSymmetricMatrices","page":"Unit-norm symmetric matrices","title":"Manifolds.SphereSymmetricMatrices","text":"SphereSymmetricMatrices{n,𝔽} <: AbstractEmbeddedManifold{ℝ,TransparentIsometricEmbedding}\n\nThe AbstractManifold consisting of the n n symmetric matrices of unit Frobenius norm, i.e.\n\nmathcalS_textsym =biglp 𝔽^n n big p^mathrmH = p lVert p rVert = 1 bigr\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transpose, and the field 𝔽 ℝ ℂ.\n\nConstructor\n\nSphereSymmetricMatrices(n[, field=ℝ])\n\nGenerate the manifold of n-by-n symmetric matrices of unit Frobenius norm.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/spheresymmetricmatrices.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{n}, Tuple{SphereSymmetricMatrices{n, 𝔽}, Any}} where {n, 𝔽}","page":"Unit-norm symmetric matrices","title":"ManifoldsBase.check_point","text":"check_point(M::SphereSymmetricMatrices{n,𝔽}, p; kwargs...)\n\nCheck whether the matrix is a valid point on the SphereSymmetricMatrices M, i.e. is an n-by-n symmetric matrix of unit Frobenius norm.\n\nThe tolerance for the symmetry of p can be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spheresymmetricmatrices.html#ManifoldsBase.check_vector-Union{Tuple{𝔽}, Tuple{n}, Tuple{SphereSymmetricMatrices{n, 𝔽}, Any, Any}} where {n, 𝔽}","page":"Unit-norm symmetric matrices","title":"ManifoldsBase.check_vector","text":"check_vector(M::SphereSymmetricMatrices{n,𝔽}, p, X; kwargs... )\n\nCheck whether X is a tangent vector to manifold point p on the SphereSymmetricMatrices M, i.e. X has to be a symmetric matrix of size (n,n) of unit Frobenius norm.\n\nThe tolerance for the symmetry of p and X can be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spheresymmetricmatrices.html#ManifoldsBase.is_flat-Tuple{SphereSymmetricMatrices}","page":"Unit-norm symmetric matrices","title":"ManifoldsBase.is_flat","text":"is_flat(::SphereSymmetricMatrices)\n\nReturn false. SphereSymmetricMatrices is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spheresymmetricmatrices.html#ManifoldsBase.manifold_dimension-Union{Tuple{SphereSymmetricMatrices{n, 𝔽}}, Tuple{𝔽}, Tuple{n}} where {n, 𝔽}","page":"Unit-norm symmetric matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::SphereSymmetricMatrices{n,𝔽})\n\nReturn the manifold dimension of the SphereSymmetricMatrices n-by-n symmetric matrix M of unit Frobenius norm over the number system 𝔽, i.e.\n\nbeginaligned\ndim(mathcalS_textsym)(nℝ) = fracn(n+1)2 - 1\ndim(mathcalS_textsym)(nℂ) = 2fracn(n+1)2 - n -1\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spheresymmetricmatrices.html#ManifoldsBase.project-Tuple{SphereSymmetricMatrices, Any, Any}","page":"Unit-norm symmetric matrices","title":"ManifoldsBase.project","text":"project(M::SphereSymmetricMatrices, p, X)\n\nProject the matrix X onto the tangent space at p on the SphereSymmetricMatrices M, i.e.\n\noperatornameproj_p(X) = fracX + X^mathrmH2 - p fracX + X^mathrmH2p\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/spheresymmetricmatrices.html#ManifoldsBase.project-Tuple{SphereSymmetricMatrices, Any}","page":"Unit-norm symmetric matrices","title":"ManifoldsBase.project","text":"project(M::SphereSymmetricMatrices, p)\n\nProjects p from the embedding onto the SphereSymmetricMatrices M, i.e.\n\noperatornameproj_mathcalS_textsym(p) = frac12 bigl( p + p^mathrmH bigr)\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#Positive-Numbers","page":"Positive numbers","title":"Positive Numbers","text":"","category":"section"},{"location":"manifolds/positivenumbers.html","page":"Positive numbers","title":"Positive numbers","text":"The manifold PositiveNumbers represents positive numbers with hyperbolic geometry. Additionally, there are also short forms for its corresponding PowerManifolds, i.e. PositiveVectors, PositiveMatrices, and PositiveArrays.","category":"page"},{"location":"manifolds/positivenumbers.html","page":"Positive numbers","title":"Positive numbers","text":"Modules = [Manifolds]\nPages = [\"manifolds/PositiveNumbers.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/positivenumbers.html#Manifolds.PositiveNumbers","page":"Positive numbers","title":"Manifolds.PositiveNumbers","text":"PositiveNumbers <: AbstractManifold{ℝ}\n\nThe hyperbolic manifold of positive numbers H^1 is a the hyperbolic manifold represented by just positive numbers.\n\nConstructor\n\nPositiveNumbers()\n\nGenerate the ℝ-valued hyperbolic model represented by positive positive numbers. To use this with arrays (1-element arrays), please use SymmetricPositiveDefinite(1).\n\n\n\n\n\n","category":"type"},{"location":"manifolds/positivenumbers.html#Base.exp-Tuple{PositiveNumbers, Any, Any}","page":"Positive numbers","title":"Base.exp","text":"exp(M::PositiveNumbers, p, X)\n\nCompute the exponential map on the PositiveNumbers M.\n\nexp_p X = poperatornameexp(Xp)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#Base.log-Tuple{PositiveNumbers, Any, Any}","page":"Positive numbers","title":"Base.log","text":"log(M::PositiveNumbers, p, q)\n\nCompute the logarithmic map on the PositiveNumbers M.\n\nlog_p q = plogfracqp\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#Manifolds.PositiveArrays-Union{Tuple{Vararg{Int64, I}}, Tuple{I}} where I","page":"Positive numbers","title":"Manifolds.PositiveArrays","text":"PositiveArrays(n₁,n₂,...,nᵢ)\n\nGenerate the manifold of i-dimensional arrays with positive entries. This manifold is modeled as a PowerManifold of PositiveNumbers.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#Manifolds.PositiveMatrices-Tuple{Integer, Integer}","page":"Positive numbers","title":"Manifolds.PositiveMatrices","text":"PositiveMatrices(m,n)\n\nGenerate the manifold of matrices with positive entries. This manifold is modeled as a PowerManifold of PositiveNumbers.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#Manifolds.PositiveVectors-Tuple{Integer}","page":"Positive numbers","title":"Manifolds.PositiveVectors","text":"PositiveVectors(n)\n\nGenerate the manifold of vectors with positive entries. This manifold is modeled as a PowerManifold of PositiveNumbers.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.change_metric-Tuple{PositiveNumbers, EuclideanMetric, Any, Any}","page":"Positive numbers","title":"ManifoldsBase.change_metric","text":"change_metric(M::PositiveNumbers, E::EuclideanMetric, p, X)\n\nGiven a tangent vector X T_pmathcal M representing a linear function with respect to the EuclideanMetric g_E, this function changes the representer into the one with respect to the positivity metric of PositiveNumbers M.\n\nFor all ZY we are looking for the function c on the tangent space at p such that\n\n ZY = XY = fracc(Z)c(Y)p^2 = g_p(c(Y)c(Z))\n\nand hence C(X) = pX.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.change_representer-Tuple{PositiveNumbers, EuclideanMetric, Any, Any}","page":"Positive numbers","title":"ManifoldsBase.change_representer","text":"change_representer(M::PositiveNumbers, E::EuclideanMetric, p, X)\n\nGiven a tangent vector X T_pmathcal M representing a linear function with respect to the EuclideanMetric g_E, this function changes the representer into the one with respect to the positivity metric representation of PositiveNumbers M.\n\nFor all tangent vectors Y the result Z has to fulfill\n\n XY = XY = fracZYp^2 = g_p(YZ)\n\nand hence Z = p^2X\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.check_point-Tuple{PositiveNumbers, Any}","page":"Positive numbers","title":"ManifoldsBase.check_point","text":"check_point(M::PositiveNumbers, p)\n\nCheck whether p is a point on the PositiveNumbers M, i.e. p0.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.check_vector-Tuple{PositiveNumbers, Any, Any}","page":"Positive numbers","title":"ManifoldsBase.check_vector","text":"check_vector(M::PositiveNumbers, p, X; kwargs...)\n\nCheck whether X is a tangent vector in the tangent space of p on the PositiveNumbers M. For the real-valued case represented by positive numbers, all X are valid, since the tangent space is the whole real line. For the complex-valued case X [...]\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.distance-Tuple{PositiveNumbers, Any, Any}","page":"Positive numbers","title":"ManifoldsBase.distance","text":"distance(M::PositiveNumbers, p, q)\n\nCompute the distance on the PositiveNumbers M, which is\n\nd(pq) = Bigllvert log fracpq Bigrrvert = lvert log p - log qrvert\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.get_coordinates-Tuple{PositiveNumbers, Any, Any, DefaultOrthonormalBasis{ℝ}}","page":"Positive numbers","title":"ManifoldsBase.get_coordinates","text":"get_coordinates(::PositiveNumbers, p, X, ::DefaultOrthonormalBasis{ℝ})\n\nCompute the coordinate of vector X which is tangent to p on the PositiveNumbers manifold. The formula is X p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.get_vector-Tuple{PositiveNumbers, Any, Any, DefaultOrthonormalBasis{ℝ}}","page":"Positive numbers","title":"ManifoldsBase.get_vector","text":"get_vector(::PositiveNumbers, p, c, ::DefaultOrthonormalBasis{ℝ})\n\nCompute the vector with coordinate c which is tangent to p on the PositiveNumbers manifold. The formula is p * c.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.injectivity_radius-Tuple{PositiveNumbers}","page":"Positive numbers","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::PositiveNumbers[, p])\n\nReturn the injectivity radius on the PositiveNumbers M, i.e. infty.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.inner-Tuple{PositiveNumbers, Vararg{Any}}","page":"Positive numbers","title":"ManifoldsBase.inner","text":"inner(M::PositiveNumbers, p, X, Y)\n\nCompute the inner product of the two tangent vectors X,Y from the tangent plane at p on the PositiveNumbers M, i.e.\n\ng_p(XY) = fracXYp^2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.is_flat-Tuple{PositiveNumbers}","page":"Positive numbers","title":"ManifoldsBase.is_flat","text":"is_flat(::PositiveNumbers)\n\nReturn false. PositiveNumbers is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.manifold_dimension-Tuple{PositiveNumbers}","page":"Positive numbers","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::PositiveNumbers)\n\nReturn the dimension of the PositiveNumbers M, i.e. of the 1-dimensional hyperbolic space,\n\ndim(H^1) = 1\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.parallel_transport_to-Tuple{PositiveNumbers, Any, Any, Any}","page":"Positive numbers","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::PositiveNumbers, p, X, q)\n\nCompute the parallel transport of X from the tangent space at p to the tangent space at q on the PositiveNumbers M.\n\nmathcal P_qgets p(X) = Xcdotfracqp\n\n\n\n\n\n","category":"method"},{"location":"manifolds/positivenumbers.html#ManifoldsBase.project-Tuple{PositiveNumbers, Any, Any}","page":"Positive numbers","title":"ManifoldsBase.project","text":"project(M::PositiveNumbers, p, X)\n\nProject a value X onto the tangent space of the point p on the PositiveNumbers M, which is just the identity.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#Torus","page":"Torus","title":"Torus","text":"","category":"section"},{"location":"manifolds/torus.html","page":"Torus","title":"Torus","text":"The torus 𝕋^d -ππ)^d is modeled as an AbstractPowerManifold of the (real-valued) Circle and uses ArrayPowerRepresentation. Points on the torus are hence row vectors, x ℝ^d.","category":"page"},{"location":"manifolds/torus.html#Example","page":"Torus","title":"Example","text":"","category":"section"},{"location":"manifolds/torus.html","page":"Torus","title":"Torus","text":"The following code can be used to make a three-dimensional torus 𝕋^3 and compute a tangent vector:","category":"page"},{"location":"manifolds/torus.html","page":"Torus","title":"Torus","text":"using Manifolds\nM = Torus(3)\np = [0.5, 0.0, 0.0]\nq = [0.0, 0.5, 1.0]\nX = log(M, p, q)","category":"page"},{"location":"manifolds/torus.html#Types-and-functions","page":"Torus","title":"Types and functions","text":"","category":"section"},{"location":"manifolds/torus.html","page":"Torus","title":"Torus","text":"Most functions are directly implemented for an AbstractPowerManifold with ArrayPowerRepresentation except the following special cases:","category":"page"},{"location":"manifolds/torus.html","page":"Torus","title":"Torus","text":"Modules = [Manifolds]\nPages = [\"manifolds/Torus.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/torus.html#Manifolds.Torus","page":"Torus","title":"Manifolds.Torus","text":"Torus{N} <: AbstractPowerManifold\n\nThe n-dimensional torus is the n-dimensional product of the Circle.\n\nThe Circle is stored internally within M.manifold, such that all functions of AbstractPowerManifold can be used directly.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/torus.html#ManifoldsBase.check_point-Tuple{Torus, Any}","page":"Torus","title":"ManifoldsBase.check_point","text":"check_point(M::Torus{n},p)\n\nChecks whether p is a valid point on the Torus M, i.e. each of its entries is a valid point on the Circle and the length of x is n.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#ManifoldsBase.check_vector-Union{Tuple{N}, Tuple{Torus{N}, Any, Any}} where N","page":"Torus","title":"ManifoldsBase.check_vector","text":"check_vector(M::Torus{n}, p, X; kwargs...)\n\nChecks whether X is a valid tangent vector to p on the Torus M. This means, that p is valid, that X is of correct dimension and elementwise a tangent vector to the elements of p on the Circle.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#Embedded-Torus","page":"Torus","title":"Embedded Torus","text":"","category":"section"},{"location":"manifolds/torus.html","page":"Torus","title":"Torus","text":"Two-dimensional torus embedded in ℝ^3.","category":"page"},{"location":"manifolds/torus.html","page":"Torus","title":"Torus","text":"Modules = [Manifolds]\nPages = [\"manifolds/EmbeddedTorus.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/torus.html#Manifolds.DefaultTorusAtlas","page":"Torus","title":"Manifolds.DefaultTorusAtlas","text":"DefaultTorusAtlas()\n\nAtlas for torus with charts indexed by two angles numbers θ₀ φ₀ -π π). Inverse of a chart (θ₀ φ₀) is given by\n\nx(θ φ) = (R + rcos(θ + θ₀))cos(φ + φ₀) \ny(θ φ) = (R + rcos(θ + θ₀))sin(φ + φ₀) \nz(θ φ) = rsin(θ + θ₀)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/torus.html#Manifolds.EmbeddedTorus","page":"Torus","title":"Manifolds.EmbeddedTorus","text":"EmbeddedTorus{TR<:Real} <: AbstractDecoratorManifold{ℝ}\n\nSurface in ℝ³ described by parametric equations:\n\nx(θ φ) = (R + rcos θ)cos φ \ny(θ φ) = (R + rcos θ)sin φ \nz(θ φ) = rsin θ\n\nfor θ, φ in -π π). It is assumed that R r 0.\n\nAlternative names include anchor ring, donut and doughnut.\n\nConstructor\n\nEmbeddedTorus(R, r)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/torus.html#Manifolds.affine_connection-Tuple{Manifolds.EmbeddedTorus, Manifolds.DefaultTorusAtlas, Vararg{Any, 4}}","page":"Torus","title":"Manifolds.affine_connection","text":"affine_connection(M::EmbeddedTorus, A::DefaultTorusAtlas, i, a, Xc, Yc)\n\nAffine connection on EmbeddedTorus M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#Manifolds.check_chart_switch-Tuple{Manifolds.EmbeddedTorus, Manifolds.DefaultTorusAtlas, Any, Any}","page":"Torus","title":"Manifolds.check_chart_switch","text":"check_chart_switch(::EmbeddedTorus, A::DefaultTorusAtlas, i, a; ϵ = pi/3)\n\nReturn true if parameters a lie closer than ϵ to chart boundary.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#Manifolds.gaussian_curvature-Tuple{Manifolds.EmbeddedTorus, Any}","page":"Torus","title":"Manifolds.gaussian_curvature","text":"gaussian_curvature(M::EmbeddedTorus, p)\n\nGaussian curvature at point p from EmbeddedTorus M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#Manifolds.inverse_chart_injectivity_radius-Tuple{Manifolds.EmbeddedTorus, Manifolds.DefaultTorusAtlas, Any}","page":"Torus","title":"Manifolds.inverse_chart_injectivity_radius","text":"inverse_chart_injectivity_radius(M::AbstractManifold, A::AbstractAtlas, i)\n\nInjectivity radius of get_point for chart i from the DefaultTorusAtlas A of the EmbeddedTorus.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#Manifolds.normal_vector-Tuple{Manifolds.EmbeddedTorus, Any}","page":"Torus","title":"Manifolds.normal_vector","text":"normal_vector(M::EmbeddedTorus, p)\n\nOutward-pointing normal vector on the EmbeddedTorus at the point p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#ManifoldsBase.check_point-Tuple{Manifolds.EmbeddedTorus, Any}","page":"Torus","title":"ManifoldsBase.check_point","text":"check_point(M::EmbeddedTorus, p; kwargs...)\n\nCheck whether p is a valid point on the EmbeddedTorus M. The tolerance for the last test can be set using the kwargs....\n\nThe method checks if (p_1^2 + p_2^2 + p_3^2 + R^2 - r^2)^2 is apprximately equal to 4R^2(p_1^2 + p_2^2).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#ManifoldsBase.check_vector-Tuple{Manifolds.EmbeddedTorus, Any, Any}","page":"Torus","title":"ManifoldsBase.check_vector","text":"check_vector(M::EmbeddedTorus, p, X; atol=eps(eltype(p)), kwargs...)\n\nCheck whether X is a valid vector tangent to p on the EmbeddedTorus M. The method checks if the vector X is orthogonal to the vector normal to the torus, see normal_vector. Absolute tolerance can be set using atol.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#ManifoldsBase.inner-Tuple{Manifolds.EmbeddedTorus, Manifolds.DefaultTorusAtlas, Vararg{Any, 4}}","page":"Torus","title":"ManifoldsBase.inner","text":"inner(M::EmbeddedTorus, ::DefaultTorusAtlas, i, a, Xc, Yc)\n\nInner product on EmbeddedTorus in chart i in the DefaultTorusAtlas. between vectors with coordinates Xc and Yc tangent at point with parameters a. Vector coordinates must be given in the induced basis.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#ManifoldsBase.is_flat-Tuple{Manifolds.EmbeddedTorus}","page":"Torus","title":"ManifoldsBase.is_flat","text":"is_flat(::EmbeddedTorus)\n\nReturn false. EmbeddedTorus is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/torus.html#ManifoldsBase.manifold_dimension-Tuple{Manifolds.EmbeddedTorus}","page":"Torus","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::EmbeddedTorus)\n\nReturn the dimension of the EmbeddedTorus M that is 2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#The-probability-simplex","page":"Probability simplex","title":"The probability simplex","text":"","category":"section"},{"location":"manifolds/probabilitysimplex.html","page":"Probability simplex","title":"Probability simplex","text":"Modules = [Manifolds]\nPages = [\"manifolds/ProbabilitySimplex.jl\"]\nOrder = [:type, :function]\nPrivate=false\nPublic=true","category":"page"},{"location":"manifolds/probabilitysimplex.html#Manifolds.FisherRaoMetric","page":"Probability simplex","title":"Manifolds.FisherRaoMetric","text":"FisherRaoMetric <: AbstractMetric\n\nThe Fisher-Rao metric or Fisher information metric is a particular Riemannian metric which can be defined on a smooth statistical manifold, i.e., a smooth manifold whose points are probability measures defined on a common probability space.\n\nSee for example the ProbabilitySimplex.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/probabilitysimplex.html#Manifolds.ProbabilitySimplex","page":"Probability simplex","title":"Manifolds.ProbabilitySimplex","text":"ProbabilitySimplex{n,boundary} <: AbstractDecoratorManifold{𝔽}\n\nThe (relative interior of) the probability simplex is the set\n\nΔ^n = biggl p ℝ^n+1 big p_i 0 text for all i=1n+1\ntext and mathbb1p = sum_i=1^n+1 p_i = 1biggr\n\nwhere mathbb1=(11)^mathrmT ℝ^n+1 denotes the vector containing only ones.\n\nIf boundary is set to :open, then the object represents an open simplex. Otherwise, that is when boundary is set to :closed, the boundary is also included:\n\nhatΔ^n = biggl p ℝ^n+1 big p_i geq 0 text for all i=1n+1\ntext and mathbb1p = sum_i=1^n+1 p_i = 1biggr\n\nThis set is also called the unit simplex or standard simplex.\n\nThe tangent space is given by\n\nT_pΔ^n = biggl X ℝ^n+1 big mathbb1X = sum_i=1^n+1 X_i = 0 biggr\n\nThe manifold is implemented assuming the Fisher-Rao metric for the multinomial distribution, which is equivalent to the induced metric from isometrically embedding the probability simplex in the n-sphere of radius 2. The corresponding diffeomorphism varphi mathbb Δ^n mathcal N, where mathcal N subset 2𝕊^n is given by varphi(p) = 2sqrtp.\n\nThis implementation follows the notation in [ÅströmPetraSchmitzerSchnörr2017].\n\nConstructor\n\nProbabilitySimplex(n::Int; boundary::Symbol=:open)\n\n[ÅströmPetraSchmitzerSchnörr2017]: F. Åström, S. Petra, B. Schmitzer, C. Schnörr: “Image Labeling by Assignment”, Journal of Mathematical Imaging and Vision, 58(2), pp. 221–238, 2017. doi: 10.1007/s10851-016-0702-4 arxiv: 1603.05285.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/probabilitysimplex.html#Base.exp-Tuple{ProbabilitySimplex, Vararg{Any}}","page":"Probability simplex","title":"Base.exp","text":"exp(M::ProbabilitySimplex, p, X)\n\nCompute the exponential map on the probability simplex.\n\nexp_pX = frac12Bigl(p+fracX_p^2lVert X_p rVert^2Bigr)\n+ frac12Bigl(p - fracX_p^2lVert X_p rVert^2Bigr)cos(lVert X_prVert)\n+ frac1lVert X_p rVertsqrtpsin(lVert X_prVert)\n\nwhere X_p = fracXsqrtp, with its division meant elementwise, as well as for the operations X_p^2 and sqrtp.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#Base.log-Tuple{ProbabilitySimplex, Vararg{Any}}","page":"Probability simplex","title":"Base.log","text":"log(M::ProbabilitySimplex, p, q)\n\nCompute the logarithmic map of p and q on the ProbabilitySimplex M.\n\nlog_pq = fracd_Δ^n(pq)sqrt1-sqrtpsqrtq(sqrtpq - sqrtpsqrtqp)\n\nwhere pq and sqrtp is meant elementwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#Base.rand-Tuple{ProbabilitySimplex}","page":"Probability simplex","title":"Base.rand","text":"rand(::ProbabilitySimplex; vector_at=nothing, σ::Real=1.0)\n\nWhen vector_at is nothing, return a random (uniform over the Fisher-Rao metric; that is, uniform with respect to the n-sphere whose positive orthant is mapped to the simplex). point x on the ProbabilitySimplex manifold M according to the isometric embedding into the n-sphere by normalizing the vector length of a sample from a multivariate Gaussian. See [Marsaglia1972].\n\nWhen vector_at is not nothing, return a (Gaussian) random vector from the tangent space T_pmathrmDelta^nby shifting a multivariate Gaussian with standard deviation σ to have a zero component sum.\n\n[Marsaglia1972]: Marsaglia, G.: Choosing a Point from the Surface of a Sphere. Annals of Mathematical Statistics, 43 (2): 645–646, 1972. doi: 10.1214/aoms/1177692644\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldDiff.riemannian_gradient-Tuple{ProbabilitySimplex, Any, Any}","page":"Probability simplex","title":"ManifoldDiff.riemannian_gradient","text":"X = riemannian_gradient(M::ProbabilitySimplex{n}, p, Y)\nriemannian_gradient!(M::ProbabilitySimplex{n}, X, p, Y)\n\nGiven a gradient Y = operatornamegrad tilde f(p) in the embedding ℝ^n+1 of the ProbabilitySimplex Δ^n, this function computes the Riemannian gradient X = operatornamegrad f(p) where f is the function tilde f restricted to the manifold.\n\nThe formula reads\n\n X = p Y - p Yp\n\nwhere denotes the emelementwise product.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.change_metric-Tuple{ProbabilitySimplex, EuclideanMetric, Any, Any}","page":"Probability simplex","title":"ManifoldsBase.change_metric","text":"change_metric(M::ProbabilitySimplex, ::EuclideanMetric, p, X)\n\nTo change the metric, we are looking for a function ccolon T_pΔ^n to T_pΔ^n such that for all XY T_pΔ^n This can be achieved by rewriting representer change in matrix form as (Diagonal(p) - p * p') * X and taking square root of the matrix\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.change_representer-Tuple{ProbabilitySimplex, EuclideanMetric, Any, Any}","page":"Probability simplex","title":"ManifoldsBase.change_representer","text":"change_representer(M::ProbabilitySimplex, ::EuclideanMetric, p, X)\n\nGiven a tangent vector with respect to the metric from the embedding, the EuclideanMetric, the representer of a linear functional on the tangent space is adapted as Z = p * X - p * dot(p X). The first part “compensates” for the divsion by p in the Riemannian metric on the ProbabilitySimplex and the second part performs appropriate projection to keep the vector tangent.\n\nFor details see Proposition 2.3 in [ÅströmPetraSchmitzerSchnörr2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.check_point-Union{Tuple{boundary}, Tuple{n}, Tuple{ProbabilitySimplex{n, boundary}, Any}} where {n, boundary}","page":"Probability simplex","title":"ManifoldsBase.check_point","text":"check_point(M::ProbabilitySimplex, p; kwargs...)\n\nCheck whether p is a valid point on the ProbabilitySimplex M, i.e. is a point in the embedding with positive entries that sum to one The tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.check_vector-Tuple{ProbabilitySimplex, Any, Any}","page":"Probability simplex","title":"ManifoldsBase.check_vector","text":"check_vector(M::ProbabilitySimplex, p, X; kwargs... )\n\nCheck whether X is a tangent vector to p on the ProbabilitySimplex M, i.e. after check_point(M,p), X has to be of same dimension as p and its elements have to sum to one. The tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.distance-Tuple{ProbabilitySimplex, Any, Any}","page":"Probability simplex","title":"ManifoldsBase.distance","text":"distance(M, p, q)\n\nCompute the distance between two points on the ProbabilitySimplex M. The formula reads\n\nd_Δ^n(pq) = 2arccos biggl( sum_i=1^n+1 sqrtp_i q_i biggr)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.injectivity_radius-Union{Tuple{n}, Tuple{ProbabilitySimplex{n}, Any}} where n","page":"Probability simplex","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M, p)\n\nCompute the injectivity radius on the ProbabilitySimplex M at the point p, i.e. the distanceradius to a point near/on the boundary, that could be reached by following the geodesic.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.inner-Union{Tuple{boundary}, Tuple{n}, Tuple{ProbabilitySimplex{n, boundary}, Any, Any, Any}} where {n, boundary}","page":"Probability simplex","title":"ManifoldsBase.inner","text":"inner(M::ProbabilitySimplex, p, X, Y)\n\nCompute the inner product of two tangent vectors X, Y from the tangent space T_pΔ^n at p. The formula reads\n\ng_p(XY) = sum_i=1^n+1fracX_iY_ip_i\n\nWhen M includes boundary, we can just skip coordinates where p_i is equal to 0, see Proposition 2.1 in [AyJostLeSchwachhöfer2017].\n\n[AyJostLeSchwachhöfer2017]: N. Ay, J. Jost, H. V. Le, and L. Schwachhöfer, Information Geometry. in Ergebnisse der Mathematik und ihrer Grenzgebiete. 3. Folge / A Series of Modern Surveys in Mathematics. Springer International Publishing, 2017. doi: 10.1007/978-3-319-56478-4\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.inverse_retract-Tuple{ProbabilitySimplex, Any, Any, SoftmaxInverseRetraction}","page":"Probability simplex","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::ProbabilitySimplex, p, q, ::SoftmaxInverseRetraction)\n\nCompute a first order approximation by projection. The formula reads\n\noperatornameretr^-1_p q = bigl( I_n+1 - frac1nmathbb1^n+1n+1 bigr)(log(q)-log(p))\n\nwhere mathbb1^mn is the size (m,n) matrix containing ones, and log is applied elementwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.is_flat-Tuple{ProbabilitySimplex}","page":"Probability simplex","title":"ManifoldsBase.is_flat","text":"is_flat(::ProbabilitySimplex)\n\nReturn false. ProbabilitySimplex is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.manifold_dimension-Union{Tuple{ProbabilitySimplex{n}}, Tuple{n}} where n","page":"Probability simplex","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::ProbabilitySimplex{n})\n\nReturns the manifold dimension of the probability simplex in ℝ^n+1, i.e.\n\n dim_Δ^n = n\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.project-Tuple{ProbabilitySimplex, Any, Any}","page":"Probability simplex","title":"ManifoldsBase.project","text":"project(M::ProbabilitySimplex, p, Y)\n\nProject Y from the embedding onto the tangent space at p on the ProbabilitySimplex M. The formula reads\n\n`math \\operatorname{proj}_{Δ^n}(p,Y) = Y - \\bar{Y} where barY denotes mean of Y.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.project-Tuple{ProbabilitySimplex, Any}","page":"Probability simplex","title":"ManifoldsBase.project","text":"project(M::ProbabilitySimplex, p)\n\nproject p from the embedding onto the ProbabilitySimplex M. The formula reads\n\noperatornameproj_Δ^n(p) = frac1mathbb 1pp\n\nwhere mathbb 1 ℝ denotes the vector of ones. Not that this projection is only well-defined if p has positive entries.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.representation_size-Union{Tuple{ProbabilitySimplex{n}}, Tuple{n}} where n","page":"Probability simplex","title":"ManifoldsBase.representation_size","text":"representation_size(::ProbabilitySimplex{n})\n\nReturn the representation size of points in the n-dimensional probability simplex, i.e. an array size of (n+1,).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.retract-Tuple{ProbabilitySimplex, Any, Any, SoftmaxRetraction}","page":"Probability simplex","title":"ManifoldsBase.retract","text":"retract(M::ProbabilitySimplex, p, X, ::SoftmaxRetraction)\n\nCompute a first order approximation by applying the softmax function. The formula reads\n\noperatornameretr_p X = fracpmathrme^Xpmathrme^X\n\nwhere multiplication, exponentiation and division are meant elementwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.riemann_tensor-Tuple{ProbabilitySimplex, Vararg{Any, 4}}","page":"Probability simplex","title":"ManifoldsBase.riemann_tensor","text":"riemann_tensor(::ProbabilitySimplex, p, X, Y, Z)\n\nCompute the Riemann tensor R(XY)Z at point p on ProbabilitySimplex M. It is computed using isometry with positive orthant of a sphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#Statistics.mean-Tuple{ProbabilitySimplex, Vararg{Any}}","page":"Probability simplex","title":"Statistics.mean","text":"mean(\n M::ProbabilitySimplex,\n x::AbstractVector,\n [w::AbstractWeights,]\n method = GeodesicInterpolation();\n kwargs...,\n)\n\nCompute the Riemannian mean of x using GeodesicInterpolation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#Real-probability-amplitudes","page":"Probability simplex","title":"Real probability amplitudes","text":"","category":"section"},{"location":"manifolds/probabilitysimplex.html","page":"Probability simplex","title":"Probability simplex","text":"An isometric embedding of interior of ProbabilitySimplex in positive orthant of the Sphere is established through functions simplex_to_amplitude and amplitude_to_simplex. Some properties extend to the boundary but not all.","category":"page"},{"location":"manifolds/probabilitysimplex.html","page":"Probability simplex","title":"Probability simplex","text":"This embedding isometrically maps the Fisher-Rao metric on the open probability simplex to the sphere of radius 1 with Euclidean metric. More details can be found in Section 2.2 of [AyJostLeSchwachhöfer2017].","category":"page"},{"location":"manifolds/probabilitysimplex.html","page":"Probability simplex","title":"Probability simplex","text":"The name derives from the notion of probability amplitudes in quantum mechanics. They are complex-valued and their squared norm corresponds to probability. This construction restricted to real valued amplitudes results in this embedding.","category":"page"},{"location":"manifolds/probabilitysimplex.html","page":"Probability simplex","title":"Probability simplex","text":"Modules = [Manifolds]\nPages = [\"manifolds/ProbabilitySimplex.jl\"]\nOrder = [:type, :function]\nPrivate=true\nPublic=false","category":"page"},{"location":"manifolds/probabilitysimplex.html#Manifolds.amplitude_to_simplex-Tuple{ProbabilitySimplex, Any}","page":"Probability simplex","title":"Manifolds.amplitude_to_simplex","text":"amplitude_to_simplex(M::ProbabilitySimplex{N}, p) where {N}\n\nConvert point (real) probability amplitude p on to a point on ProbabilitySimplex. The formula reads (p_1^2 p_2^2 p_N+1^2). This is an isometry from the interior of the positive orthant of a sphere to interior of the probability simplex.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#Manifolds.amplitude_to_simplex_diff-Tuple{ProbabilitySimplex, Any, Any}","page":"Probability simplex","title":"Manifolds.amplitude_to_simplex_diff","text":"amplitude_to_simplex_diff(M::ProbabilitySimplex, p, X)\n\nCompute differential of amplitude_to_simplex of a point p on ProbabilitySimplex at tangent vector X from the tangent space at p from a sphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#Manifolds.simplex_to_amplitude-Tuple{ProbabilitySimplex, Any}","page":"Probability simplex","title":"Manifolds.simplex_to_amplitude","text":"simplex_to_amplitude(M::ProbabilitySimplex, p)\n\nConvert point p on ProbabilitySimplex to (real) probability amplitude. The formula reads (sqrtp_1 sqrtp_2 sqrtp_N+1). This is an isometry from the interior of the probability simplex to the interior of the positive orthant of a sphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#Manifolds.simplex_to_amplitude_diff-Tuple{ProbabilitySimplex, Any, Any}","page":"Probability simplex","title":"Manifolds.simplex_to_amplitude_diff","text":"simplex_to_amplitude_diff(M::ProbabilitySimplex, p, X)\n\nCompute differential of simplex_to_amplitude of a point on p one ProbabilitySimplex at tangent vector X from the tangent space at p from a sphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#ManifoldsBase.zero_vector-Tuple{ProbabilitySimplex, Any}","page":"Probability simplex","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::ProbabilitySimplex, p)\n\nReturn the zero tangent vector in the tangent space of the point p from the ProbabilitySimplex M, i.e. its representation by the zero vector in the embedding.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/probabilitysimplex.html#Literature","page":"Probability simplex","title":"Literature","text":"","category":"section"},{"location":"manifolds/generalizedstiefel.html#Generalized-Stiefel","page":"Generalized Stiefel","title":"Generalized Stiefel","text":"","category":"section"},{"location":"manifolds/generalizedstiefel.html","page":"Generalized Stiefel","title":"Generalized Stiefel","text":"Modules = [Manifolds]\nPages = [\"manifolds/GeneralizedStiefel.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/generalizedstiefel.html#Manifolds.GeneralizedStiefel","page":"Generalized Stiefel","title":"Manifolds.GeneralizedStiefel","text":"GeneralizedStiefel{n,k,𝔽,B} <: AbstractDecoratorManifold{𝔽}\n\nThe Generalized Stiefel manifold consists of all ntimes k, ngeq k orthonormal matrices w.r.t. an arbitrary scalar product with symmetric positive definite matrix Bin R^n n, i.e.\n\noperatornameSt(nkB) = bigl p in mathbb F^n k big p^mathrmH B p = I_k bigr\n\nwhere 𝔽 ℝ ℂ, cdot^mathrmH denotes the complex conjugate transpose or Hermitian, and I_k in mathbb R^k k denotes the k k identity matrix.\n\nIn the case B=I_k one gets the usual Stiefel manifold.\n\nThe tangent space at a point pinmathcal M=operatornameSt(nkB) is given by\n\nT_pmathcal M = X in 𝔽^n k p^mathrmHBX + X^mathrmHBp=0_n\n\nwhere 0_k is the k k zero matrix.\n\nThis manifold is modeled as an embedded manifold to the Euclidean, i.e. several functions like the zero_vector are inherited from the embedding.\n\nThe manifold is named after Eduard L. Stiefel (1909–1978).\n\nConstructor\n\nGeneralizedStiefel(n, k, B=I_n, F=ℝ)\n\nGenerate the (real-valued) Generalized Stiefel manifold of ntimes k dimensional orthonormal matrices with scalar product B.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/generalizedstiefel.html#Base.rand-Tuple{GeneralizedStiefel}","page":"Generalized Stiefel","title":"Base.rand","text":"rand(::GeneralizedStiefel; vector_at=nothing, σ::Real=1.0)\n\nWhen vector_at is nothing, return a random (Gaussian) point p on the GeneralizedStiefel manifold M by generating a (Gaussian) matrix with standard deviation σ and return the (generalized) orthogonalized version, i.e. return the projection onto the manifold of the Q component of the QR decomposition of the random matrix of size nk.\n\nWhen vector_at is not nothing, return a (Gaussian) random vector from the tangent space T_vector_atmathrmSt(nk) with mean zero and standard deviation σ by projecting a random Matrix onto the tangent vector at vector_at.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedstiefel.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{GeneralizedStiefel{n, k, 𝔽}, Any}} where {n, k, 𝔽}","page":"Generalized Stiefel","title":"ManifoldsBase.check_point","text":"check_point(M::GeneralizedStiefel, p; kwargs...)\n\nCheck whether p is a valid point on the GeneralizedStiefel M=operatornameSt(nkB), i.e. that it has the right AbstractNumbers type and x^mathrmHBx is (approximately) the identity, where cdot^mathrmH is the complex conjugate transpose. The settings for approximately can be set with kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedstiefel.html#ManifoldsBase.check_vector-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{GeneralizedStiefel{n, k, 𝔽}, Any, Any}} where {n, k, 𝔽}","page":"Generalized Stiefel","title":"ManifoldsBase.check_vector","text":"check_vector(M::GeneralizedStiefel, p, X; kwargs...)\n\nCheck whether X is a valid tangent vector at p on the GeneralizedStiefel M=operatornameSt(nkB), i.e. the AbstractNumbers fits, p is a valid point on M and it (approximately) holds that p^mathrmHBX + overlineX^mathrmHBp = 0, where kwargs... is passed to the isapprox.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedstiefel.html#ManifoldsBase.inner-Tuple{GeneralizedStiefel, Any, Any, Any}","page":"Generalized Stiefel","title":"ManifoldsBase.inner","text":"inner(M::GeneralizedStiefel, p, X, Y)\n\nCompute the inner product for two tangent vectors X, Y from the tangent space of p on the GeneralizedStiefel manifold M. The formula reads\n\n(X Y)_p = operatornametrace(v^mathrmHBw)\n\ni.e. the metric induced by the scalar product B from the embedding, restricted to the tangent space.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedstiefel.html#ManifoldsBase.is_flat-Tuple{GeneralizedStiefel}","page":"Generalized Stiefel","title":"ManifoldsBase.is_flat","text":"is_flat(M::GeneralizedStiefel)\n\nReturn true if GeneralizedStiefel M is one-dimensional.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedstiefel.html#ManifoldsBase.manifold_dimension-Union{Tuple{GeneralizedStiefel{n, k, ℝ}}, Tuple{k}, Tuple{n}} where {n, k}","page":"Generalized Stiefel","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::GeneralizedStiefel)\n\nReturn the dimension of the GeneralizedStiefel manifold M=operatornameSt(nkB𝔽). The dimension is given by\n\nbeginaligned\ndim mathrmSt(n k B ℝ) = nk - frac12k(k+1) \ndim mathrmSt(n k B ℂ) = 2nk - k^2\ndim mathrmSt(n k B ℍ) = 4nk - k(2k-1)\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedstiefel.html#ManifoldsBase.project-Tuple{GeneralizedStiefel, Any, Any}","page":"Generalized Stiefel","title":"ManifoldsBase.project","text":"project(M:GeneralizedStiefel, p, X)\n\nProject X onto the tangent space of p to the GeneralizedStiefel manifold M. The formula reads\n\noperatornameproj_operatornameSt(nk)(pX) = X - poperatornameSym(p^mathrmHBX)\n\nwhere operatornameSym(y) is the symmetrization of y, e.g. by operatornameSym(y) = fracy^mathrmH+y2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedstiefel.html#ManifoldsBase.project-Tuple{GeneralizedStiefel, Any}","page":"Generalized Stiefel","title":"ManifoldsBase.project","text":"project(M::GeneralizedStiefel,p)\n\nProject p from the embedding onto the GeneralizedStiefel M, i.e. compute q as the polar decomposition of p such that q^mathrmHBq is the identity, where cdot^mathrmH denotes the hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedstiefel.html#ManifoldsBase.retract-Tuple{GeneralizedStiefel, Vararg{Any}}","page":"Generalized Stiefel","title":"ManifoldsBase.retract","text":"retract(M::GeneralizedStiefel, p, X)\nretract(M::GeneralizedStiefel, p, X, ::PolarRetraction)\nretract(M::GeneralizedStiefel, p, X, ::ProjectionRetraction)\n\nCompute the SVD-based retraction PolarRetraction on the GeneralizedStiefel manifold M, which in this case is the same as the projection based retraction employing the exponential map in the embedding and projecting the result back to the manifold.\n\nThe default retraction for this manifold is the ProjectionRetraction.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#Symplectic-Stiefel","page":"Symplectic Stiefel","title":"Symplectic Stiefel","text":"","category":"section"},{"location":"manifolds/symplecticstiefel.html","page":"Symplectic Stiefel","title":"Symplectic Stiefel","text":"The SymplecticStiefel manifold, denoted operatornameSpSt(2n 2k), represents canonical symplectic bases of 2k dimensonal symplectic subspaces of mathbbR^2n times 2n. This means that the columns of each element p in operatornameSpSt(2n 2k) subset mathbbR^2n times 2k constitute a canonical symplectic basis of operatornamespan(p). The canonical symplectic form is a non-degenerate, bilinear, and skew symmetric map omega_2kcolon mathbbF^2k times mathbbF^2k rightarrow mathbbF, given by omega_2k(x y) = x^T Q_2k y for elements x y in mathbbF^2k, with","category":"page"},{"location":"manifolds/symplecticstiefel.html","page":"Symplectic Stiefel","title":"Symplectic Stiefel","text":" Q_2k = \n beginbmatrix\n 0_k I_k \n -I_k 0_k\n endbmatrix","category":"page"},{"location":"manifolds/symplecticstiefel.html","page":"Symplectic Stiefel","title":"Symplectic Stiefel","text":"Specifically given an element p in operatornameSpSt(2n 2k) we require that","category":"page"},{"location":"manifolds/symplecticstiefel.html","page":"Symplectic Stiefel","title":"Symplectic Stiefel","text":" omega_2n (p x p y) = x^T(p^TQ_2np)y = x^TQ_2ky = omega_2k(x y) forall x y in mathbbF^2k","category":"page"},{"location":"manifolds/symplecticstiefel.html","page":"Symplectic Stiefel","title":"Symplectic Stiefel","text":"leading to the requirement on p that p^TQ_2np = Q_2k. In the case that k = n, this manifold reduces to the Symplectic manifold, which is also known as the symplectic group.","category":"page"},{"location":"manifolds/symplecticstiefel.html","page":"Symplectic Stiefel","title":"Symplectic Stiefel","text":"Modules = [Manifolds]\nPages = [\"manifolds/SymplecticStiefel.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/symplecticstiefel.html#Manifolds.SymplecticStiefel","page":"Symplectic Stiefel","title":"Manifolds.SymplecticStiefel","text":"SymplecticStiefel{n, k, 𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType}\n\nThe symplectic Stiefel manifold consists of all 2n 2k n geq k matrices satisfying the requirement\n\noperatornameSpSt(2n 2k ℝ)\n = bigl p ℝ^2n 2n big p^mathrmTQ_2np = Q_2k bigr\n\nwhere\n\nQ_2n =\nbeginbmatrix\n 0_n I_n \n -I_n 0_n\nendbmatrix\n\nThe symplectic Stiefel tangent space at p can be parametrized as [BendokatZimmermann2021]\n\n beginalign*\n T_poperatornameSpSt(2n 2k)\n = X in mathbbR^2n times 2k p^TQ_2nX + X^TQ_2np = 0 \n = X = pΩ + p^sB \n Ω ℝ^2k 2k Ω^+ = -Ω \n p^s operatornameSpSt(2n 2(n- k)) B ℝ^2(n-k) 2k \n endalign*\n\nwhere Ω in mathfraksp(2nF) is Hamiltonian and p^s means the symplectic complement of p s.t. p^+p^s = 0.\n\nConstructor\n\nSymplecticStiefel(2n::Int, 2k::Int, field::AbstractNumbers=ℝ)\n -> SymplecticStiefel{div(2n, 2), div(2k, 2), field}()\n\nGenerate the (real-valued) symplectic Stiefel manifold of 2n times 2k matrices which span a 2k dimensional symplectic subspace of ℝ^2n times 2n. The constructor for the SymplecticStiefel manifold accepts the even column dimension 2n and an even number of columns 2k for the real symplectic Stiefel manifold with elements p in ℝ^2n 2k.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symplecticstiefel.html#Base.exp-Tuple{SymplecticStiefel, Any, Any}","page":"Symplectic Stiefel","title":"Base.exp","text":"exp(::SymplecticStiefel, p, X)\nexp!(M::SymplecticStiefel, q, p, X)\n\nCompute the exponential mapping\n\n operatornameexpcolon ToperatornameSpSt(2n 2k)\n rightarrow operatornameSpSt(2n 2k)\n\nat a point p in operatornameSpSt(2n 2k) in the direction of X in T_poperatornameSpSt(2n 2k).\n\nThe tangent vector X can be written in the form X = barOmegap [BendokatZimmermann2021], with\n\n barOmega = X (p^mathrmTp)^-1p^mathrmT\n + Q_2np(p^mathrmTp)^-1X^mathrmT(I_2n - Q_2n^mathrmTp(p^mathrmTp)^-1p^mathrmTQ_2n)Q_2n\n in ℝ^2n times 2n\n\nwhere Q_2n is the SymplecticMatrix. Using this expression for X, the exponential mapping can be computed as\n\n operatornameexp_p(X) = operatornameExp(barOmega - barOmega^mathrmT)\n operatornameExp(barOmega^mathrmT)p\n\nwhere operatornameExp(cdot) denotes the matrix exponential.\n\nComputing the above mapping directly however, requires taking matrix exponentials of two 2n times 2n matrices, which is computationally expensive when n increases. Therefore we instead follow [BendokatZimmermann2021] who express the above exponential mapping in a way which only requires taking matrix exponentials of an 8k times 8k matrix and a 4k times 4k matrix.\n\nTo this end, first define\n\nbarA = Q_2kp^mathrmTX(p^mathrmTp)^-1Q_2k +\n (p^mathrmTp)^-1X^mathrmT(p - Q_2n^mathrmTp(p^mathrmTp)^-1Q_2k) in ℝ^2k times 2k\n\nand\n\nbarH = (I_2n - pp^+)Q_2nX(p^mathrmTp)^-1Q_2k in ℝ^2n times 2k\n\nWe then let barDelta = pbarA + barH, and define the matrices\n\n γ = leftleft(I_2n - frac12pp^+right)barDelta quad\n -p right in ℝ^2n times 4k\n\nand\n\n λ = leftQ_2n^mathrmTpQ_2k quad\n left(barDelta^+left(I_2n\n - frac12pp^+right)right)^mathrmTright in ℝ^2n times 4k\n\nWith the above defined matrices it holds that barOmega = λγ^mathrmT. As a last preliminary step, concatenate γ and λ to define the matrices Γ = λ quad -γ in ℝ^2n times 8k and Λ = γ quad λ in ℝ^2n times 8k.\n\nWith these matrix constructions done, we can compute the exponential mapping as\n\n operatornameexp_p(X) =\n Γ operatornameExp(ΛΓ^mathrmT)\n beginbmatrix\n 0_4k \n I_4k\n endbmatrix\n operatornameExp(λγ^mathrmT)\n beginbmatrix\n 0_2k \n I_2k\n endbmatrix\n\nwhich only requires computing the matrix exponentials of ΛΓ^mathrmT in ℝ^8k times 8k and λγ^mathrmT in ℝ^4k times 4k.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#Base.inv-Union{Tuple{k}, Tuple{n}, Tuple{SymplecticStiefel{n, k}, Any}} where {n, k}","page":"Symplectic Stiefel","title":"Base.inv","text":"inv(::SymplecticStiefel{n, k}, A)\ninv!(::SymplecticStiefel{n, k}, q, p)\n\nCompute the symplectic inverse A^+ of matrix A ℝ^2n 2k. Given a matrix\n\nA ℝ^2n 2kquad\nA =\nbeginbmatrix\nA_1 1 A_1 2 \nA_2 1 A_2 2\nendbmatrix A_i j in ℝ^2n 2k\n\nthe symplectic inverse is defined as:\n\nA^+ = Q_2k^mathrmT A^mathrmT Q_2n\n\nwhere\n\nQ_2n =\nbeginbmatrix\n0_n I_n \n -I_n 0_n\nendbmatrix\n\nFor any p in operatornameSpSt(2n 2k) we have that p^+p = I_2k.\n\nThe symplectic inverse of a matrix A can be expressed explicitly as:\n\nA^+ =\nbeginbmatrix\n A_2 2^mathrmT -A_1 2^mathrmT 12mm\n -A_2 1^mathrmT A_1 1^mathrmT\nendbmatrix\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#Base.rand-Union{Tuple{SymplecticStiefel{n}}, Tuple{n}} where n","page":"Symplectic Stiefel","title":"Base.rand","text":"rand(M::SymplecticStiefel; vector_at=nothing,\n hamiltonian_norm=(vector_at === nothing ? 1/2 : 1.0))\n\nGenerate a random point p in operatornameSpSt(2n 2k) or a random tangent vector X in T_poperatornameSpSt(2n 2k) if vector_at is set to a point p in operatornameSp(2n).\n\nA random point on operatornameSpSt(2n 2k) is found by first generating a random point on the symplectic manifold operatornameSp(2n), and then projecting onto the Symplectic Stiefel manifold using the canonical_project π_operatornameSpSt(2n 2k). That is, p = π_operatornameSpSt(2n 2k)(p_operatornameSp).\n\nTo generate a random tangent vector in T_poperatornameSpSt(2n 2k) this code exploits the second tangent vector space parametrization of SymplecticStiefel, showing that any X in T_poperatornameSpSt(2n 2k) can be written as X = pΩ_X + p^sB_X. To generate random tangent vectors at p then, this function sets B_X = 0 and generates a random Hamiltonian matrix Ω_X in mathfraksp(2nF) with Frobenius norm of hamiltonian_norm before returning X = pΩ_X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#ManifoldDiff.riemannian_gradient-Tuple{SymplecticStiefel, Any, Any}","page":"Symplectic Stiefel","title":"ManifoldDiff.riemannian_gradient","text":"X = riemannian_gradient(::SymplecticStiefel, f, p, Y; embedding_metric::EuclideanMetric=EuclideanMetric())\nriemannian_gradient!(::SymplecticStiefel, f, X, p, Y; embedding_metric::EuclideanMetric=EuclideanMetric())\n\nCompute the riemannian gradient X of f on SymplecticStiefel at a point p, provided that the gradient of the function tilde f, which is f continued into the embedding is given by Y. The metric in the embedding is the Euclidean metric.\n\nThe manifold gradient X is computed from Y as\n\n X = Yp^mathrmTp + Q_2npY^mathrmTQ_2np\n\nwhere Q_2n is the SymplecticMatrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#Manifolds.canonical_project-Union{Tuple{k}, Tuple{n}, Tuple{SymplecticStiefel{n, k}, Any}} where {n, k}","page":"Symplectic Stiefel","title":"Manifolds.canonical_project","text":"canonical_project(::SymplecticStiefel, p_Sp)\ncanonical_project!(::SymplecticStiefel{n,k}, p, p_Sp)\n\nDefine the canonical projection from operatornameSp(2n 2n) onto operatornameSpSt(2n 2k), by projecting onto the first k columns and the n + 1'th onto the n + k'th columns [BendokatZimmermann2021].\n\nIt is assumed that the point p is on operatornameSp(2n 2n).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#Manifolds.get_total_space-Union{Tuple{SymplecticStiefel{n, k, 𝔽}}, Tuple{𝔽}, Tuple{k}, Tuple{n}} where {n, k, 𝔽}","page":"Symplectic Stiefel","title":"Manifolds.get_total_space","text":"get_total_space(::SymplecticStiefel)\n\nReturn the total space of the SymplecticStiefel manifold, which is the corresponding Symplectic manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#Manifolds.symplectic_inverse_times-Union{Tuple{k}, Tuple{n}, Tuple{SymplecticStiefel{n, k}, Any, Any}} where {n, k}","page":"Symplectic Stiefel","title":"Manifolds.symplectic_inverse_times","text":"symplectic_inverse_times(::SymplecticStiefel, p, q)\nsymplectic_inverse_times!(::SymplecticStiefel, A, p, q)\n\nDirectly compute the symplectic inverse of p in operatornameSpSt(2n 2k), multiplied with q in operatornameSpSt(2n 2k). That is, this function efficiently computes p^+q = (Q_2kp^mathrmTQ_2n)q in ℝ^2k times 2k, where Q_2n Q_2k are the SymplecticMatrix of sizes 2n times 2n and 2k times 2k respectively.\n\nThis function performs this common operation without allocating more than a 2k times 2k matrix to store the result in, or in the case of the in-place function, without allocating memory at all.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#ManifoldsBase.check_point-Union{Tuple{k}, Tuple{n}, Tuple{SymplecticStiefel{n, k}, Any}} where {n, k}","page":"Symplectic Stiefel","title":"ManifoldsBase.check_point","text":"check_point(M::SymplecticStiefel, p; kwargs...)\n\nCheck whether p is a valid point on the SymplecticStiefel, operatornameSpSt(2n 2k) manifold. That is, the point has the right AbstractNumbers type and p^+p is (approximately) the identity, where for A in mathbbR^2n times 2k, A^+ = Q_2k^mathrmTA^mathrmTQ_2n is the symplectic inverse, with\n\nQ_2n =\nbeginbmatrix\n0_n I_n \n -I_n 0_n\nendbmatrix\n\nThe tolerance can be set with kwargs... (e.g. atol = 1.0e-14).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#ManifoldsBase.check_vector-Tuple{SymplecticStiefel, Vararg{Any}}","page":"Symplectic Stiefel","title":"ManifoldsBase.check_vector","text":"check_vector(M::Symplectic, p, X; kwargs...)\n\nChecks whether X is a valid tangent vector at p on the SymplecticStiefel, operatornameSpSt(2n 2k) manifold. First recall the definition of the symplectic inverse for A in mathbbR^2n times 2k, A^+ = Q_2k^mathrmTA^mathrmTQ_2n is the symplectic inverse, with\n\n Q_2n =\n beginbmatrix\n 0_n I_n \n -I_n 0_n\nendbmatrix\n\nThe we check that H = p^+X in 𝔤_2k, where 𝔤 is the Lie Algebra of the symplectic group operatornameSp(2k), characterized as [BendokatZimmermann2021],\n\n 𝔤_2k = H in ℝ^2k times 2k H^+ = -H \n\nThe tolerance can be set with kwargs... (e.g. atol = 1.0e-14).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#ManifoldsBase.inner-Union{Tuple{k}, Tuple{n}, Tuple{SymplecticStiefel{n, k}, Any, Any, Any}} where {n, k}","page":"Symplectic Stiefel","title":"ManifoldsBase.inner","text":"inner(M::SymplecticStiefel{n, k}, p, X. Y)\n\nCompute the Riemannian inner product g^operatornameSpSt at p in operatornameSpSt between tangent vectors X X in T_poperatornameSpSt. Given by Proposition 3.10 in [BendokatZimmermann2021].\n\ng^operatornameSpSt_p(X Y)\n = operatornametrleft(X^mathrmTleft(I_2n -\n frac12Q_2n^mathrmTp(p^mathrmTp)^-1p^mathrmTQ_2nright)Y(p^mathrmTp)^-1right)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#ManifoldsBase.inverse_retract-Tuple{SymplecticStiefel, Any, Any, CayleyInverseRetraction}","page":"Symplectic Stiefel","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(::SymplecticStiefel, p, q, ::CayleyInverseRetraction)\ninverse_retract!(::SymplecticStiefel, q, p, X, ::CayleyInverseRetraction)\n\nCompute the Cayley Inverse Retraction X = mathcalL_p^operatornameSpSt(q) such that the Cayley Retraction from p along X lands at q, i.e. mathcalR_p(X) = q [BendokatZimmermann2021].\n\nFirst, recall the definition the standard symplectic matrix\n\nQ =\nbeginbmatrix\n 0 I \n-I 0\nendbmatrix\n\nas well as the symplectic inverse of a matrix A, A^+ = Q^mathrmT A^mathrmT Q.\n\nFor p q operatornameSpSt(2n 2k ℝ) then, we can define the inverse cayley retraction as long as the following matrices exist.\n\n U = (I + p^+ q)^-1 in ℝ^2k times 2k\n quad\n V = (I + q^+ p)^-1 in ℝ^2k times 2k\n\nIf that is the case, the inverse cayley retration at p applied to q is\n\nmathcalL_p^operatornameSp(q) = 2pbigl(V - Ubigr) + 2bigl((p + q)U - pbigr)\n T_poperatornameSp(2n)\n\n[BendokatZimmermann2021]: Bendokat, Thomas and Zimmermann, Ralf: The real symplectic Stiefel and Grassmann manifolds: metrics, geodesics and applications arXiv preprint arXiv:2108.12447, 2021.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#ManifoldsBase.is_flat-Tuple{SymplecticStiefel}","page":"Symplectic Stiefel","title":"ManifoldsBase.is_flat","text":"is_flat(::SymplecticStiefel)\n\nReturn false. SymplecticStiefel is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#ManifoldsBase.manifold_dimension-Union{Tuple{SymplecticStiefel{n, k}}, Tuple{k}, Tuple{n}} where {n, k}","page":"Symplectic Stiefel","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(::SymplecticStiefel{n, k})\n\nReturns the dimension of the symplectic Stiefel manifold embedded in ℝ^2n times 2k, i.e. [BendokatZimmermann2021]\n\n operatornamedim(operatornameSpSt(2n 2k)) = (4n - 2k + 1)k\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#ManifoldsBase.project-Tuple{SymplecticStiefel, Any, Any}","page":"Symplectic Stiefel","title":"ManifoldsBase.project","text":"project(::SymplecticStiefel, p, A)\nproject!(::SymplecticStiefel, Y, p, A)\n\nGiven a point p in operatornameSpSt(2n 2k), project an element A in mathbbR^2n times 2k onto the tangent space T_poperatornameSpSt(2n 2k) relative to the euclidean metric of the embedding mathbbR^2n times 2k.\n\nThat is, we find the element X in T_poperatornameSpSt(2n 2k) which solves the constrained optimization problem\n\n operatornamemin_X in mathbbR^2n times 2k frac12X - A^2 quad\n textst\n h(X)colon= X^mathrmT Q p + p^mathrmT Q X = 0\n\nwhere h mathbbR^2n times 2k rightarrow operatornameskew(2k) defines the restriction of X onto the tangent space T_poperatornameSpSt(2n 2k).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#ManifoldsBase.retract-Tuple{SymplecticStiefel, Any, Any, CayleyRetraction}","page":"Symplectic Stiefel","title":"ManifoldsBase.retract","text":"retract(::SymplecticStiefel, p, X, ::CayleyRetraction)\nretract!(::SymplecticStiefel, q, p, X, ::CayleyRetraction)\n\nCompute the Cayley retraction on the Symplectic Stiefel manifold, computed inplace of q from p along X.\n\nGiven a point p in operatornameSpSt(2n 2k), every tangent vector X in T_poperatornameSpSt(2n 2k) is of the form X = tildeOmegap, with\n\n tildeOmega = left(I_2n - frac12pp^+right)Xp^+ -\n pX^+left(I_2n - frac12pp^+right) in ℝ^2n times 2n\n\nas shown in Proposition 3.5 of [BendokatZimmermann2021]. Using this representation of X, the Cayley retraction on operatornameSpSt(2n 2k) is defined pointwise as\n\n mathcalR_p(X) = operatornamecayleft(frac12tildeOmegaright)p\n\nThe operator operatornamecay(A) = (I - A)^-1(I + A) is the Cayley transform.\n\nHowever, the computation of an 2n times 2n matrix inverse in the expression above can be reduced down to inverting a 2k times 2k matrix due to Proposition 5.2 of [BendokatZimmermann2021].\n\nLet A = p^+X and H = X - pA. Then an equivalent expression for the Cayley retraction defined pointwise above is\n\n mathcalR_p(X) = -p + (H + 2p)(H^+H4 - A2 + I_2k)^-1\n\nIt is this expression we compute inplace of q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplecticstiefel.html#Literature","page":"Symplectic Stiefel","title":"Literature","text":"","category":"section"},{"location":"manifolds/connection.html#ConnectionSection","page":"Connection manifold","title":"Connection manifold","text":"","category":"section"},{"location":"manifolds/connection.html","page":"Connection manifold","title":"Connection manifold","text":"A connection manifold always consists of a topological manifold together with a connection Gamma.","category":"page"},{"location":"manifolds/connection.html","page":"Connection manifold","title":"Connection manifold","text":"However, often there is an implicitly assumed (default) connection, like the LeviCivitaConnection connection on a Riemannian manifold. It is not necessary to use this decorator if you implement just one (or the first) connection. If you later introduce a second, the old (first) connection can be used without an explicitly stated connection.","category":"page"},{"location":"manifolds/connection.html","page":"Connection manifold","title":"Connection manifold","text":"This manifold decorator serves two purposes:","category":"page"},{"location":"manifolds/connection.html","page":"Connection manifold","title":"Connection manifold","text":"to implement different connections (e.g. in closed form) for one AbstractManifold\nto provide a way to compute geodesics on manifolds, where this AbstractAffineConnection does not yield a closed formula.","category":"page"},{"location":"manifolds/connection.html","page":"Connection manifold","title":"Connection manifold","text":"An example of usage can be found in Cartan-Schouten connections, see AbstractCartanSchoutenConnection.","category":"page"},{"location":"manifolds/connection.html","page":"Connection manifold","title":"Connection manifold","text":"Pages = [\"connection.md\"]\nDepth = 2","category":"page"},{"location":"manifolds/connection.html#Types","page":"Connection manifold","title":"Types","text":"","category":"section"},{"location":"manifolds/connection.html","page":"Connection manifold","title":"Connection manifold","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/ConnectionManifold.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/connection.html#Manifolds.AbstractAffineConnection","page":"Connection manifold","title":"Manifolds.AbstractAffineConnection","text":"AbstractAffineConnection\n\nAbstract type for affine connections on a manifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/connection.html#Manifolds.ConnectionManifold","page":"Connection manifold","title":"Manifolds.ConnectionManifold","text":"ConnectionManifold{𝔽,,M<:AbstractManifold{𝔽},G<:AbstractAffineConnection} <: AbstractDecoratorManifold{𝔽}\n\nConstructor\n\nConnectionManifold(M, C)\n\nDecorate the AbstractManifold M with AbstractAffineConnection C.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/connection.html#Manifolds.IsConnectionManifold","page":"Connection manifold","title":"Manifolds.IsConnectionManifold","text":"IsConnectionManifold <: AbstractTrait\n\nSpecify that a certain decorated Manifold is a connection manifold in the sence that it provides explicit connection properties, extending/changing the default connection properties of a manifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/connection.html#Manifolds.IsDefaultConnection","page":"Connection manifold","title":"Manifolds.IsDefaultConnection","text":"IsDefaultConnection{G<:AbstractAffineConnection}\n\nSpecify that a certain AbstractAffineConnection is the default connection for a manifold. This way the corresponding ConnectionManifold falls back to the default methods of the manifold it decorates.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/connection.html#Manifolds.LeviCivitaConnection","page":"Connection manifold","title":"Manifolds.LeviCivitaConnection","text":"LeviCivitaConnection\n\nThe Levi-Civita connection of a Riemannian manifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/connection.html#Functions","page":"Connection manifold","title":"Functions","text":"","category":"section"},{"location":"manifolds/connection.html","page":"Connection manifold","title":"Connection manifold","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/ConnectionManifold.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/connection.html#Base.exp-Tuple{ManifoldsBase.TraitList{IsConnectionManifold}, AbstractDecoratorManifold, Any, Any}","page":"Connection manifold","title":"Base.exp","text":"exp(::TraitList{IsConnectionManifold}, M::AbstractDecoratorManifold, p, X)\n\nCompute the exponential map on a manifold that IsConnectionManifold M equipped with corresponding affine connection.\n\nIf M is a MetricManifold with a IsDefaultMetric trait, this method falls back to exp(M, p, X).\n\nOtherwise it numerically integrates the underlying ODE, see solve_exp_ode. Currently, the numerical integration is only accurate when using a single coordinate chart that covers the entire manifold. This excludes coordinates in an embedded space.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#Manifolds.christoffel_symbols_first-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Connection manifold","title":"Manifolds.christoffel_symbols_first","text":"christoffel_symbols_first(\n M::AbstractManifold,\n p,\n B::AbstractBasis;\n backend::AbstractDiffBackend = default_differential_backend(),\n)\n\nCompute the Christoffel symbols of the first kind in local coordinates of basis B. The Christoffel symbols are (in Einstein summation convention)\n\nΓ_ijk = frac12 Biglg_kji + g_ikj - g_ijkBigr\n\nwhere g_ijk=frac p^k g_ij is the coordinate derivative of the local representation of the metric tensor. The dimensions of the resulting multi-dimensional array are ordered (ijk).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#Manifolds.christoffel_symbols_second-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Connection manifold","title":"Manifolds.christoffel_symbols_second","text":"christoffel_symbols_second(\n M::AbstractManifold,\n p,\n B::AbstractBasis;\n backend::AbstractDiffBackend = default_differential_backend(),\n)\n\nCompute the Christoffel symbols of the second kind in local coordinates of basis B. For affine connection manifold the Christoffel symbols need to be explicitly implemented while, for a MetricManifold they are computed as (in Einstein summation convention)\n\nΓ^l_ij = g^kl Γ_ijk\n\nwhere Γ_ijk are the Christoffel symbols of the first kind (see christoffel_symbols_first), and g^kl is the inverse of the local representation of the metric tensor. The dimensions of the resulting multi-dimensional array are ordered (lij).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#Manifolds.christoffel_symbols_second_jacobian-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Connection manifold","title":"Manifolds.christoffel_symbols_second_jacobian","text":"christoffel_symbols_second_jacobian(\n M::AbstractManifold,\n p,\n B::AbstractBasis;\n backend::AbstractDiffBackend = default_differential_backend(),\n)\n\nGet partial derivatives of the Christoffel symbols of the second kind for manifold M at p with respect to the coordinates of B, i.e.\n\nfrac p^l Γ^k_ij = Γ^k_ijl\n\nThe dimensions of the resulting multi-dimensional array are ordered (ijkl).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#Manifolds.connection-Tuple{AbstractManifold}","page":"Connection manifold","title":"Manifolds.connection","text":"connection(M::AbstractManifold)\n\nGet the connection (an object of a subtype of AbstractAffineConnection) of AbstractManifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#Manifolds.connection-Tuple{ConnectionManifold}","page":"Connection manifold","title":"Manifolds.connection","text":"connection(M::ConnectionManifold)\n\nReturn the connection associated with ConnectionManifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#Manifolds.gaussian_curvature-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Connection manifold","title":"Manifolds.gaussian_curvature","text":"gaussian_curvature(M::AbstractManifold, p, B::AbstractBasis; backend::AbstractDiffBackend = default_differential_backend())\n\nCompute the Gaussian curvature of the manifold M at the point p using basis B. This is equal to half of the scalar Ricci curvature, see ricci_curvature.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#Manifolds.is_default_connection-Tuple{AbstractManifold, AbstractAffineConnection}","page":"Connection manifold","title":"Manifolds.is_default_connection","text":"is_default_connection(M::AbstractManifold, G::AbstractAffineConnection)\n\nreturns whether an AbstractAffineConnection is the default metric on the manifold M or not. This can be set by defining this function, or setting the IsDefaultConnection trait for an AbstractDecoratorManifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#Manifolds.ricci_tensor-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Connection manifold","title":"Manifolds.ricci_tensor","text":"ricci_tensor(M::AbstractManifold, p, B::AbstractBasis; backend::AbstractDiffBackend = default_differential_backend())\n\nCompute the Ricci tensor, also known as the Ricci curvature tensor, of the manifold M at the point p using basis B, see https://en.wikipedia.org/wiki/Ricci_curvature#Introduction_and_local_definition.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#Manifolds.solve_exp_ode-Tuple{AbstractManifold, Any, Any, Number}","page":"Connection manifold","title":"Manifolds.solve_exp_ode","text":"solve_exp_ode(\n M::AbstractConnectionManifold,\n p,\n X,\n t::Number,\n B::AbstractBasis;\n backend::AbstractDiffBackend = default_differential_backend(),\n solver = AutoVern9(Rodas5()),\n kwargs...,\n)\n\nApproximate the exponential map on the manifold by evaluating the ODE descripting the geodesic at 1, assuming the default connection of the given manifold by solving the ordinary differential equation\n\nfracd^2dt^2 p^k + Γ^k_ij fracddt p_i fracddt p_j = 0\n\nwhere Γ^k_ij are the Christoffel symbols of the second kind, and the Einstein summation convention is assumed. The argument solver follows the OrdinaryDiffEq conventions. kwargs... specify keyword arguments that will be passed to OrdinaryDiffEq.solve.\n\nCurrently, the numerical integration is only accurate when using a single coordinate chart that covers the entire manifold. This excludes coordinates in an embedded space.\n\nnote: Note\nThis function only works when OrdinaryDiffEq.jl is loaded withusing OrdinaryDiffEq\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#ManifoldsBase.riemann_tensor-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Connection manifold","title":"ManifoldsBase.riemann_tensor","text":"riemann_tensor(M::AbstractManifold, p, B::AbstractBasis; backend::AbstractDiffBackend=default_differential_backend())\n\nCompute the Riemann tensor R^l_ijk, also known as the Riemann curvature tensor, at the point p in local coordinates defined by B. The dimensions of the resulting multi-dimensional array are ordered (lijk).\n\nThe function uses the coordinate expression involving the second Christoffel symbol, see https://en.wikipedia.org/wiki/Riemann_curvature_tensor#Coordinate_expression for details.\n\nSee also\n\nchristoffel_symbols_second, christoffel_symbols_second_jacobian\n\n\n\n\n\n","category":"method"},{"location":"manifolds/connection.html#connections_charts","page":"Connection manifold","title":"Charts and bases of vector spaces","text":"","category":"section"},{"location":"manifolds/connection.html","page":"Connection manifold","title":"Connection manifold","text":"All connection-related functions take a basis of a vector space as one of the arguments. This is needed because generally there is no way to define these functions without referencing a basis. In some cases there is no need to be explicit about this basis, and then for example a DefaultOrthonormalBasis object can be used. In cases where being explicit about these bases is needed, for example when using multiple charts, a basis can be specified, for example using induced_basis.","category":"page"},{"location":"index.html#Manifolds","page":"Home","title":"Manifolds","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"Manifolds.Manifolds","category":"page"},{"location":"index.html#Manifolds.Manifolds","page":"Home","title":"Manifolds.Manifolds","text":"Manifolds.jl provides a library of manifolds aiming for an easy-to-use and fast implementation.\n\n\n\n\n\n","category":"module"},{"location":"index.html","page":"Home","title":"Home","text":"The implemented manifolds are accompanied by their mathematical formulae.","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"The manifolds are implemented using the interface for manifolds given in ManifoldsBase.jl. You can use that interface to implement your own software on manifolds, such that all manifolds based on that interface can be used within your code.","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"For more information, see the About section.","category":"page"},{"location":"index.html#Getting-started","page":"Home","title":"Getting started","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"To install the package just type","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"using Pkg; Pkg.add(\"Manifolds\")","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"Then you can directly start, for example to stop half way from the north pole on the Sphere to a point on the the equator, you can generate the shortest_geodesic. It internally employs log and exp.","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"using Manifolds\nM = Sphere(2)\nγ = shortest_geodesic(M, [0., 0., 1.], [0., 1., 0.])\nγ(0.5)","category":"page"},{"location":"index.html#Citation","page":"Home","title":"Citation","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"If you use Manifolds.jl in your work, please cite the following","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"@online{2106.08777,\n Author = {Seth D. Axen and Mateusz Baran and Ronny Bergmann and Krzysztof Rzecki},\n Title = {Manifolds.jl: An Extensible Julia Framework for Data Analysis on Manifolds},\n Year = {2021},\n Eprint = {2106.08777},\n Eprinttype = {arXiv},\n}","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"To refer to a certain version we recommend to also cite for example","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"@software{manifoldsjl-zenodo-mostrecent,\n Author = {Seth D. Axen and Mateusz Baran and Ronny Bergmann},\n Title = {Manifolds.jl},\n Doi = {10.5281/ZENODO.4292129},\n Url = {https://zenodo.org/record/4292129},\n Publisher = {Zenodo},\n Year = {2021},\n Copyright = {MIT License}\n}","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"for the most recent version or a corresponding version specific DOI, see the list of all versions. Note that both citations are in BibLaTeX format.","category":"page"},{"location":"manifolds/lorentz.html#Lorentzian-Manifold","page":"Lorentzian manifold","title":"Lorentzian Manifold","text":"","category":"section"},{"location":"manifolds/lorentz.html","page":"Lorentzian manifold","title":"Lorentzian manifold","text":"The Lorentz manifold is a pseudo-Riemannian manifold. It is named after the Dutch physicist Hendrik Lorentz (1853–1928). The default LorentzMetric is the MinkowskiMetric named after the German mathematician Hermann Minkowski (1864–1909).","category":"page"},{"location":"manifolds/lorentz.html","page":"Lorentzian manifold","title":"Lorentzian manifold","text":"Within Manifolds.jl it is used as the embedding of the Hyperbolic space.","category":"page"},{"location":"manifolds/lorentz.html","page":"Lorentzian manifold","title":"Lorentzian manifold","text":"Modules = [Manifolds]\nPages = [\"Lorentz.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/lorentz.html#Manifolds.Lorentz","page":"Lorentzian manifold","title":"Manifolds.Lorentz","text":"Lorentz{N} = MetricManifold{Euclidean{N,ℝ},LorentzMetric}\n\nThe Lorentz manifold (or Lorentzian) is a pseudo-Riemannian manifold.\n\nConstructor\n\nLorentz(n[, metric=MinkowskiMetric()])\n\nGenerate the Lorentz manifold of dimension n with the LorentzMetric m, which is by default set to the MinkowskiMetric.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/lorentz.html#Manifolds.LorentzMetric","page":"Lorentzian manifold","title":"Manifolds.LorentzMetric","text":"LorentzMetric <: AbstractMetric\n\nAbstract type for Lorentz metrics, which have a single time dimension. These metrics assume the spacelike convention with the time dimension being last, giving the signature (+++-).\n\n\n\n\n\n","category":"type"},{"location":"manifolds/lorentz.html#Manifolds.MinkowskiMetric","page":"Lorentzian manifold","title":"Manifolds.MinkowskiMetric","text":"MinkowskiMetric <: LorentzMetric\n\nAs a special metric of signature (+++-), i.e. a LorentzMetric, see minkowski_metric for the formula.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/lorentz.html#Manifolds.minkowski_metric-Tuple{Any, Any}","page":"Lorentzian manifold","title":"Manifolds.minkowski_metric","text":"minkowski_metric(a,b)\n\nCompute the minkowski metric on mathbb R^n is given by\n\nab_mathrmM = -a_nb_n +\ndisplaystylesum_k=1^n-1 a_kb_k\n\n\n\n\n\n","category":"method"},{"location":"misc/internals.html#Internal-documentation","page":"Internals","title":"Internal documentation","text":"","category":"section"},{"location":"misc/internals.html","page":"Internals","title":"Internals","text":"This page documents the internal types and methods of Manifolds.jl's that might be of use for writing your own manifold.","category":"page"},{"location":"misc/internals.html#Functions","page":"Internals","title":"Functions","text":"","category":"section"},{"location":"misc/internals.html","page":"Internals","title":"Internals","text":"Manifolds.eigen_safe\nManifolds.isnormal\nManifolds.log_safe\nManifolds.log_safe!\nManifolds.mul!_safe\nManifolds.nzsign\nManifolds.realify\nManifolds.realify!\nManifolds.select_from_tuple\nManifolds.unrealify!\nManifolds.usinc\nManifolds.usinc_from_cos\nManifolds.vec2skew!\nManifolds.ziptuples","category":"page"},{"location":"misc/internals.html#Manifolds.eigen_safe","page":"Internals","title":"Manifolds.eigen_safe","text":"eigen_safe(x)\n\nCompute the eigendecomposition of x. If x is a StaticMatrix, it is converted to a Matrix before the decomposition.\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.isnormal","page":"Internals","title":"Manifolds.isnormal","text":"isnormal(x; kwargs...) -> Bool\n\nCheck if the matrix or number x is normal, that is, if it commutes with its adjoint:\n\nx x^mathrmH = x^mathrmH x\n\nBy default, this is an equality check. Provide kwargs for isapprox to perform an approximate check.\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.log_safe","page":"Internals","title":"Manifolds.log_safe","text":"log_safe(x)\n\nCompute the matrix logarithm of x. If x is a StaticMatrix, it is converted to a Matrix before computing the log.\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.log_safe!","page":"Internals","title":"Manifolds.log_safe!","text":"log_safe!(y, x)\n\nCompute the matrix logarithm of x. If the eltype of y is real, then the imaginary part of x is ignored, and a DomainError is raised if real(x) has no real logarithm.\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.mul!_safe","page":"Internals","title":"Manifolds.mul!_safe","text":"mul!_safe(Y, A, B) -> Y\n\nCall mul! safely, that is, A and/or B are permitted to alias with Y.\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.nzsign","page":"Internals","title":"Manifolds.nzsign","text":"nzsign(z[, absz])\n\nCompute a modified sign(z) that is always nonzero, i.e. where\n\noperatorname(nzsign)(z) = begincases\n 1 textif z = 0\n fraczz textotherwise\nendcases\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.realify","page":"Internals","title":"Manifolds.realify","text":"realify(X::AbstractMatrix{T𝔽}, 𝔽::AbstractNumbers) -> Y::AbstractMatrix{<:Real}\n\nGiven a matrix X 𝔽^n n, compute Y ℝ^m m, where m = n operatornamedim_𝔽, and operatornamedim_𝔽 is the real_dimension of the number field 𝔽, using the map ϕ colon X Y, that preserves the matrix product, so that for all CD 𝔽^n n,\n\nϕ(C) ϕ(D) = ϕ(CD)\n\nSee realify! for an in-place version, and unrealify! to compute the inverse of ϕ.\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.realify!","page":"Internals","title":"Manifolds.realify!","text":"realify!(Y::AbstractMatrix{<:Real}, X::AbstractMatrix{T𝔽}, 𝔽::AbstractNumbers)\n\nIn-place version of realify.\n\n\n\n\n\nrealify!(Y::AbstractMatrix{<:Real}, X::AbstractMatrix{<:Complex}, ::typeof(ℂ))\n\nGiven a complex matrix X = A + iB ℂ^n n, compute its realified matrix Y ℝ^2n 2n, written where\n\nY = beginpmatrixA -B B A endpmatrix\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.select_from_tuple","page":"Internals","title":"Manifolds.select_from_tuple","text":"select_from_tuple(t::NTuple{N, Any}, positions::Val{P})\n\nSelects elements of tuple t at positions specified by the second argument. For example select_from_tuple((\"a\", \"b\", \"c\"), Val((3, 1, 1))) returns (\"c\", \"a\", \"a\").\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.unrealify!","page":"Internals","title":"Manifolds.unrealify!","text":"unrealify!(X::AbstractMatrix{T𝔽}, Y::AbstractMatrix{<:Real}, 𝔽::AbstractNumbers[, n])\n\nGiven a real matrix Y ℝ^m m, where m = n operatornamedim_𝔽, and operatornamedim_𝔽 is the real_dimension of the number field 𝔽, compute in-place its equivalent matrix X 𝔽^n n. Note that this function does not check that Y has a valid structure to be un-realified.\n\nSee realify! for the inverse of this function.\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.usinc","page":"Internals","title":"Manifolds.usinc","text":"usinc(θ::Real)\n\nUnnormalized version of sinc function, i.e. operatornameusinc(θ) = fracsin(θ)θ. This is equivalent to sinc(θ/π).\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.usinc_from_cos","page":"Internals","title":"Manifolds.usinc_from_cos","text":"usinc_from_cos(x::Real)\n\nUnnormalized version of sinc function, i.e. operatornameusinc(θ) = fracsin(θ)θ, computed from x = cos(θ).\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.vec2skew!","page":"Internals","title":"Manifolds.vec2skew!","text":"vec2skew!(X, v, k)\n\ncreate a skew symmetric matrix inplace in X of size ktimes k from a vector v, for example for v=[1,2,3] and k=3 this yields\n\n[ 0 1 2;\n -1 0 3;\n -2 -3 0\n]\n\n\n\n\n\n","category":"function"},{"location":"misc/internals.html#Manifolds.ziptuples","page":"Internals","title":"Manifolds.ziptuples","text":"ziptuples(a, b[, c[, d[, e]]])\n\nZips tuples a, b, and remaining in a fast, type-stable way. If they have different lengths, the result is trimmed to the length of the shorter tuple.\n\n\n\n\n\n","category":"function"},{"location":"manifolds/sphere.html#SphereSection","page":"Sphere","title":"Sphere and unit norm arrays","text":"","category":"section"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"AbstractSphere","category":"page"},{"location":"manifolds/sphere.html#Manifolds.AbstractSphere","page":"Sphere","title":"Manifolds.AbstractSphere","text":"AbstractSphere{𝔽} <: AbstractDecoratorManifold{𝔽}\n\nAn abstract type to represent a unit sphere that is represented isometrically in the embedding.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"The classical sphere, i.e. unit norm (real- or complex-valued) vectors can be generated as usual: to create the 2-dimensional sphere (in ℝ^3), use Sphere(2) and Sphere(2,ℂ), respectively.","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"Sphere","category":"page"},{"location":"manifolds/sphere.html#Manifolds.Sphere","page":"Sphere","title":"Manifolds.Sphere","text":"Sphere{n,𝔽} <: AbstractSphere{𝔽}\n\nThe (unit) sphere manifold 𝕊^n is the set of all unit norm vectors in 𝔽^n+1. The sphere is represented in the embedding, i.e.\n\n𝕊^n = bigl p in 𝔽^n+1 big lVert p rVert = 1 bigr\n\nwhere 𝔽inℝℂℍ. Note that compared to the ArraySphere, here the argument n of the manifold is the dimension of the manifold, i.e. 𝕊^n 𝔽^n+1, nin ℕ.\n\nThe tangent space at point p is given by\n\nT_p𝕊^n = bigl X 𝔽^n+1 Re(pX) = 0 bigr \n\nwhere 𝔽inℝℂℍ and cdotcdot denotes the inner product in the embedding 𝔽^n+1.\n\nFor 𝔽=ℂ, the manifold is the complex sphere, written ℂ𝕊^n, embedded in ℂ^n+1. ℂ𝕊^n is the complexification of the real sphere 𝕊^2n+1. Likewise, the quaternionic sphere ℍ𝕊^n is the quaternionification of the real sphere 𝕊^4n+3. Consequently, ℂ𝕊^0 is equivalent to 𝕊^1 and Circle, while ℂ𝕊^1 and ℍ𝕊^0 are equivalent to 𝕊^3, though with different default representations.\n\nThis manifold is modeled as a special case of the more general case, i.e. as an embedded manifold to the Euclidean, and several functions like the inner product and the zero_vector are inherited from the embedding.\n\nConstructor\n\nSphere(n[, field=ℝ])\n\nGenerate the (real-valued) sphere 𝕊^n ℝ^n+1, where field can also be used to generate the complex- and quaternionic-valued sphere.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"For the higher-dimensional arrays, for example unit (Frobenius) norm matrices, the manifold is generated using the size of the matrix. To create the unit sphere of 32 real-valued matrices, write ArraySphere(3,2) and the complex case is done – as for the Euclidean case – with an keyword argument ArraySphere(3,2; field = ℂ). This case also covers the classical sphere as a special case, but you specify the size of the vectors/embedding instead: The 2-sphere can here be generated ArraySphere(3).","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"ArraySphere","category":"page"},{"location":"manifolds/sphere.html#Manifolds.ArraySphere","page":"Sphere","title":"Manifolds.ArraySphere","text":"ArraySphere{T<:Tuple,𝔽} <: AbstractSphere{𝔽}\n\nThe (unit) sphere manifold 𝕊^n₁n₂nᵢ is the set of all unit (Frobenius) norm elements of 𝔽^n₁n₂nᵢ, where 𝔽\\in{ℝ,ℂ,ℍ}. The generalized sphere is represented in the embedding, and supports arbitrary sized arrays or in other words arbitrary tensors of unit norm. The set formally reads\n\n𝕊^n_1 n_2 n_i = bigl p in 𝔽^n_1 n_2 n_i big lVert p rVert = 1 bigr\n\nwhere 𝔽inℝℂℍ. Setting i=1 and 𝔽=ℝ this simplifies to unit vectors in ℝ^n, see Sphere for this special case. Note that compared to this classical case, the argument for the generalized case here is given by the dimension of the embedding. This means that Sphere(2) and ArraySphere(3) are the same manifold.\n\nThe tangent space at point p is given by\n\nT_p 𝕊^n_1 n_2 n_i = bigl X 𝔽^n_1 n_2 n_i Re(pX) = 0 bigr \n\nwhere 𝔽inℝℂℍ and cdotcdot denotes the (Frobenius) inner product in the embedding 𝔽^n_1 n_2 n_i.\n\nThis manifold is modeled as an embedded manifold to the Euclidean, i.e. several functions like the inner product and the zero_vector are inherited from the embedding.\n\nConstructor\n\nArraySphere(n₁,n₂,...,nᵢ; field=ℝ)\n\nGenerate sphere in 𝔽^n_1 n_2 n_i, where 𝔽 defaults to the real-valued case ℝ.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"There is also one atlas available on the sphere.","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"Manifolds.StereographicAtlas","category":"page"},{"location":"manifolds/sphere.html#Manifolds.StereographicAtlas","page":"Sphere","title":"Manifolds.StereographicAtlas","text":"StereographicAtlas()\n\nThe stereographic atlas of S^n with two charts: one with the singular point (-1, 0, ..., 0) (called :north) and one with the singular point (1, 0, ..., 0) (called :south).\n\n\n\n\n\n","category":"type"},{"location":"manifolds/sphere.html#Functions-on-unit-spheres","page":"Sphere","title":"Functions on unit spheres","text":"","category":"section"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"Modules = [Manifolds]\nPages = [\"manifolds/Sphere.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/sphere.html#Base.exp-Tuple{AbstractSphere, Vararg{Any}}","page":"Sphere","title":"Base.exp","text":"exp(M::AbstractSphere, p, X)\n\nCompute the exponential map from p in the tangent direction X on the AbstractSphere M by following the great arc eminating from p in direction X.\n\nexp_p X = cos(lVert X rVert_p)p + sin(lVert X rVert_p)fracXlVert X rVert_p\n\nwhere lVert X rVert_p is the norm on the tangent space at p of the AbstractSphere M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#Base.log-Tuple{AbstractSphere, Vararg{Any}}","page":"Sphere","title":"Base.log","text":"log(M::AbstractSphere, p, q)\n\nCompute the logarithmic map on the AbstractSphere M, i.e. the tangent vector, whose geodesic starting from p reaches q after time 1. The formula reads for x -y\n\nlog_p q = d_𝕊(pq) fracq-Re(pq) plVert q-Re(pq) p rVert_2\n\nand a deterministic choice from the set of tangent vectors is returned if x=-y, i.e. for opposite points.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#Manifolds.local_metric-Union{Tuple{n}, Tuple{Sphere{n, ℝ}, Any, DefaultOrthonormalBasis}} where n","page":"Sphere","title":"Manifolds.local_metric","text":"local_metric(M::Sphere{n}, p, ::DefaultOrthonormalBasis)\n\nreturn the local representation of the metric in a DefaultOrthonormalBasis, namely the diagonal matrix of size nn with ones on the diagonal, since the metric is obtained from the embedding by restriction to the tangent space T_pmathcal M at p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#Manifolds.uniform_distribution-Union{Tuple{n}, Tuple{Sphere{n, ℝ}, Any}} where n","page":"Sphere","title":"Manifolds.uniform_distribution","text":"uniform_distribution(M::Sphere{n,ℝ}, p) where {n}\n\nUniform distribution on given Sphere M. Generated points will be of similar type as p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.Weingarten-Tuple{Sphere, Any, Any, Any}","page":"Sphere","title":"ManifoldsBase.Weingarten","text":"Weingarten(M::Sphere, p, X, V)\n\nCompute the Weingarten map mathcal W_p at p on the Sphere M with respect to the tangent vector X in T_pmathcal M and the normal vector V in N_pmathcal M.\n\nThe formula is due to [AMT13] given by\n\n\\mathcal W_p(X,V) = -Xp^{\\mathrm{T}}V\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.check_point-Tuple{AbstractSphere, Any}","page":"Sphere","title":"ManifoldsBase.check_point","text":"check_point(M::AbstractSphere, p; kwargs...)\n\nCheck whether p is a valid point on the AbstractSphere M, i.e. is a point in the embedding of unit length. The tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.check_vector-Tuple{AbstractSphere, Any, Any}","page":"Sphere","title":"ManifoldsBase.check_vector","text":"check_vector(M::AbstractSphere, p, X; kwargs... )\n\nCheck whether X is a tangent vector to p on the AbstractSphere M, i.e. after check_point(M,p), X has to be of same dimension as p and orthogonal to p. The tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.distance-Tuple{AbstractSphere, Any, Any}","page":"Sphere","title":"ManifoldsBase.distance","text":"distance(M::AbstractSphere, p, q)\n\nCompute the geodesic distance betweeen p and q on the AbstractSphere M. The formula is given by the (shorter) great arc length on the (or a) great circle both p and q lie on.\n\nd_𝕊(pq) = arccos(Re(pq))\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.get_coordinates-Tuple{AbstractSphere{ℝ}, Any, Any, DefaultOrthonormalBasis}","page":"Sphere","title":"ManifoldsBase.get_coordinates","text":"get_coordinates(M::AbstractSphere{ℝ}, p, X, B::DefaultOrthonormalBasis)\n\nRepresent the tangent vector X at point p from the AbstractSphere M in an orthonormal basis by rotating the hyperplane containing X to a hyperplane whose normal is the x-axis.\n\nGiven q = p λ + x, where λ = operatornamesgn(x p), and _mathrmF denotes the Frobenius inner product, the formula for Y is\n\nbeginpmatrix0 Yendpmatrix = X - qfrac2 q X_mathrmFq q_mathrmF\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.get_vector-Tuple{AbstractSphere{ℝ}, Any, Any, DefaultOrthonormalBasis}","page":"Sphere","title":"ManifoldsBase.get_vector","text":"get_vector(M::AbstractSphere{ℝ}, p, X, B::DefaultOrthonormalBasis)\n\nConvert a one-dimensional vector of coefficients X in the basis B of the tangent space at p on the AbstractSphere M to a tangent vector Y at p by rotating the hyperplane containing X, whose normal is the x-axis, to the hyperplane whose normal is p.\n\nGiven q = p λ + x, where λ = operatornamesgn(x p), and _mathrmF denotes the Frobenius inner product, the formula for Y is\n\nY = X - qfrac2 leftlangle q beginpmatrix0 Xendpmatrixrightrangle_mathrmFq q_mathrmF\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.injectivity_radius-Tuple{AbstractSphere}","page":"Sphere","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::AbstractSphere[, p])\n\nReturn the injectivity radius for the AbstractSphere M, which is globally π.\n\ninjectivity_radius(M::Sphere, x, ::ProjectionRetraction)\n\nReturn the injectivity radius for the ProjectionRetraction on the AbstractSphere, which is globally fracπ2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.inverse_retract-Tuple{AbstractSphere, Any, Any, ProjectionInverseRetraction}","page":"Sphere","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::AbstractSphere, p, q, ::ProjectionInverseRetraction)\n\nCompute the inverse of the projection based retraction on the AbstractSphere M, i.e. rearranging p+X = qlVert p+XrVert_2 yields since Re(pX) = 0 and when d_𝕊^2(pq) fracπ2 that\n\noperatornameretr_p^-1(q) = fracqRe(p q) - p\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.is_flat-Tuple{AbstractSphere}","page":"Sphere","title":"ManifoldsBase.is_flat","text":"is_flat(M::AbstractSphere)\n\nReturn true if AbstractSphere is of dimension 1 and false otherwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.manifold_dimension-Tuple{AbstractSphere}","page":"Sphere","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::AbstractSphere)\n\nReturn the dimension of the AbstractSphere M, respectively i.e. the dimension of the embedding -1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.parallel_transport_to-Tuple{AbstractSphere, Vararg{Any, 4}}","page":"Sphere","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::AbstractSphere, p, X, q)\n\nCompute the parallel transport on the Sphere of the tangent vector X at p to q, provided, the geodesic between p and q is unique. The formula reads\n\nP_pq(X) = X - fracRe(log_p qX_p)d^2_𝕊(pq)\nbigl(log_p q + log_q p bigr)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.project-Tuple{AbstractSphere, Any, Any}","page":"Sphere","title":"ManifoldsBase.project","text":"project(M::AbstractSphere, p, X)\n\nProject the point X onto the tangent space at p on the Sphere M.\n\noperatornameproj_p(X) = X - Re(p X)p\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.project-Tuple{AbstractSphere, Any}","page":"Sphere","title":"ManifoldsBase.project","text":"project(M::AbstractSphere, p)\n\nProject the point p from the embedding onto the Sphere M.\n\noperatornameproj(p) = fracplVert p rVert\n\nwhere lVertcdotrVert denotes the usual 2-norm for vectors if m=1 and the Frobenius norm for the case m1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.representation_size-Union{Tuple{ArraySphere{N}}, Tuple{N}} where N","page":"Sphere","title":"ManifoldsBase.representation_size","text":"representation_size(M::AbstractSphere)\n\nReturn the size points on the AbstractSphere M are represented as, i.e., the representation size of the embedding.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.retract-Tuple{AbstractSphere, Any, Any, ProjectionRetraction}","page":"Sphere","title":"ManifoldsBase.retract","text":"retract(M::AbstractSphere, p, X, ::ProjectionRetraction)\n\nCompute the retraction that is based on projection, i.e.\n\noperatornameretr_p(X) = fracp+XlVert p+X rVert_2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#ManifoldsBase.riemann_tensor-Tuple{AbstractSphere{ℝ}, Vararg{Any, 4}}","page":"Sphere","title":"ManifoldsBase.riemann_tensor","text":"riemann_tensor(M::AbstractSphere{ℝ}, p, X, Y, Z)\n\nCompute the Riemann tensor R(XY)Z at point p on AbstractSphere M. The formula reads [MuralidharanFletcher2021] (though note that a different convention is used in that paper than in Manifolds.jl):\n\nR(XY)Z = langle Z Y rangle X - langle Z X rangle Y\n\n[MuralidharanFletcher2021]: P. Muralidharan and P. T. Fletcher, “Sasaki Metrics for Analysis of Longitudinal Data on Manifolds,” Proc IEEE Comput Soc Conf Comput Vis Pattern Recognit, vol. 2012, pp. 1027–1034, Jun. 2012, doi: 10.1109/CVPR.2012.6247780.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#Statistics.mean-Tuple{AbstractSphere, Vararg{Any}}","page":"Sphere","title":"Statistics.mean","text":"mean(\n S::AbstractSphere,\n x::AbstractVector,\n [w::AbstractWeights,]\n method = GeodesicInterpolationWithinRadius(π/2);\n kwargs...,\n)\n\nCompute the Riemannian mean of x using GeodesicInterpolationWithinRadius.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/sphere.html#Visualization-on-Sphere{2,ℝ}","page":"Sphere","title":"Visualization on Sphere{2,ℝ}","text":"","category":"section"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"You can visualize both points and tangent vectors on the sphere.","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"note: Note\nThere seems to be no unified way to draw spheres in the backends of Plots.jl. This recipe currently uses the seriestype wireframe and surface, which does not yet work with the default backend GR.","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"In general you can plot the surface of the hyperboloid either as wireframe (wireframe=true) additionally specifying wires (or wires_x and wires_y) to change the density of the wires and a wireframe_color for their color. The same holds for the plot as a surface (which is false by default) and its surface_resolution (or surface_resolution_lat or surface_resolution_lon) and a surface_color.","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"using Manifolds, Plots\npythonplot()\nM = Sphere(2)\npts = [ [1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0] ]\nscene = plot(M, pts; wireframe_color=colorant\"#CCCCCC\", markersize=10)","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"which scatters our points. We can also draw connecting geodesics, which here is a geodesic triangle. Here we discretize each geodesic with 100 points along the geodesic. The default value is geodesic_interpolation=-1 which switches to scatter plot of the data.","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"plot!(scene, M, pts; wireframe=false, geodesic_interpolation=100, linewidth=2)","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"And we can also add tangent vectors, for example tangents pointing towards the geometric center of given points.","category":"page"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"pts2 = [ [1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0] ]\np3 = 1/sqrt(3) .* [1.0, -1.0, 1.0]\nvecs = log.(Ref(M), pts2, Ref(p3))\nplot!(scene, M, pts2, vecs; wireframe = false, linewidth=1.5)","category":"page"},{"location":"manifolds/sphere.html#Literature","page":"Sphere","title":"Literature","text":"","category":"section"},{"location":"manifolds/sphere.html","page":"Sphere","title":"Sphere","text":"Pages = [\"manifolds/sphere.md\"]\nCanonical=false","category":"page"},{"location":"manifolds/shapespace.html#Shape-spaces","page":"Shape spaces","title":"Shape spaces","text":"","category":"section"},{"location":"manifolds/shapespace.html","page":"Shape spaces","title":"Shape spaces","text":"Shape spaces are spaces of k points in mathbbR^n up to simultaneous action of a group on all points. The most commonly encountered are Kendall's pre-shape and shape spaces. In the case of the Kendall's pre-shape spaces the action is translation and scaling. In the case of the Kendall's shape spaces the action is translation, scaling and rotation.","category":"page"},{"location":"manifolds/shapespace.html","page":"Shape spaces","title":"Shape spaces","text":"using Manifolds, Plots\n\nM = KendallsShapeSpace(2, 3)\n# two random point on the shape space\np = [\n 0.4385117672460505 -0.6877826444042382 0.24927087715818771\n -0.3830259932279294 0.35347460720654283 0.029551386021386548\n]\nq = [\n -0.42693314765896473 -0.3268567431952937 0.7537898908542584\n 0.3054740561061169 -0.18962848284149897 -0.11584557326461796\n]\n# let's plot them as triples of points on a plane\nfig = scatter(p[1,:], p[2,:], label=\"p\", aspect_ratio=:equal)\nscatter!(fig, q[1,:], q[2,:], label=\"q\")\n\n# aligning q to p\nA = get_orbit_action(M)\na = optimal_alignment(A, p, q)\nrot_q = apply(A, a, q)\nscatter!(fig, rot_q[1,:], rot_q[2,:], label=\"q aligned to p\")","category":"page"},{"location":"manifolds/shapespace.html","page":"Shape spaces","title":"Shape spaces","text":"A more extensive usage example is available in the hand_gestures.jl tutorial.","category":"page"},{"location":"manifolds/shapespace.html","page":"Shape spaces","title":"Shape spaces","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/KendallsPreShapeSpace.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/shapespace.html#Manifolds.KendallsPreShapeSpace","page":"Shape spaces","title":"Manifolds.KendallsPreShapeSpace","text":"KendallsPreShapeSpace{n,k} <: AbstractSphere{ℝ}\n\nKendall's pre-shape space of k landmarks in ℝ^n represented by n×k matrices. In each row the sum of elements of a matrix is equal to 0. The Frobenius norm of the matrix is equal to 1 [Kendall1984][Kendall1989].\n\nThe space can be interpreted as tuples of k points in ℝ^n up to simultaneous translation and scaling of all points, so this can be thought of as a quotient manifold.\n\nConstructor\n\nKendallsPreShapeSpace(n::Int, k::Int)\n\nSee also\n\nKendallsShapeSpace, esp. for the references\n\n\n\n\n\n","category":"type"},{"location":"manifolds/shapespace.html","page":"Shape spaces","title":"Shape spaces","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/KendallsShapeSpace.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/shapespace.html#Manifolds.KendallsShapeSpace","page":"Shape spaces","title":"Manifolds.KendallsShapeSpace","text":"KendallsShapeSpace{n,k} <: AbstractDecoratorManifold{ℝ}\n\nKendall's shape space, defined as quotient of a KendallsPreShapeSpace (represented by n×k matrices) by the action ColumnwiseMultiplicationAction.\n\nThe space can be interpreted as tuples of k points in ℝ^n up to simultaneous translation and scaling and rotation of all points [Kendall1984][Kendall1989].\n\nThis manifold possesses the IsQuotientManifold trait.\n\nConstructor\n\nKendallsShapeSpace(n::Int, k::Int)\n\nReferences\n\n[Kendall1989]: D. G. Kendall, “A Survey of the Statistical Theory of Shape,” Statist. Sci., vol. 4, no. 2, pp. 87–99, May 1989 doi: 10.1214/ss/1177012582.\n\n[Kendall1984]: D. G. Kendall, “Shape Manifolds, Procrustean Metrics, and Complex Projective Spaces,” Bull. London Math. Soc., vol. 16, no. 2, pp. 81–121, Mar. 1984 doi: 10.1112/blms/16.2.81.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/shapespace.html#Provided-functions","page":"Shape spaces","title":"Provided functions","text":"","category":"section"},{"location":"manifolds/shapespace.html","page":"Shape spaces","title":"Shape spaces","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/KendallsPreShapeSpace.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/shapespace.html#ManifoldsBase.check_point-Tuple{KendallsPreShapeSpace, Any}","page":"Shape spaces","title":"ManifoldsBase.check_point","text":"check_point(M::KendallsPreShapeSpace, p; atol=sqrt(max_eps(X, Y)), kwargs...)\n\nCheck whether p is a valid point on KendallsPreShapeSpace, i.e. whether each row has zero mean. Other conditions are checked via embedding in ArraySphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#ManifoldsBase.check_vector-Tuple{KendallsPreShapeSpace, Any, Any}","page":"Shape spaces","title":"ManifoldsBase.check_vector","text":"check_vector(M::KendallsPreShapeSpace, p, X; kwargs... )\n\nCheck whether X is a valid tangent vector on KendallsPreShapeSpace, i.e. whether each row has zero mean. Other conditions are checked via embedding in ArraySphere.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#ManifoldsBase.get_embedding-Union{Tuple{KendallsPreShapeSpace{N, K}}, Tuple{K}, Tuple{N}} where {N, K}","page":"Shape spaces","title":"ManifoldsBase.get_embedding","text":"get_embedding(M::KendallsPreShapeSpace)\n\nReturn the space KendallsPreShapeSpace M is embedded in, i.e. ArraySphere of matrices of the same shape.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#ManifoldsBase.manifold_dimension-Union{Tuple{KendallsPreShapeSpace{n, k}}, Tuple{k}, Tuple{n}} where {n, k}","page":"Shape spaces","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::KendallsPreShapeSpace)\n\nReturn the dimension of the KendallsPreShapeSpace manifold M. The dimension is given by n(k - 1) - 1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#ManifoldsBase.project-Tuple{KendallsPreShapeSpace, Any, Any}","page":"Shape spaces","title":"ManifoldsBase.project","text":"project(M::KendallsPreShapeSpace, p, X)\n\nProject tangent vector X at point p from the embedding to KendallsPreShapeSpace by selecting the right element from the tangent space to orthogonal section representing the quotient manifold M. See Section 3.7 of [Srivastava2016] for details.\n\nReferences\n\n[Srivastava2016]: A. Srivastava and E. P. Klassen, Functional and Shape Data Analysis. Springer New York, 2016. ISBN: 978-1-4939-4018-9. doi: 10.1007/978-1-4939-4020-2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#ManifoldsBase.project-Tuple{KendallsPreShapeSpace, Any}","page":"Shape spaces","title":"ManifoldsBase.project","text":"project(M::KendallsPreShapeSpace, p)\n\nProject point p from the embedding to KendallsPreShapeSpace by selecting the right element from the orthogonal section representing the quotient manifold M. See Section 3.7 of [Srivastava2016] for details.\n\nThe method computes the mean of the landmarks and moves them to make their mean zero; afterwards the Frobenius norm of the landmarks (as a matrix) is normalised to fix the scaling.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html","page":"Shape spaces","title":"Shape spaces","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/KendallsShapeSpace.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/shapespace.html#Base.exp-Tuple{KendallsShapeSpace, Any, Any}","page":"Shape spaces","title":"Base.exp","text":"exp(M::KendallsShapeSpace, p, X)\n\nCompute the exponential map on KendallsShapeSpace M. See [Guigui2021] for discussion about its computation.\n\n[Guigui2021]: N. Guigui, E. Maignant, A. Trouvé, and X. Pennec, “Parallel Transport on Kendall Shape Spaces,” in Geometric Science of Information, Cham, 2021, pp. 103–110. doi: 10.1007/978-3-030-80209-7_12.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#Base.log-Tuple{KendallsShapeSpace, Any, Any}","page":"Shape spaces","title":"Base.log","text":"log(M::KendallsShapeSpace, p, q)\n\nCompute the logarithmic map on KendallsShapeSpace M. See the [exp](@ref exp(::KendallsShapeSpace, ::Any, ::Any)onential map for more details\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#Base.rand-Tuple{KendallsShapeSpace}","page":"Shape spaces","title":"Base.rand","text":"rand(::KendallsShapeSpace; vector_at=nothing)\n\nWhen vector_at is nothing, return a random point x on the KendallsShapeSpace manifold M by generating a random point in the embedding.\n\nWhen vector_at is not nothing, return a random vector from the tangent space with mean zero and standard deviation σ.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#Manifolds.get_total_space-Union{Tuple{KendallsShapeSpace{n, k}}, Tuple{k}, Tuple{n}} where {n, k}","page":"Shape spaces","title":"Manifolds.get_total_space","text":"get_total_space(::Grassmann{n,k})\n\nReturn the total space of the KendallsShapeSpace manifold, which is the KendallsPreShapeSpace manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#Manifolds.horizontal_component-Tuple{KendallsShapeSpace, Any, Any}","page":"Shape spaces","title":"Manifolds.horizontal_component","text":"horizontal_component(::KendallsShapeSpace, p, X)\n\nCompute the horizontal component of tangent vector X at p on KendallsShapeSpace M. See [Guigui2021], Section 2.3 for details.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#ManifoldsBase.get_embedding-Union{Tuple{KendallsShapeSpace{N, K}}, Tuple{K}, Tuple{N}} where {N, K}","page":"Shape spaces","title":"ManifoldsBase.get_embedding","text":"get_embedding(M::KendallsShapeSpace)\n\nGet the manifold in which KendallsShapeSpace M is embedded, i.e. KendallsPreShapeSpace of matrices of the same shape.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#ManifoldsBase.is_flat-Tuple{KendallsShapeSpace}","page":"Shape spaces","title":"ManifoldsBase.is_flat","text":"is_flat(::KendallsShapeSpace)\n\nReturn false. KendallsShapeSpace is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/shapespace.html#ManifoldsBase.manifold_dimension-Union{Tuple{KendallsShapeSpace{n, k}}, Tuple{k}, Tuple{n}} where {n, k}","page":"Shape spaces","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::KendallsShapeSpace)\n\nReturn the dimension of the KendallsShapeSpace manifold M. The dimension is given by n(k - 1) - 1 - n(n - 1)2 in the typical case where k geq n+1, and (k + 1)(k - 2) 2 otherwise, unless k is equal to 1, in which case the dimension is 0. See [Kendall1984] for a discussion of the over-dimensioned case.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/graph.html#Graph-manifold","page":"Graph manifold","title":"Graph manifold","text":"","category":"section"},{"location":"manifolds/graph.html","page":"Graph manifold","title":"Graph manifold","text":"For a given graph G(VE) implemented using Graphs.jl, the GraphManifold models a PowerManifold either on the nodes or edges of the graph, depending on the GraphManifoldType. i.e., it's either a mathcal M^lvert V rvert for the case of a vertex manifold or a mathcal M^lvert E rvert for the case of a edge manifold.","category":"page"},{"location":"manifolds/graph.html#Example","page":"Graph manifold","title":"Example","text":"","category":"section"},{"location":"manifolds/graph.html","page":"Graph manifold","title":"Graph manifold","text":"To make a graph manifold over ℝ^2 with three vertices and two edges, one can use","category":"page"},{"location":"manifolds/graph.html","page":"Graph manifold","title":"Graph manifold","text":"using Manifolds\nusing Graphs\nM = Euclidean(2)\np = [[1., 4.], [2., 5.], [3., 6.]]\nq = [[4., 5.], [6., 7.], [8., 9.]]\nx = [[6., 5.], [4., 3.], [2., 8.]]\nG = SimpleGraph(3)\nadd_edge!(G, 1, 2)\nadd_edge!(G, 2, 3)\nN = GraphManifold(G, M, VertexManifold())","category":"page"},{"location":"manifolds/graph.html","page":"Graph manifold","title":"Graph manifold","text":"It supports all AbstractPowerManifold operations (it is based on NestedPowerRepresentation) and furthermore it is possible to compute a graph logarithm:","category":"page"},{"location":"manifolds/graph.html","page":"Graph manifold","title":"Graph manifold","text":"using Manifolds\nusing Graphs\nM = Euclidean(2)\np = [[1., 4.], [2., 5.], [3., 6.]]\nq = [[4., 5.], [6., 7.], [8., 9.]]\nx = [[6., 5.], [4., 3.], [2., 8.]]\nG = SimpleGraph(3)\nadd_edge!(G, 1, 2)\nadd_edge!(G, 2, 3)\nN = GraphManifold(G, M, VertexManifold())","category":"page"},{"location":"manifolds/graph.html","page":"Graph manifold","title":"Graph manifold","text":"incident_log(N, p)","category":"page"},{"location":"manifolds/graph.html#Types-and-functions","page":"Graph manifold","title":"Types and functions","text":"","category":"section"},{"location":"manifolds/graph.html","page":"Graph manifold","title":"Graph manifold","text":"Modules = [Manifolds]\nPages = [\"manifolds/GraphManifold.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/graph.html#Manifolds.EdgeManifold","page":"Graph manifold","title":"Manifolds.EdgeManifold","text":"EdgeManifoldManifold <: GraphManifoldType\n\nA type for a GraphManifold where the data is given on the edges.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/graph.html#Manifolds.GraphManifold","page":"Graph manifold","title":"Manifolds.GraphManifold","text":"GraphManifold{G,𝔽,M,T} <: AbstractPowerManifold{𝔽,M,NestedPowerRepresentation}\n\nBuild a manifold, that is a PowerManifold of the AbstractManifold M either on the edges or vertices of a graph G depending on the GraphManifoldType T.\n\nFields\n\nG is an AbstractSimpleGraph\nM is a AbstractManifold\n\n\n\n\n\n","category":"type"},{"location":"manifolds/graph.html#Manifolds.GraphManifoldType","page":"Graph manifold","title":"Manifolds.GraphManifoldType","text":"GraphManifoldType\n\nThis type represents the type of data on the graph that the GraphManifold represents.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/graph.html#Manifolds.VertexManifold","page":"Graph manifold","title":"Manifolds.VertexManifold","text":"VectexGraphManifold <: GraphManifoldType\n\nA type for a GraphManifold where the data is given on the vertices.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/graph.html#Manifolds.incident_log-Tuple{GraphManifold{<:Graphs.AbstractGraph, 𝔽, <:AbstractManifold{𝔽}, VertexManifold} where 𝔽, Any}","page":"Graph manifold","title":"Manifolds.incident_log","text":"incident_log(M::GraphManifold, x)\n\nReturn the tangent vector on the (vertex) GraphManifold, where at each node the sum of the logs to incident nodes is computed. For a SimpleGraph, an egde is interpreted as double edge in the corresponding SimpleDiGraph\n\nIf the internal graph is a SimpleWeightedGraph the weighted sum of the tangent vectors is computed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/graph.html#ManifoldsBase.check_point-Tuple{GraphManifold, Vararg{Any}}","page":"Graph manifold","title":"ManifoldsBase.check_point","text":"check_point(M::GraphManifold, p)\n\nCheck whether p is a valid point on the GraphManifold, i.e. its length equals the number of vertices (for VertexManifolds) or the number of edges (for EdgeManifolds) and that each element of p passes the check_point test for the base manifold M.manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/graph.html#ManifoldsBase.check_vector-Tuple{GraphManifold, Vararg{Any}}","page":"Graph manifold","title":"ManifoldsBase.check_vector","text":"check_vector(M::GraphManifold, p, X; kwargs...)\n\nCheck whether p is a valid point on the GraphManifold, and X it from its tangent space, i.e. its length equals the number of vertices (for VertexManifolds) or the number of edges (for EdgeManifolds) and that each element of X together with its corresponding entry of p passes the check_vector test for the base manifold M.manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/graph.html#ManifoldsBase.manifold_dimension-Tuple{GraphManifold{<:Graphs.AbstractGraph, 𝔽, <:AbstractManifold{𝔽}, EdgeManifold} where 𝔽}","page":"Graph manifold","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(N::GraphManifold{G,𝔽,M,EdgeManifold})\n\nreturns the manifold dimension of the GraphManifold N on the edges of a graph G=(VE), i.e.\n\ndim(mathcal N) = lvert E rvert dim(mathcal M)\n\nwhere mathcal M is the manifold of the data on the edges.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/graph.html#ManifoldsBase.manifold_dimension-Tuple{GraphManifold{<:Graphs.AbstractGraph, 𝔽, <:AbstractManifold{𝔽}, VertexManifold} where 𝔽}","page":"Graph manifold","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(N::GraphManifold{G,𝔽,M,VertexManifold})\n\nreturns the manifold dimension of the GraphManifold N on the vertices of a graph G=(VE), i.e.\n\ndim(mathcal N) = lvert V rvert dim(mathcal M)\n\nwhere mathcal M is the manifold of the data on the nodes.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#EuclideanSection","page":"Euclidean","title":"Euclidean space","text":"","category":"section"},{"location":"manifolds/euclidean.html","page":"Euclidean","title":"Euclidean","text":"The Euclidean space ℝ^n is a simple model space, since it has curvature constantly zero everywhere; hence, nearly all operations simplify. The easiest way to generate an Euclidean space is to use a field, i.e. AbstractNumbers, e.g. to create the ℝ^n or ℝ^ntimes n you can simply type M = ℝ^n or ℝ^(n,n), respectively.","category":"page"},{"location":"manifolds/euclidean.html","page":"Euclidean","title":"Euclidean","text":"Modules = [Manifolds]\nPages = [\"manifolds/Euclidean.jl\"]\nOrder = [:type,:function]","category":"page"},{"location":"manifolds/euclidean.html#Manifolds.Euclidean","page":"Euclidean","title":"Manifolds.Euclidean","text":"Euclidean{T<:Tuple,𝔽} <: AbstractManifold{𝔽}\n\nEuclidean vector space.\n\nConstructor\n\nEuclidean(n)\n\nGenerate the n-dimensional vector space ℝ^n.\n\nEuclidean(n₁,n₂,...,nᵢ; field=ℝ)\n𝔽^(n₁,n₂,...,nᵢ) = Euclidean(n₁,n₂,...,nᵢ; field=𝔽)\n\nGenerate the vector space of k = n_1 cdot n_2 cdot cdot n_i values, i.e. the manifold 𝔽^n_1 n_2 n_i, 𝔽inℝℂ, whose elements are interpreted as n_1 n_2 n_i arrays. For i=2 we obtain a matrix space. The default field=ℝ can also be set to field=ℂ. The dimension of this space is k dim_ℝ 𝔽, where dim_ℝ 𝔽 is the real_dimension of the field 𝔽.\n\nEuclidean(; field=ℝ)\n\nGenerate the 1D Euclidean manifold for an ℝ-, ℂ-valued real- or complex-valued immutable values (in contrast to 1-element arrays from the constructor above).\n\n\n\n\n\n","category":"type"},{"location":"manifolds/euclidean.html#Base.exp-Tuple{Euclidean, Any, Any}","page":"Euclidean","title":"Base.exp","text":"exp(M::Euclidean, p, X)\n\nCompute the exponential map on the Euclidean manifold M from p in direction X, which in this case is just\n\nexp_p X = p + X\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#Base.log-Tuple{Euclidean, Vararg{Any}}","page":"Euclidean","title":"Base.log","text":"log(M::Euclidean, p, q)\n\nCompute the logarithmic map on the Euclidean M from p to q, which in this case is just\n\nlog_p q = q-p\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#LinearAlgebra.norm-Tuple{Euclidean, Any, Any}","page":"Euclidean","title":"LinearAlgebra.norm","text":"norm(M::Euclidean, p, X)\n\nCompute the norm of a tangent vector X at p on the Euclidean M, i.e. since every tangent space can be identified with M itself in this case, just the (Frobenius) norm of X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.distance-Tuple{Euclidean, Any, Any}","page":"Euclidean","title":"ManifoldsBase.distance","text":"distance(M::Euclidean, p, q)\n\nCompute the Euclidean distance between two points on the Euclidean manifold M, i.e. for vectors it's just the norm of the difference, for matrices and higher order arrays, the matrix and ternsor Frobenius norm, respectively.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.embed-Tuple{Euclidean, Any, Any}","page":"Euclidean","title":"ManifoldsBase.embed","text":"embed(M::Euclidean, p, X)\n\nEmbed the tangent vector X at point p in M. Equivalent to an identity map.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.embed-Tuple{Euclidean, Any}","page":"Euclidean","title":"ManifoldsBase.embed","text":"embed(M::Euclidean, p)\n\nEmbed the point p in M. Equivalent to an identity map.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.injectivity_radius-Tuple{Euclidean}","page":"Euclidean","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::Euclidean)\n\nReturn the injectivity radius on the Euclidean M, which is .\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.inner-Tuple{Euclidean, Vararg{Any}}","page":"Euclidean","title":"ManifoldsBase.inner","text":"inner(M::Euclidean, p, X, Y)\n\nCompute the inner product on the Euclidean M, which is just the inner product on the real-valued or complex valued vector space of arrays (or tensors) of size n_1 n_2 n_i, i.e.\n\ng_p(XY) = sum_k I overlineX_k Y_k\n\nwhere I is the set of vectors k ℕ^i, such that for all\n\ni j i it holds 1 k_j n_j and overlinecdot denotes the complex conjugate.\n\nFor the special case of i 2, i.e. matrices and vectors, this simplifies to\n\ng_p(XY) = X^mathrmHY\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.is_flat-Tuple{Euclidean}","page":"Euclidean","title":"ManifoldsBase.is_flat","text":"is_flat(::Euclidean)\n\nReturn true. Euclidean is a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.manifold_dimension-Union{Tuple{Euclidean{N, 𝔽}}, Tuple{𝔽}, Tuple{N}} where {N, 𝔽}","page":"Euclidean","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::Euclidean)\n\nReturn the manifold dimension of the Euclidean M, i.e. the product of all array dimensions and the real_dimension of the underlying number system.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.parallel_transport_along-Tuple{Euclidean, Any, Any, AbstractVector}","page":"Euclidean","title":"ManifoldsBase.parallel_transport_along","text":"parallel_transport_along(M::Euclidean, p, X, c)\n\nthe parallel transport on Euclidean is the identiy, i.e. returns X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.parallel_transport_direction-Tuple{Euclidean, Any, Any, Any}","page":"Euclidean","title":"ManifoldsBase.parallel_transport_direction","text":"parallel_transport_direction(M::Euclidean, p, X, d)\n\nthe parallel transport on Euclidean is the identiy, i.e. returns X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.parallel_transport_to-Tuple{Euclidean, Any, Any, Any}","page":"Euclidean","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::Euclidean, p, X, q)\n\nthe parallel transport on Euclidean is the identiy, i.e. returns X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.project-Tuple{Euclidean, Any, Any}","page":"Euclidean","title":"ManifoldsBase.project","text":"project(M::Euclidean, p, X)\n\nProject an arbitrary vector X into the tangent space of a point p on the Euclidean M, which is just the identity, since any tangent space of M can be identified with all of M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.project-Tuple{Euclidean, Any}","page":"Euclidean","title":"ManifoldsBase.project","text":"project(M::Euclidean, p)\n\nProject an arbitrary point p onto the Euclidean manifold M, which is of course just the identity map.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.representation_size-Union{Tuple{Euclidean{N}}, Tuple{N}} where N","page":"Euclidean","title":"ManifoldsBase.representation_size","text":"representation_size(M::Euclidean)\n\nReturn the array dimensions required to represent an element on the Euclidean M, i.e. the vector of all array dimensions.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.riemann_tensor-Tuple{Euclidean, Vararg{Any, 4}}","page":"Euclidean","title":"ManifoldsBase.riemann_tensor","text":"riemann_tensor(M::Euclidean, p, X, Y, Z)\n\nCompute the Riemann tensor R(XY)Z at point p on Euclidean manifold M. Its value is always the zero tangent vector. ````\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.vector_transport_to-Tuple{Euclidean, Any, Any, Any, AbstractVectorTransportMethod}","page":"Euclidean","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::Euclidean, p, X, q, ::AbstractVectorTransportMethod)\n\nTransport the vector X from the tangent space at p to the tangent space at q on the Euclidean M, which simplifies to the identity.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/euclidean.html#ManifoldsBase.zero_vector-Tuple{Euclidean, Vararg{Any}}","page":"Euclidean","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::Euclidean, x)\n\nReturn the zero vector in the tangent space of x on the Euclidean M, which here is just a zero filled array the same size as x.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialsymmetric.html#Multinomial-symmetric-matrices","page":"Multinomial symmetric matrices","title":"Multinomial symmetric matrices","text":"","category":"section"},{"location":"manifolds/multinomialsymmetric.html","page":"Multinomial symmetric matrices","title":"Multinomial symmetric matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/MultinomialSymmetric.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/multinomialsymmetric.html#Manifolds.MultinomialSymmetric","page":"Multinomial symmetric matrices","title":"Manifolds.MultinomialSymmetric","text":"MultinomialSymmetric{n} <: AbstractMultinomialDoublyStochastic{N}\n\nThe multinomial symmetric matrices manifold consists of all symmetric nn matrices with positive entries such that each column sums to one, i.e.\n\nbeginaligned\nmathcalSP(n) coloneqq biglp ℝ^nn big p_ij 0 text for all i=1n j=1m\n p^mathrmT = p\n pmathbf1_n = mathbf1_n\nbigr\nendaligned\n\nwhere mathbf1_n is the vector of length n containing ones.\n\nIt is modeled as IsIsometricEmbeddedManifold. via the AbstractMultinomialDoublyStochastic type, since it shares a few functions also with AbstractMultinomialDoublyStochastic, most and foremost projection of a point from the embedding onto the manifold.\n\nThe tangent space can be written as\n\nT_pmathcalSP(n) coloneqq bigl\nX ℝ^nn big X = X^mathrmT text and \nXmathbf1_n = mathbf0_n\nbigr\n\nwhere mathbf0_n is the vector of length n containing zeros.\n\nMore details can be found in Section IV[DouikHassibi2019].\n\nConstructor\n\nMultinomialSymmetric(n)\n\nGenerate the manifold of matrices mathbb R^nn that are doubly stochastic and symmetric.\n\n[DouikHassibi2019]: A. Douik, B. Hassibi: AbstractManifold Optimization Over the Set of Doubly Stochastic Matrices: A Second-Order Geometry, IEEE Transactions on Signal Processing 67(22), pp. 5761–5774, 2019. doi: 10.1109/tsp.2019.2946024, arXiv: 1802.02628.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/multinomialsymmetric.html#ManifoldsBase.check_point-Union{Tuple{n}, Tuple{MultinomialSymmetric{n}, Any}} where n","page":"Multinomial symmetric matrices","title":"ManifoldsBase.check_point","text":"check_point(M::MultinomialSymmetric, p)\n\nChecks whether p is a valid point on the MultinomialSymmetric(m,n) M, i.e. is a symmetric matrix with positive entries whose rows sum to one.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialsymmetric.html#ManifoldsBase.check_vector-Union{Tuple{n}, Tuple{MultinomialSymmetric{n}, Any, Any}} where n","page":"Multinomial symmetric matrices","title":"ManifoldsBase.check_vector","text":"check_vector(M::MultinomialSymmetric p, X; kwargs...)\n\nChecks whether X is a valid tangent vector to p on the MultinomialSymmetric M. This means, that p is valid, that X is of correct dimension, symmetric, and sums to zero along any row.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialsymmetric.html#ManifoldsBase.is_flat-Tuple{MultinomialSymmetric}","page":"Multinomial symmetric matrices","title":"ManifoldsBase.is_flat","text":"is_flat(::MultinomialSymmetric)\n\nReturn false. MultinomialSymmetric is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialsymmetric.html#ManifoldsBase.manifold_dimension-Union{Tuple{MultinomialSymmetric{n}}, Tuple{n}} where n","page":"Multinomial symmetric matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::MultinomialSymmetric{n}) where {n}\n\nreturns the dimension of the MultinomialSymmetric manifold namely\n\noperatornamedim_mathcalSP(n) = fracn(n-1)2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialsymmetric.html#ManifoldsBase.project-Tuple{MultinomialSymmetric, Any, Any}","page":"Multinomial symmetric matrices","title":"ManifoldsBase.project","text":"project(M::MultinomialSymmetric{n}, p, Y) where {n}\n\nProject Y onto the tangent space at p on the MultinomialSymmetric M, return the result in X. The formula reads\n\n operatornameproj_p(Y) = Y - (αmathbf1_n^mathrmT + mathbf1_n α^mathrmT) p\n\nwhere denotes the Hadamard or elementwise product and mathbb1_n is the vector of length n containing ones. The two vector α ℝ^nn is given by solving\n\n (I_n+p)α = Ymathbf1\n\nwhere I_n is teh nn unit matrix and mathbf1_n is the vector of length n containing ones.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialsymmetric.html#ManifoldsBase.retract-Tuple{MultinomialSymmetric, Any, Any, ProjectionRetraction}","page":"Multinomial symmetric matrices","title":"ManifoldsBase.retract","text":"retract(M::MultinomialSymmetric, p, X, ::ProjectionRetraction)\n\ncompute a projection based retraction by projecting podotexp(Xp) back onto the manifold, where are elementwise multiplication and division, respectively. Similarly, exp refers to the elementwise exponentiation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomialsymmetric.html#Literature","page":"Multinomial symmetric matrices","title":"Literature","text":"","category":"section"},{"location":"manifolds/quotient.html#QuotientManifoldSection","page":"Quotient manifold","title":"Quotient manifold","text":"","category":"section"},{"location":"manifolds/quotient.html","page":"Quotient manifold","title":"Quotient manifold","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/QuotientManifold.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/quotient.html#Manifolds.IsQuotientManifold","page":"Quotient manifold","title":"Manifolds.IsQuotientManifold","text":"IsQuotientManifold <: AbstractTrait\n\nSpecify that a certain decorated manifold is a quotient manifold in the sense that it provides implicitly (or explicitly through QuotientManifold properties of a quotient manifold.\n\nSee QuotientManifold for more details.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/quotient.html#Manifolds.QuotientManifold","page":"Quotient manifold","title":"Manifolds.QuotientManifold","text":"QuotientManifold{M <: AbstractManifold{𝔽}, N} <: AbstractManifold{𝔽}\n\nEquip a manifold mathcal M explicitly with the property of being a quotient manifold.\n\nA manifold mathcal M is then a a quotient manifold of another manifold mathcal N, i.e. for an equivalence relation on mathcal N we have\n\n mathcal M = mathcal N = bigl p p mathcal N bigr\n\nwhere p q mathcal N q p denotes the equivalence class containing p. For more details see Subsection 3.4.1[AbsilMahonySepulchre2008].\n\nThis manifold type models an explicit quotient structure. This should be done if either the default implementation of mathcal M uses another representation different from the quotient structure or if it provides a (default) quotient structure that is different from the one introduced here.\n\nFields\n\nmanifold – the manifold mathcal M in the introduction above.\ntotal_space – the manifold mathcal N in the introduction above.\n\nConstructor\n\nQuotientManifold(M,N)\n\nCreate a manifold where M is the quotient manifold and Nis its total space.\n\n[AbsilMahonySepulchre2008]: Absil, P.-A., Mahony, R. and Sepulchre R., Optimization Algorithms on Matrix Manifolds Princeton University Press, 2008, doi: 10.1515/9781400830244 open access\n\n\n\n\n\n","category":"type"},{"location":"manifolds/quotient.html#Provided-functions","page":"Quotient manifold","title":"Provided functions","text":"","category":"section"},{"location":"manifolds/quotient.html","page":"Quotient manifold","title":"Quotient manifold","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/QuotientManifold.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/quotient.html#Manifolds.canonical_project!-Tuple{AbstractManifold, Any, Any}","page":"Quotient manifold","title":"Manifolds.canonical_project!","text":"canonical_project!(M, q, p)\n\nCompute the canonical projection π on a manifold mathcal M that IsQuotientManifold, e.g. a QuotientManifold in place of q.\n\nSee canonical_project for more details.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/quotient.html#Manifolds.canonical_project-Tuple{AbstractManifold, Any}","page":"Quotient manifold","title":"Manifolds.canonical_project","text":"canonical_project(M, p)\n\nCompute the canonical projection π on a manifold mathcal M that IsQuotientManifold, e.g. a QuotientManifold. The canonical (or natural) projection π from the total space mathcal N onto mathcal M given by\n\n π = π_mathcal N mathcal M mathcal N mathcal M p π_mathcal N mathcal M(p) = p\n\nin other words, this function implicitly assumes, that the total space mathcal N is given, for example explicitly when M is a QuotientManifold and p is a point on N.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/quotient.html#Manifolds.differential_canonical_project!-Tuple{AbstractManifold, Any, Any}","page":"Quotient manifold","title":"Manifolds.differential_canonical_project!","text":"differential_canonical_project!(M, Y, p, X)\n\nCompute the differential of the canonical projection π on a manifold mathcal M that IsQuotientManifold, e.g. a QuotientManifold. See differential_canonical_project for details.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/quotient.html#Manifolds.differential_canonical_project-Tuple{AbstractManifold, Any, Any}","page":"Quotient manifold","title":"Manifolds.differential_canonical_project","text":"differential_canonical_project(M, p, X)\n\nCompute the differential of the canonical projection π on a manifold mathcal M that IsQuotientManifold, e.g. a QuotientManifold. The canonical (or natural) projection π from the total space mathcal N onto mathcal M, such that its differential\n\n Dπ(p) T_pmathcal N T_π(p)mathcal M\n\nwhere again the total space might be implicitly assumed, or explicitly when using a QuotientManifold M. So here p is a point on N and X is from T_pmathcal N.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/quotient.html#Manifolds.get_orbit_action-Tuple{AbstractManifold}","page":"Quotient manifold","title":"Manifolds.get_orbit_action","text":"get_orbit_action(M::AbstractDecoratorManifold)\n\nReturn the group action that generates the orbit of an equivalence class of the quotient manifold M for which equivalence classes are orbits of an action of a Lie group. For the case that\n\nmathcal M = mathcal N mathcal O\n\nwhere mathcal O is a Lie group with its group action generating the orbit.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/quotient.html#Manifolds.get_total_space-Tuple{AbstractManifold}","page":"Quotient manifold","title":"Manifolds.get_total_space","text":"get_total_space(M::AbstractDecoratorManifold)\n\nReturn the total space of a manifold that IsQuotientManifold, e.g. a QuotientManifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/quotient.html#Manifolds.horizontal_component-Tuple{AbstractManifold, Any, Any}","page":"Quotient manifold","title":"Manifolds.horizontal_component","text":"horizontal_component(N::AbstractManifold, p, X)\n\nCompute the horizontal component of tangent vector X at point p in the total space of quotient manifold N.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/quotient.html#Manifolds.horizontal_lift!-Tuple{AbstractManifold, Any, Any, Any}","page":"Quotient manifold","title":"Manifolds.horizontal_lift!","text":"horizontal_lift!(N, Y, q, X)\nhorizontal_lift!(QuotientManifold{M,N}, Y, p, X)\n\nCompute the horizontal_lift of X from T_pmathcal M, p=π(q). to `T_q\\mathcal N in place of Y.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/quotient.html#Manifolds.horizontal_lift-Tuple{AbstractManifold, Any, Any}","page":"Quotient manifold","title":"Manifolds.horizontal_lift","text":"horizontal_lift(N::AbstractManifold, q, X)\nhorizontal_lift(::QuotientManifold{𝔽,MT<:AbstractManifold{𝔽},NT<:AbstractManifold}, p, X) where {𝔽}\n\nGiven a point q in total space of quotient manifold N such that p=π(q) is a point on a quotient manifold M (implicitly given for the first case) and a tangent vector X this method computes a tangent vector Y on the horizontal space of T_qmathcal N, i.e. the subspace that is orthogonal to the kernel of Dπ(q).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/quotient.html#Manifolds.vertical_component-Tuple{AbstractManifold, Any, Any}","page":"Quotient manifold","title":"Manifolds.vertical_component","text":"vertical_component(N::AbstractManifold, p, X)\n\nCompute the vertical component of tangent vector X at point p in the total space of quotient manifold N.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/centeredmatrices.html#Centered-matrices","page":"Centered matrices","title":"Centered matrices","text":"","category":"section"},{"location":"manifolds/centeredmatrices.html","page":"Centered matrices","title":"Centered matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/CenteredMatrices.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/centeredmatrices.html#Manifolds.CenteredMatrices","page":"Centered matrices","title":"Manifolds.CenteredMatrices","text":"CenteredMatrices{m,n,𝔽} <: AbstractDecoratorManifold{𝔽}\n\nThe manifold of m n real-valued or complex-valued matrices whose columns sum to zero, i.e.\n\nbigl p 𝔽^m n big 1 1 * p = 0 0 bigr\n\nwhere 𝔽 ℝℂ.\n\nConstructor\n\nCenteredMatrices(m, n[, field=ℝ])\n\nGenerate the manifold of m-by-n (field-valued) matrices whose columns sum to zero.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/centeredmatrices.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{n}, Tuple{m}, Tuple{CenteredMatrices{m, n, 𝔽}, Any}} where {m, n, 𝔽}","page":"Centered matrices","title":"ManifoldsBase.check_point","text":"check_point(M::CenteredMatrices{m,n,𝔽}, p; kwargs...)\n\nCheck whether the matrix is a valid point on the CenteredMatrices M, i.e. is an m-by-n matrix whose columns sum to zero.\n\nThe tolerance for the column sums of p can be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/centeredmatrices.html#ManifoldsBase.check_vector-Union{Tuple{𝔽}, Tuple{n}, Tuple{m}, Tuple{CenteredMatrices{m, n, 𝔽}, Any, Any}} where {m, n, 𝔽}","page":"Centered matrices","title":"ManifoldsBase.check_vector","text":"check_vector(M::CenteredMatrices{m,n,𝔽}, p, X; kwargs... )\n\nCheck whether X is a tangent vector to manifold point p on the CenteredMatrices M, i.e. that X is a matrix of size (m, n) whose columns sum to zero and its values are from the correct AbstractNumbers. The tolerance for the column sums of p and X can be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/centeredmatrices.html#ManifoldsBase.is_flat-Tuple{CenteredMatrices}","page":"Centered matrices","title":"ManifoldsBase.is_flat","text":"is_flat(::CenteredMatrices)\n\nReturn true. CenteredMatrices is a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/centeredmatrices.html#ManifoldsBase.manifold_dimension-Union{Tuple{CenteredMatrices{m, n, 𝔽}}, Tuple{𝔽}, Tuple{n}, Tuple{m}} where {m, n, 𝔽}","page":"Centered matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::CenteredMatrices{m,n,𝔽})\n\nReturn the manifold dimension of the CenteredMatrices m-by-n matrix M over the number system 𝔽, i.e.\n\ndim(mathcal M) = (m*n - n) dim_ℝ 𝔽\n\nwhere dim_ℝ 𝔽 is the real_dimension of 𝔽.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/centeredmatrices.html#ManifoldsBase.project-Tuple{CenteredMatrices, Any, Any}","page":"Centered matrices","title":"ManifoldsBase.project","text":"project(M::CenteredMatrices, p, X)\n\nProject the matrix X onto the tangent space at p on the CenteredMatrices M, i.e.\n\noperatornameproj_p(X) = X - beginbmatrix\n1\n\n1\nendbmatrix * c_1 dots c_n\n\nwhere c_i = frac1msum_j=1^m x_ji for i = 1 dots n.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/centeredmatrices.html#ManifoldsBase.project-Tuple{CenteredMatrices, Any}","page":"Centered matrices","title":"ManifoldsBase.project","text":"project(M::CenteredMatrices, p)\n\nProjects p from the embedding onto the CenteredMatrices M, i.e.\n\noperatornameproj_mathcal M(p) = p - beginbmatrix\n1\n\n1\nendbmatrix * c_1 dots c_n\n\nwhere c_i = frac1msum_j=1^m p_ji for i = 1 dots n.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#GroupManifoldSection","page":"Group manifold","title":"Group manifolds and actions","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Lie groups, groups that are Riemannian manifolds with a smooth binary group operation AbstractGroupOperation, are implemented as AbstractDecoratorManifold and specifying the group operation using the IsGroupManifold or by decorating an existing manifold with a group operation using GroupManifold.","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"The common addition and multiplication group operations of AdditionOperation and MultiplicationOperation are provided, though their behavior may be customized for a specific group.","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"There are short introductions at the beginning of each subsection. They briefly mention what is available with links to more detailed descriptions.","category":"page"},{"location":"manifolds/group.html#Contents","page":"Group manifold","title":"Contents","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Pages = [\"group.md\"]\nDepth = 3","category":"page"},{"location":"manifolds/group.html#Groups","page":"Group manifold","title":"Groups","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"The following operations are available for group manifolds:","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Identity: an allocation-free representation of the identity element of the group.\ninv: get the inverse of a given element.\ncompose: compose two given elements of a group.\nidentity_element get the identity element of the group, in the representation used by other points from the group.","category":"page"},{"location":"manifolds/group.html#Group-manifold","page":"Group manifold","title":"Group manifold","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"GroupManifold adds a group structure to the wrapped manifold. It does not affect metric (or connection) structure of the wrapped manifold, however it can to be further wrapped in MetricManifold to get invariant metrics, or in a ConnectionManifold to equip it with a Cartan-Schouten connection.","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/group.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.AbstractGroupOperation","page":"Group manifold","title":"Manifolds.AbstractGroupOperation","text":"AbstractGroupOperation\n\nAbstract type for smooth binary operations on elements of a Lie group mathcalG:\n\n mathcalG mathcalG mathcalG\n\nAn operation can be either defined for a specific group manifold over number system 𝔽 or in general, by defining for an operation Op the following methods:\n\nidentity_element!(::AbstractDecoratorManifold, q, q)\ninv!(::AbstractDecoratorManifold, q, p)\n_compose!(::AbstractDecoratorManifold, x, p, q)\n\nNote that a manifold is connected with an operation by wrapping it with a decorator, AbstractDecoratorManifold using the IsGroupManifold to specify the operation. For a concrete case the concrete wrapper GroupManifold can be used.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.AbstractInvarianceTrait","page":"Group manifold","title":"Manifolds.AbstractInvarianceTrait","text":"AbstractInvarianceTrait <: AbstractTrait\n\nA common supertype for anz AbstractTrait related to metric invariance\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.ActionDirection","page":"Group manifold","title":"Manifolds.ActionDirection","text":"ActionDirection\n\nDirection of action on a manifold, either LeftForwardAction, LeftBackwardAction, RightForwardAction or RightBackwardAction.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.ForwardBackwardSwitch","page":"Group manifold","title":"Manifolds.ForwardBackwardSwitch","text":"struct ForwardBackwardSwitch <: AbstractDirectionSwitchType end\n\nSwitch between forward and backward action, maintaining left/right direction.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.GroupExponentialRetraction","page":"Group manifold","title":"Manifolds.GroupExponentialRetraction","text":"GroupExponentialRetraction{D<:ActionDirection} <: AbstractRetractionMethod\n\nRetraction using the group exponential exp_lie \"translated\" to any point on the manifold.\n\nFor more details, see retract.\n\nConstructor\n\nGroupExponentialRetraction(conv::ActionDirection = LeftForwardAction())\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.GroupLogarithmicInverseRetraction","page":"Group manifold","title":"Manifolds.GroupLogarithmicInverseRetraction","text":"GroupLogarithmicInverseRetraction{D<:ActionDirection} <: AbstractInverseRetractionMethod\n\nRetraction using the group logarithm log_lie \"translated\" to any point on the manifold.\n\nFor more details, see inverse_retract.\n\nConstructor\n\nGroupLogarithmicInverseRetraction(conv::ActionDirection = LeftForwardAction())\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.HasBiinvariantMetric","page":"Group manifold","title":"Manifolds.HasBiinvariantMetric","text":"HasBiinvariantMetric <: AbstractInvarianceTrait\n\nSpecify that a certain the metric of a GroupManifold is a bi-invariant metric\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.HasLeftInvariantMetric","page":"Group manifold","title":"Manifolds.HasLeftInvariantMetric","text":"HasLeftInvariantMetric <: AbstractInvarianceTrait\n\nSpecify that a certain the metric of a GroupManifold is a left-invariant metric\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.HasRightInvariantMetric","page":"Group manifold","title":"Manifolds.HasRightInvariantMetric","text":"HasRightInvariantMetric <: AbstractInvarianceTrait\n\nSpecify that a certain the metric of a GroupManifold is a right-invariant metric\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.Identity","page":"Group manifold","title":"Manifolds.Identity","text":"Identity{O<:AbstractGroupOperation}\n\nRepresent the group identity element e mathcalG on a Lie group mathcal G with AbstractGroupOperation of type O.\n\nSimilar to the philosophy that points are agnostic of their group at hand, the identity does not store the group g it belongs to. However it depends on the type of the AbstractGroupOperation used.\n\nSee also identity_element on how to obtain the corresponding AbstractManifoldPoint or array representation.\n\nConstructors\n\nIdentity(G::AbstractDecoratorManifold{𝔽})\nIdentity(o::O)\nIdentity(::Type{O})\n\ncreate the identity of the corresponding subtype O<:AbstractGroupOperation\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.IsGroupManifold","page":"Group manifold","title":"Manifolds.IsGroupManifold","text":"IsGroupManifold{O<:AbstractGroupOperation} <: AbstractTrait\n\nA trait to declare an AbstractManifold as a manifold with group structure with operation of type O.\n\nUsing this trait you can turn a manifold that you implement implictly into a Lie group. If you wish to decorate an existing manifold with one (or different) AbstractGroupActions, see GroupManifold.\n\nConstructor\n\nIsGroupManifold(op)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.LeftBackwardAction","page":"Group manifold","title":"Manifolds.LeftBackwardAction","text":"LeftBackwardAction()\n\nLeft action of a group on a manifold. For an action α X G X it is characterized by \n\nα(α(x h) g) = α(x gh)\n\nfor all g h G and x X.\n\nNote that a left action may still act from the right side in an expression.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.LeftForwardAction","page":"Group manifold","title":"Manifolds.LeftForwardAction","text":"LeftForwardAction()\n\nLeft action of a group on a manifold. For an action α G X X it is characterized by \n\nα(g α(h x)) = α(gh x)\n\nfor all g h G and x X.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.LeftRightSwitch","page":"Group manifold","title":"Manifolds.LeftRightSwitch","text":"struct LeftRightSwitch <: AbstractDirectionSwitchType end\n\nSwitch between left and right action, maintaining forward/backward direction.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.RightBackwardAction","page":"Group manifold","title":"Manifolds.RightBackwardAction","text":"RightBackwardAction()\n\nRight action of a group on a manifold. For an action α X G X it is characterized by \n\nα(α(x h) g) = α(x hg)\n\nfor all g h G and x X.\n\nNote that a right action may still act from the left side in an expression.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.RightForwardAction","page":"Group manifold","title":"Manifolds.RightForwardAction","text":"RightForwardAction()\n\nRight action of a group on a manifold. For an action α G X X it is characterized by \n\nα(g α(h x)) = α(hg x)\n\nfor all g h G and x X.\n\nNote that a right action may still act from the left side in an expression.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.SimultaneousSwitch","page":"Group manifold","title":"Manifolds.SimultaneousSwitch","text":"struct LeftRightSwitch <: AbstractDirectionSwitchType end\n\nSimultaneously switch left/right and forward/backward directions.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Base.inv-Tuple{AbstractDecoratorManifold, Vararg{Any}}","page":"Group manifold","title":"Base.inv","text":"inv(G::AbstractDecoratorManifold, p)\n\nInverse p^-1 mathcalG of an element p mathcalG, such that p circ p^-1 = p^-1 circ p = e mathcalG, where e is the Identity element of mathcalG.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.adjoint_action-Tuple{AbstractDecoratorManifold, Any, Any}","page":"Group manifold","title":"Manifolds.adjoint_action","text":"adjoint_action(G::AbstractDecoratorManifold, p, X)\n\nAdjoint action of the element p of the Lie group G on the element X of the corresponding Lie algebra.\n\nIt is defined as the differential of the group authomorphism Ψ_p(q) = pqp¹ at the identity of G.\n\nThe formula reads\n\noperatornameAd_p(X) = dΨ_p(e)X\n\nwhere e is the identity element of G.\n\nNote that the adjoint representation of a Lie group isn't generally faithful. Notably the adjoint representation of SO(2) is trivial.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.compose-Tuple{AbstractDecoratorManifold, Vararg{Any}}","page":"Group manifold","title":"Manifolds.compose","text":"compose(G::AbstractDecoratorManifold, p, q)\n\nCompose elements pq mathcalG using the group operation p circ q.\n\nFor implementing composition on a new group manifold, please overload _compose instead so that methods with Identity arguments are not ambiguous.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.exp_lie-Tuple{AbstractManifold, Any}","page":"Group manifold","title":"Manifolds.exp_lie","text":"exp_lie(G, X)\nexp_lie!(G, q, X)\n\nCompute the group exponential of the Lie algebra element X. It is equivalent to the exponential map defined by the CartanSchoutenMinus connection.\n\nGiven an element X 𝔤 = T_e mathcalG, where e is the Identity element of the group mathcalG, and 𝔤 is its Lie algebra, the group exponential is the map\n\nexp 𝔤 mathcalG\n\nsuch that for ts ℝ, γ(t) = exp (t X) defines a one-parameter subgroup with the following properties. Note that one-parameter subgroups are commutative (see [Suhubi2013], section 3.5), even if the Lie group itself is not commutative.\n\nbeginaligned\nγ(t) = γ(-t)^-1\nγ(t + s) = γ(t) circ γ(s) = γ(s) circ γ(t)\nγ(0) = e\nlim_t 0 fracddt γ(t) = X\nendaligned\n\nnote: Note\nIn general, the group exponential map is distinct from the Riemannian exponential map exp.\n\nFor example for the MultiplicationOperation and either Number or AbstractMatrix the Lie exponential is the numeric/matrix exponential.\n\nexp X = operatornameExp X = sum_n=0^ frac1n X^n\n\nSince this function also depends on the group operation, make sure to implement the corresponding trait version exp_lie(::TraitList{<:IsGroupManifold}, G, X).\n\n[Suhubi2013]: E. Suhubi, Exterior Analysis: Using Applications of Differential Forms, 1st edition. Amsterdam: Academic Press, 2013.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.get_coordinates_lie-Tuple{ManifoldsBase.TraitList{<:IsGroupManifold}, AbstractManifold, Any, AbstractBasis}","page":"Group manifold","title":"Manifolds.get_coordinates_lie","text":"get_coordinates_lie(G::AbstractManifold, X, B::AbstractBasis)\n\nGet the coordinates of an element X from the Lie algebra og G with respect to a basis B. This is similar to calling get_coordinates at the p=Identity(G).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.get_vector_lie-Tuple{ManifoldsBase.TraitList{<:IsGroupManifold}, AbstractManifold, Any, AbstractBasis}","page":"Group manifold","title":"Manifolds.get_vector_lie","text":"get_vector_lie(G::AbstractDecoratorManifold, a, B::AbstractBasis)\n\nReconstruct a tangent vector from the Lie algebra of G from cooordinates a of a basis B. This is similar to calling get_vector at the p=Identity(G).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.identity_element-Tuple{AbstractDecoratorManifold, Any}","page":"Group manifold","title":"Manifolds.identity_element","text":"identity_element(G::AbstractDecoratorManifold, p)\n\nReturn a point representation of the Identity on the IsGroupManifold G, where p indicates the type to represent the identity.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.identity_element-Tuple{AbstractDecoratorManifold}","page":"Group manifold","title":"Manifolds.identity_element","text":"identity_element(G)\n\nReturn a point representation of the Identity on the IsGroupManifold G. By default this representation is the default array or number representation. It should return the corresponding default representation of e as a point on G if points are not represented by arrays.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.inverse_translate-Tuple{AbstractDecoratorManifold, Vararg{Any}}","page":"Group manifold","title":"Manifolds.inverse_translate","text":"inverse_translate(G::AbstractDecoratorManifold, p, q, conv::ActionDirection=LeftForwardAction())\n\nInverse translate group element q by p with the inverse translation τ_p^-1 with the specified convention, either left (L_p^-1) or right (R_p^-1), defined as\n\nbeginaligned\nL_p^-1 q p^-1 circ q\nR_p^-1 q q circ p^-1\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.inverse_translate_diff-Tuple{AbstractDecoratorManifold, Vararg{Any}}","page":"Group manifold","title":"Manifolds.inverse_translate_diff","text":"inverse_translate_diff(G::AbstractDecoratorManifold, p, q, X, conv::ActionDirection=LeftForwardAction())\n\nFor group elements p q mathcalG and tangent vector X T_q mathcalG, compute the action on X of the differential of the inverse translation τ_p by p, with the specified left or right convention. The differential transports vectors:\n\n(mathrmdτ_p^-1)_q T_q mathcalG T_τ_p^-1 q mathcalG\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.is_group_manifold-Tuple{AbstractManifold, AbstractGroupOperation}","page":"Group manifold","title":"Manifolds.is_group_manifold","text":"is_group_manifold(G::GroupManifold)\nis_group_manifoldd(G::AbstractManifold, o::AbstractGroupOperation)\n\nreturns whether an AbstractDecoratorManifold is a group manifold with AbstractGroupOperation o. For a GroupManifold G this checks whether the right operations is stored within G.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.is_identity-Tuple{AbstractDecoratorManifold, Any}","page":"Group manifold","title":"Manifolds.is_identity","text":"is_identity(G::AbstractDecoratorManifold, q; kwargs)\n\nCheck whether q is the identity on the IsGroupManifold G, i.e. it is either the Identity{O} with the corresponding AbstractGroupOperation O, or (approximately) the correct point representation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.lie_bracket-Tuple{AbstractDecoratorManifold, Any, Any}","page":"Group manifold","title":"Manifolds.lie_bracket","text":"lie_bracket(G::AbstractDecoratorManifold, X, Y)\n\nLie bracket between elements X and Y of the Lie algebra corresponding to the Lie group G, cf. IsGroupManifold.\n\nThis can be used to compute the adjoint representation of a Lie algebra. Note that this representation isn't generally faithful. Notably the adjoint representation of 𝔰𝔬(2) is trivial.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.log_lie-Tuple{AbstractDecoratorManifold, Any}","page":"Group manifold","title":"Manifolds.log_lie","text":"log_lie(G, q)\nlog_lie!(G, X, q)\n\nCompute the Lie group logarithm of the Lie group element q. It is equivalent to the logarithmic map defined by the CartanSchoutenMinus connection.\n\nGiven an element q mathcalG, compute the right inverse of the group exponential map exp_lie, that is, the element log q = X 𝔤 = T_e mathcalG, such that q = exp X\n\nnote: Note\nIn general, the group logarithm map is distinct from the Riemannian logarithm map log.For matrix Lie groups this is equal to the (matrix) logarithm:\n\nlog q = operatornameLog q = sum_n=1^ frac(-1)^n+1n (q - e)^n\n\nwhere e here is the Identity element, that is, 1 for numeric q or the identity matrix I_m for matrix q ℝ^m m.\n\nSince this function also depends on the group operation, make sure to implement either\n\n_log_lie(G, q) and _log_lie!(G, X, q) for the points not being the Identity\nthe trait version log_lie(::TraitList{<:IsGroupManifold}, G, e), log_lie(::TraitList{<:IsGroupManifold}, G, X, e) for own implementations of the identity case.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.switch_direction-Tuple{ActionDirection, Manifolds.AbstractDirectionSwitchType}","page":"Group manifold","title":"Manifolds.switch_direction","text":"switch_direction(::ActionDirection, type::AbstractDirectionSwitchType = SimultaneousSwitch())\n\nReturns type of action between left and right, forward or backward, or both at the same type, depending on type, which is either of LeftRightSwitch, ForwardBackwardSwitch or SimultaneousSwitch.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.translate-Tuple{AbstractDecoratorManifold, Vararg{Any}}","page":"Group manifold","title":"Manifolds.translate","text":"translate(G::AbstractDecoratorManifold, p, q, conv::ActionDirection=LeftForwardAction()])\n\nTranslate group element q by p with the translation τ_p with the specified convention, either left forward (L_p), left backward (R_p), right backward (R_p) or right forward (L_p), defined as\n\nbeginaligned\nL_p q p circ q\nL_p q p^-1 circ q\nR_p q q circ p\nR_p q q circ p^-1\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.translate_diff-Tuple{AbstractDecoratorManifold, Vararg{Any}}","page":"Group manifold","title":"Manifolds.translate_diff","text":"translate_diff(G::AbstractDecoratorManifold, p, q, X, conv::ActionDirection=LeftForwardAction())\n\nFor group elements p q mathcalG and tangent vector X T_q mathcalG, compute the action of the differential of the translation τ_p by p on X, with the specified left or right convention. The differential transports vectors:\n\n(mathrmdτ_p)_q T_q mathcalG T_τ_p q mathcalG\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.hat-Union{Tuple{O}, Tuple{ManifoldsBase.TraitList{IsGroupManifold{O}}, AbstractDecoratorManifold, Identity{O}, Any}} where O<:AbstractGroupOperation","page":"Group manifold","title":"ManifoldsBase.hat","text":"hat(M::AbstractDecoratorManifold{𝔽,O}, ::Identity{O}, Xⁱ) where {𝔽,O<:AbstractGroupOperation}\n\nGiven a basis e_i on the tangent space at a the Identity and tangent component vector X^i, compute the equivalent vector representation ``X=X^i e_i**, where Einstein summation notation is used:\n\n X^i X^i e_i\n\nFor array manifolds, this converts a vector representation of the tangent vector to an array representation. The vee map is the hat map's inverse.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.inverse_retract-Tuple{ManifoldsBase.TraitList{<:IsGroupManifold}, AbstractDecoratorManifold, Any, Any, Manifolds.GroupLogarithmicInverseRetraction}","page":"Group manifold","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(\n G::AbstractDecoratorManifold,\n p,\n X,\n method::GroupLogarithmicInverseRetraction{<:ActionDirection},\n)\n\nCompute the inverse retraction using the group logarithm log_lie \"translated\" to any point on the manifold. With a group translation (translate) τ_p in a specified direction, the retraction is\n\noperatornameretr_p^-1 = (mathrmdτ_p)_e circ log circ τ_p^-1\n\nwhere log is the group logarithm (log_lie), and (mathrmdτ_p)_e is the action of the differential of translation τ_p evaluated at the identity element e (see translate_diff).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.retract-Tuple{ManifoldsBase.TraitList{<:IsGroupManifold}, AbstractDecoratorManifold, Any, Any, Manifolds.GroupExponentialRetraction}","page":"Group manifold","title":"ManifoldsBase.retract","text":"retract(\n G::AbstractDecoratorManifold,\n p,\n X,\n method::GroupExponentialRetraction{<:ActionDirection},\n)\n\nCompute the retraction using the group exponential exp_lie \"translated\" to any point on the manifold. With a group translation (translate) τ_p in a specified direction, the retraction is\n\noperatornameretr_p = τ_p circ exp circ (mathrmdτ_p^-1)_p\n\nwhere exp is the group exponential (exp_lie), and (mathrmdτ_p^-1)_p is the action of the differential of inverse translation τ_p^-1 evaluated at p (see inverse_translate_diff).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.vee-Union{Tuple{O}, Tuple{ManifoldsBase.TraitList{IsGroupManifold{O}}, AbstractDecoratorManifold, Identity{O}, Any}} where O<:AbstractGroupOperation","page":"Group manifold","title":"ManifoldsBase.vee","text":"vee(M::AbstractManifold, p, X)\n\nGiven a basis e_i on the tangent space at a point p and tangent vector X, compute the vector components X^i, such that X = X^i e_i, where Einstein summation notation is used:\n\nvee X^i e_i X^i\n\nFor array manifolds, this converts an array representation of the tangent vector to a vector representation. The hat map is the vee map's inverse.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#GroupManifold","page":"Group manifold","title":"GroupManifold","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"As a concrete wrapper for manifolds (e.g. when the manifold per se is a group manifold but another group structure should be implemented), there is the GroupManifold","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/GroupManifold.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.GroupManifold","page":"Group manifold","title":"Manifolds.GroupManifold","text":"GroupManifold{𝔽,M<:AbstractManifold{𝔽},O<:AbstractGroupOperation} <: AbstractDecoratorManifold{𝔽}\n\nDecorator for a smooth manifold that equips the manifold with a group operation, thus making it a Lie group. See IsGroupManifold for more details.\n\nGroup manifolds by default forward metric-related operations to the wrapped manifold.\n\nConstructor\n\nGroupManifold(manifold, op)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Generic-Operations","page":"Group manifold","title":"Generic Operations","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"For groups based on an addition operation or a group operation, several default implementations are provided.","category":"page"},{"location":"manifolds/group.html#Addition-Operation","page":"Group manifold","title":"Addition Operation","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/addition_operation.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.AdditionOperation","page":"Group manifold","title":"Manifolds.AdditionOperation","text":"AdditionOperation <: AbstractGroupOperation\n\nGroup operation that consists of simple addition.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Multiplication-Operation","page":"Group manifold","title":"Multiplication Operation","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/multiplication_operation.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.MultiplicationOperation","page":"Group manifold","title":"Manifolds.MultiplicationOperation","text":"MultiplicationOperation <: AbstractGroupOperation\n\nGroup operation that consists of multiplication.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Circle-group","page":"Group manifold","title":"Circle group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/circle_group.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.CircleGroup","page":"Group manifold","title":"Manifolds.CircleGroup","text":"CircleGroup <: GroupManifold{Circle{ℂ},MultiplicationOperation}\n\nThe circle group is the complex circle (Circle(ℂ)) equipped with the group operation of complex multiplication (MultiplicationOperation).\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.RealCircleGroup","page":"Group manifold","title":"Manifolds.RealCircleGroup","text":"RealCircleGroup <: GroupManifold{Circle{ℝ},AdditionOperation}\n\nThe real circle group is the real circle (Circle(ℝ)) equipped with the group operation of addition (AdditionOperation).\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#General-linear-group","page":"Group manifold","title":"General linear group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/general_linear.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.GeneralLinear","page":"Group manifold","title":"Manifolds.GeneralLinear","text":"GeneralLinear{n,𝔽} <:\n AbstractDecoratorManifold{𝔽}\n\nThe general linear group, that is, the group of all invertible matrices in 𝔽^nn.\n\nThe default metric is the left-mathrmGL(n)-right-mathrmO(n)-invariant metric whose inner product is\n\nX_pY_p_p = p^-1X_pp^-1Y_p_mathrmF = X_e Y_e_mathrmF\n\nwhere X_p Y_p T_p mathrmGL(n 𝔽), X_e = p^-1X_p 𝔤𝔩(n) = T_e mathrmGL(n 𝔽) = 𝔽^nn is the corresponding vector in the Lie algebra, and _mathrmF denotes the Frobenius inner product.\n\nBy default, tangent vectors X_p are represented with their corresponding Lie algebra vectors X_e = p^-1X_p.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Base.exp-Tuple{GeneralLinear, Any, Any}","page":"Group manifold","title":"Base.exp","text":"exp(G::GeneralLinear, p, X)\n\nCompute the exponential map on the GeneralLinear group.\n\nThe exponential map is\n\nexp_p colon X p operatornameExp(X^mathrmH) operatornameExp(X - X^mathrmH)\n\nwhere operatornameExp() denotes the matrix exponential, and ^mathrmH is the conjugate transpose. [AndruchowLarotondaRechtVarela2014][MartinNeff2016]\n\n[AndruchowLarotondaRechtVarela2014]: Andruchow E., Larotonda G., Recht L., and Varela A.: “The left invariant metric in the general linear group”, Journal of Geometry and Physics 86, pp. 241-257, 2014. doi: 10.1016/j.geomphys.2014.08.009, arXiv: 1109.0520v1.\n\n[MartinNeff2016]: Martin, R. J. and Neff, P.: “Minimal geodesics on GL(n) for left-invariant, right-O(n)-invariant Riemannian metrics”, Journal of Geometric Mechanics 8(3), pp. 323-357, 2016. doi: 10.3934/jgm.2016010, arXiv: 1409.7849v2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Base.log-Tuple{GeneralLinear, Any, Any}","page":"Group manifold","title":"Base.log","text":"log(G::GeneralLinear, p, q)\n\nCompute the logarithmic map on the GeneralLinear(n) group.\n\nThe algorithm proceeds in two stages. First, the point r = p^-1 q is projected to the nearest element (under the Frobenius norm) of the direct product subgroup mathrmO(n) S^+, whose logarithmic map is exactly computed using the matrix logarithm. This initial tangent vector is then refined using the NLSolveInverseRetraction.\n\nFor GeneralLinear(n, ℂ), the logarithmic map is instead computed on the realified supergroup GeneralLinear(2n) and the resulting tangent vector is then complexified.\n\nNote that this implementation is experimental.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Base.rand-Tuple{GeneralLinear}","page":"Group manifold","title":"Base.rand","text":"Random.rand(G::GeneralLinear; vector_at=nothing, kwargs...)\n\nIf vector_at is nothing, return a random point on the GeneralLinear group G by using rand in the embedding.\n\nIf vector_at is not nothing, return a random tangent vector from the tangent space of the point vector_at on the GeneralLinear by using by using rand in the embedding.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Heisenberg-group","page":"Group manifold","title":"Heisenberg group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/heisenberg.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.HeisenbergGroup","page":"Group manifold","title":"Manifolds.HeisenbergGroup","text":"HeisenbergGroup{n} <: AbstractDecoratorManifold{ℝ}\n\nHeisenberg group HeisenbergGroup(n) is the group of (n+2) (n+2) matrices [BinzPods2008]\n\nbeginbmatrix 1 mathbfa c \nmathbf0 I_n mathbfb \n0 mathbf0 1 endbmatrix\n\nwhere I_n is the nn unit matrix, mathbfa is a row vector of length n, mathbfb is a column vector of length n and c is a real number. The group operation is matrix multiplication.\n\nThe left-invariant metric on the manifold is used.\n\n[BinzPods2008]: E. Binz and S. Pods, The Geometry of Heisenberg Groups: With Applications in Signal Theory, Optics, Quantization, and Field Quantization. American Mathematical Soc., 2008.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Base.exp-Tuple{HeisenbergGroup, Any, Any}","page":"Group manifold","title":"Base.exp","text":"exp(M::HeisenbergGroup, p, X)\n\nExponential map on the HeisenbergGroup M with the left-invariant metric. The expression reads\n\nexp_beginbmatrix 1 mathbfa_p c_p \nmathbf0 I_n mathbfb_p \n0 mathbf0 1 endbmatrixleft(beginbmatrix 0 mathbfa_X c_X \nmathbf0 0_n mathbfb_X \n0 mathbf0 0 endbmatrixright) =\nbeginbmatrix 1 mathbfa_p + mathbfa_X c_p + c_X + mathbfa_Xmathbfb_X2 + mathbfa_pmathbfb_X \nmathbf0 I_n mathbfb_p + mathbfb_X \n0 mathbf0 1 endbmatrix\n\nwhere I_n is the nn identity matrix, 0_n is the nn zero matrix and mathbfamathbfb is dot product of vectors.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Base.log-Tuple{HeisenbergGroup, Any, Any}","page":"Group manifold","title":"Base.log","text":"log(G::HeisenbergGroup, p, q)\n\nCompute the logarithmic map on the HeisenbergGroup group. The formula reads\n\nlog_beginbmatrix 1 mathbfa_p c_p \nmathbf0 I_n mathbfb_p \n0 mathbf0 1 endbmatrixleft(beginbmatrix 1 mathbfa_q c_q \nmathbf0 I_n mathbfb_q \n0 mathbf0 1 endbmatrixright) =\nbeginbmatrix 0 mathbfa_q - mathbfa_p c_q - c_p + mathbfa_pmathbfb_p - mathbfa_qmathbfb_q - (mathbfa_q - mathbfa_p)(mathbfb_q - mathbfb_p) 2 \nmathbf0 0_n mathbfb_q - mathbfb_p \n0 mathbf0 0 endbmatrix\n\nwhere I_n is the nn identity matrix, 0_n is the nn zero matrix and mathbfamathbfb is dot product of vectors.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Base.rand-Tuple{HeisenbergGroup}","page":"Group manifold","title":"Base.rand","text":"Random.rand(M::HeisenbergGroup; vector_at = nothing, σ::Real=1.0)\n\nIf vector_at is nothing, return a random point on the HeisenbergGroup M by sampling elements of the first row and the last column from the normal distribution with mean 0 and standard deviation σ.\n\nIf vector_at is not nothing, return a random tangent vector from the tangent space of the point vector_at on the HeisenbergGroup by using a normal distribution with mean 0 and standard deviation σ.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.exp_lie-Tuple{HeisenbergGroup, Any}","page":"Group manifold","title":"Manifolds.exp_lie","text":"exp_lie(M::HeisenbergGroup, X)\n\nLie group exponential for the HeisenbergGroup M of the vector X. The formula reads\n\nexpleft(beginbmatrix 0 mathbfa c \nmathbf0 0_n mathbfb \n0 mathbf0 0 endbmatrixright) = beginbmatrix 1 mathbfa c + mathbfamathbfb2 \nmathbf0 I_n mathbfb \n0 mathbf0 1 endbmatrix\n\nwhere I_n is the nn identity matrix, 0_n is the nn zero matrix and mathbfamathbfb is dot product of vectors.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.log_lie-Tuple{HeisenbergGroup, Any}","page":"Group manifold","title":"Manifolds.log_lie","text":"log_lie(M::HeisenbergGroup, p)\n\nLie group logarithm for the HeisenbergGroup M of the point p. The formula reads\n\nlogleft(beginbmatrix 1 mathbfa c \nmathbf0 I_n mathbfb \n0 mathbf0 1 endbmatrixright) =\nbeginbmatrix 0 mathbfa c - mathbfamathbfb2 \nmathbf0 0_n mathbfb \n0 mathbf0 0 endbmatrix\n\nwhere I_n is the nn identity matrix, 0_n is the nn zero matrix and mathbfamathbfb is dot product of vectors.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.get_coordinates-Tuple{HeisenbergGroup, Any, Any, DefaultOrthonormalBasis{ℝ, ManifoldsBase.TangentSpaceType}}","page":"Group manifold","title":"ManifoldsBase.get_coordinates","text":"get_coordinates(M::HeisenbergGroup, p, X, ::DefaultOrthonormalBasis{ℝ,TangentSpaceType})\n\nGet coordinates of tangent vector X at point p from the HeisenbergGroup M. Given a matrix\n\nbeginbmatrix 1 mathbfa c \nmathbf0 I_n mathbfb \n0 mathbf0 1 endbmatrix\n\nthe coordinates are concatenated vectors mathbfa, mathbfb, and number c.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.get_vector-Tuple{HeisenbergGroup, Any, Any, DefaultOrthonormalBasis{ℝ, ManifoldsBase.TangentSpaceType}}","page":"Group manifold","title":"ManifoldsBase.get_vector","text":"get_vector(M::HeisenbergGroup, p, Xⁱ, ::DefaultOrthonormalBasis{ℝ,TangentSpaceType})\n\nGet tangent vector with coordinates Xⁱ at point p from the HeisenbergGroup M. Given a vector of coordinates beginbmatrixmathbba mathbbb cendbmatrix the tangent vector is equal to\n\nbeginbmatrix 1 mathbfa c \nmathbf0 I_n mathbfb \n0 mathbf0 1 endbmatrix\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.injectivity_radius-Tuple{HeisenbergGroup}","page":"Group manifold","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::HeisenbergGroup)\n\nReturn the injectivity radius on the HeisenbergGroup M, which is .\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.project-Union{Tuple{n}, Tuple{HeisenbergGroup{n}, Any, Any}} where n","page":"Group manifold","title":"ManifoldsBase.project","text":"project(M::HeisenbergGroup{n}, p, X)\n\nProject a matrix X in the Euclidean embedding onto the Lie algebra of HeisenbergGroup M. Sets the diagonal elements to 0 and all non-diagonal elements except the first row and the last column to 0.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.project-Union{Tuple{n}, Tuple{HeisenbergGroup{n}, Any}} where n","page":"Group manifold","title":"ManifoldsBase.project","text":"project(M::HeisenbergGroup{n}, p)\n\nProject a matrix p in the Euclidean embedding onto the HeisenbergGroup M. Sets the diagonal elements to 1 and all non-diagonal elements except the first row and the last column to 0.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#(Special)-Orthogonal-and-(Special)-Unitary-group","page":"Group manifold","title":"(Special) Orthogonal and (Special) Unitary group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Since the orthogonal, unitary and special orthogonal and special unitary groups share many common functions, these are also implemented on a common level.","category":"page"},{"location":"manifolds/group.html#Common-functions","page":"Group manifold","title":"Common functions","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/general_unitary_groups.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.GeneralUnitaryMultiplicationGroup","page":"Group manifold","title":"Manifolds.GeneralUnitaryMultiplicationGroup","text":"GeneralUnitaryMultiplicationGroup{n,𝔽,M} = GroupManifold{𝔽,M,MultiplicationOperation}\n\nA generic type for Lie groups based on a unitary property and matrix multiplcation, see e.g. Orthogonal, SpecialOrthogonal, Unitary, and SpecialUnitary\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.exp_lie-Tuple{Manifolds.GeneralUnitaryMultiplicationGroup{2, ℝ}, Any}","page":"Group manifold","title":"Manifolds.exp_lie","text":" exp_lie(G::Orthogonal{2}, X)\n exp_lie(G::SpecialOrthogonal{2}, X)\n\nCompute the Lie group exponential map on the Orthogonal(2) or SpecialOrthogonal(2) group. Given X = beginpmatrix 0 -θ θ 0 endpmatrix, the group exponential is\n\nexp_e colon X beginpmatrix cos θ -sin θ sin θ cos θ endpmatrix\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.exp_lie-Tuple{Manifolds.GeneralUnitaryMultiplicationGroup{4, ℝ}, Any}","page":"Group manifold","title":"Manifolds.exp_lie","text":" exp_lie(G::Orthogonal{4}, X)\n exp_lie(G::SpecialOrthogonal{4}, X)\n\nCompute the group exponential map on the Orthogonal(4) or the SpecialOrthogonal group. The algorithm used is a more numerically stable form of those proposed in [Gallier2002], [Andrica2013].\n\n[Gallier2002]: Gallier J.; Xu D.; Computing exponentials of skew-symmetric matrices and logarithms of orthogonal matrices. International Journal of Robotics and Automation (2002), 17(4), pp. 1-11. pdf.\n\n[Andrica2013]: Andrica D.; Rohan R.-A.; Computing the Rodrigues coefficients of the exponential map of the Lie groups of matrices. Balkan Journal of Geometry and Its Applications (2013), 18(2), pp. 1-2. pdf.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Orthogonal-group","page":"Group manifold","title":"Orthogonal group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/orthogonal.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.Orthogonal","page":"Group manifold","title":"Manifolds.Orthogonal","text":"Orthogonal{n} = GeneralUnitaryMultiplicationGroup{n,ℝ,AbsoluteDeterminantOneMatrices}\n\nOrthogonal group mathrmO(n) represented by OrthogonalMatrices.\n\nConstructor\n\nOrthogonal(n)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Special-orthogonal-group","page":"Group manifold","title":"Special orthogonal group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/special_orthogonal.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.SpecialOrthogonal","page":"Group manifold","title":"Manifolds.SpecialOrthogonal","text":"SpecialOrthogonal{n} <: GroupManifold{ℝ,Rotations{n},MultiplicationOperation}\n\nSpecial orthogonal group mathrmSO(n) represented by rotation matrices, see Rotations.\n\nConstructor\n\nSpecialOrthogonal(n)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Special-unitary-group","page":"Group manifold","title":"Special unitary group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/special_unitary.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.SpecialUnitary","page":"Group manifold","title":"Manifolds.SpecialUnitary","text":"SpecialUnitary{n} = GeneralUnitaryMultiplicationGroup{n,ℝ,GeneralUnitaryMatrices{n,ℂ,DeterminantOneMatrices}}\n\nThe special unitary group mathrmSU(n) represented by unitary matrices of determinant +1.\n\nThe tangent spaces are of the form\n\nT_pmathrmSU(x) = bigl X in mathbb C^nn big X = pY text where Y = -Y^mathrmH bigr\n\nand we represent tangent vectors by just storing the SkewHermitianMatrices Y, or in other words we represent the tangent spaces employing the Lie algebra mathfraksu(n).\n\nConstructor\n\nSpecialUnitary(n)\n\nGenerate the Lie group of nn unitary matrices with determinant +1.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#ManifoldsBase.project-Tuple{SpecialUnitary, Vararg{Any}}","page":"Group manifold","title":"ManifoldsBase.project","text":"project(G::SpecialUnitary, p)\n\nProject p to the nearest point on the SpecialUnitary group G.\n\nGiven the singular value decomposition p = U S V^mathrmH, with the singular values sorted in descending order, the projection is\n\noperatornameproj_mathrmSU(n)(p) =\nUoperatornamediagleft11det(U V^mathrmH)right V^mathrmH\n\nThe diagonal matrix ensures that the determinant of the result is +1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Unitary-group","page":"Group manifold","title":"Unitary group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/unitary.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.Unitary","page":"Group manifold","title":"Manifolds.Unitary","text":" Unitary{n,𝔽} = GeneralUnitaryMultiplicationGroup{n,𝔽,AbsoluteDeterminantOneMatrices}\n\nThe group of unitary matrices mathrmU(n 𝔽), either complex (when 𝔽=ℂ) or quaternionic (when 𝔽=ℍ)\n\nThe group consists of all points p 𝔽^n n where p^mathrmHp = pp^mathrmH = I.\n\nThe tangent spaces are if the form\n\nT_pmathrmU(n) = bigl X in 𝔽^nn big X = pY text where Y = -Y^mathrmH bigr\n\nand we represent tangent vectors by just storing the SkewHermitianMatrices Y, or in other words we represent the tangent spaces employing the Lie algebra mathfraku(n 𝔽).\n\nQuaternionic unitary group is isomorphic to the compact symplectic group of the same dimension.\n\nConstructor\n\nUnitary(n, 𝔽::AbstractNumbers=ℂ)\n\nConstruct mathrmU(n 𝔽). See also Orthogonal(n) for the real-valued case.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.exp_lie-Tuple{Unitary{2, ℂ}, Any}","page":"Group manifold","title":"Manifolds.exp_lie","text":"exp_lie(G::Unitary{2,ℂ}, X)\n\nCompute the group exponential map on the Unitary(2) group, which is\n\nexp_e colon X e^operatornametr(X) 2 left(cos θ I + fracsin θθ left(X - fracoperatornametr(X)2 Iright)right)\n\nwhere θ = frac12 sqrt4det(X) - operatornametr(X)^2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Power-group","page":"Group manifold","title":"Power group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/power_group.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.PowerGroup-Tuple{AbstractPowerManifold}","page":"Group manifold","title":"Manifolds.PowerGroup","text":"PowerGroup{𝔽,T} <: GroupManifold{𝔽,<:AbstractPowerManifold{𝔽,M,RPT},ProductOperation}\n\nDecorate a power manifold with a ProductOperation.\n\nConstituent manifold of the power manifold must also have a IsGroupManifold or a decorated instance of one. This type is mostly useful for equipping the direct product of group manifolds with an Identity element.\n\nConstructor\n\nPowerGroup(manifold::AbstractPowerManifold)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.PowerGroupNested","page":"Group manifold","title":"Manifolds.PowerGroupNested","text":"PowerGroupNested\n\nAlias to PowerGroup with NestedPowerRepresentation representation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.PowerGroupNestedReplacing","page":"Group manifold","title":"Manifolds.PowerGroupNestedReplacing","text":"PowerGroupNestedReplacing\n\nAlias to PowerGroup with NestedReplacingPowerRepresentation representation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Product-group","page":"Group manifold","title":"Product group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/product_group.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.ProductGroup-Union{Tuple{ProductManifold{𝔽}}, Tuple{𝔽}} where 𝔽","page":"Group manifold","title":"Manifolds.ProductGroup","text":"ProductGroup{𝔽,T} <: GroupManifold{𝔽,ProductManifold{T},ProductOperation}\n\nDecorate a product manifold with a ProductOperation.\n\nEach submanifold must also have a IsGroupManifold or a decorated instance of one. This type is mostly useful for equipping the direct product of group manifolds with an Identity element.\n\nConstructor\n\nProductGroup(manifold::ProductManifold)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.ProductOperation","page":"Group manifold","title":"Manifolds.ProductOperation","text":"ProductOperation <: AbstractGroupOperation\n\nDirect product group operation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Semidirect-product-group","page":"Group manifold","title":"Semidirect product group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/semidirect_product_group.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.SemidirectProductGroup-Union{Tuple{𝔽}, Tuple{AbstractDecoratorManifold{𝔽}, AbstractDecoratorManifold{𝔽}, AbstractGroupAction}} where 𝔽","page":"Group manifold","title":"Manifolds.SemidirectProductGroup","text":"SemidirectProductGroup(N::GroupManifold, H::GroupManifold, A::AbstractGroupAction)\n\nA group that is the semidirect product of a normal group mathcalN and a subgroup mathcalH, written mathcalG = mathcalN _θ mathcalH, where θ mathcalH mathcalN mathcalN is an automorphism action of mathcalH on mathcalN. The group mathcalG has the composition rule\n\ng circ g = (n h) circ (n h) = (n circ θ_h(n) h circ h)\n\nand the inverse\n\ng^-1 = (n h)^-1 = (θ_h^-1(n^-1) h^-1)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.SemidirectProductOperation","page":"Group manifold","title":"Manifolds.SemidirectProductOperation","text":"SemidirectProductOperation(action::AbstractGroupAction)\n\nGroup operation of a semidirect product group. The operation consists of the operation opN on a normal subgroup N, the operation opH on a subgroup H, and an automorphism action of elements of H on N. Only the action is stored.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.identity_element-Tuple{SemidirectProductGroup}","page":"Group manifold","title":"Manifolds.identity_element","text":"identity_element(G::SemidirectProductGroup)\n\nGet the identity element of SemidirectProductGroup G. Uses ArrayPartition from RecursiveArrayTools.jl to represent the point.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.translate_diff-Tuple{SemidirectProductGroup, Any, Any, Any, LeftForwardAction}","page":"Group manifold","title":"Manifolds.translate_diff","text":"translate_diff(G::SemidirectProductGroup, p, q, X, conX::LeftForwardAction)\n\nPerform differential of the left translation on the semidirect product group G.\n\nSince the left translation is defined as (cf. SemidirectProductGroup):\n\nL_(n h) (n h) = ( L_n θ_h(n) L_h h)\n\nthen its differential can be computed as\n\nmathrmdL_(n h)(X_n X_h) = ( mathrmdL_n (mathrmdθ_h(X_n)) mathrmdL_h X_h)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Special-Euclidean-group","page":"Group manifold","title":"Special Euclidean group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/special_euclidean.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.SpecialEuclidean","page":"Group manifold","title":"Manifolds.SpecialEuclidean","text":"SpecialEuclidean(n)\n\nSpecial Euclidean group mathrmSE(n), the group of rigid motions.\n\nmathrmSE(n) is the semidirect product of the TranslationGroup on ℝ^n and SpecialOrthogonal(n)\n\nmathrmSE(n) mathrmT(n) _θ mathrmSO(n)\n\nwhere θ is the canonical action of mathrmSO(n) on mathrmT(n) by vector rotation.\n\nThis constructor is equivalent to calling\n\nTn = TranslationGroup(n)\nSOn = SpecialOrthogonal(n)\nSemidirectProductGroup(Tn, SOn, RotationAction(Tn, SOn))\n\nPoints on mathrmSE(n) may be represented as points on the underlying product manifold mathrmT(n) mathrmSO(n). For group-specific functions, they may also be represented as affine matrices with size (n + 1, n + 1) (see affine_matrix), for which the group operation is MultiplicationOperation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.SpecialEuclideanInGeneralLinear","page":"Group manifold","title":"Manifolds.SpecialEuclideanInGeneralLinear","text":"SpecialEuclideanInGeneralLinear\n\nAn explicit isometric and homomorphic embedding of mathrmSE(n) in mathrmGL(n+1) and 𝔰𝔢(n) in 𝔤𝔩(n+1). Note that this is not a transparently isometric embedding.\n\nConstructor\n\nSpecialEuclideanInGeneralLinear(n)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.adjoint_action-Tuple{GroupManifold{ℝ, ProductManifold{ℝ, Tuple{TranslationGroup{Tuple{3}, ℝ}, SpecialOrthogonal{3}}}, Manifolds.SemidirectProductOperation{RotationAction{TranslationGroup{Tuple{3}, ℝ}, SpecialOrthogonal{3}, LeftForwardAction}}}, Any, TFVector{<:Any, VeeOrthogonalBasis{ℝ}}}","page":"Group manifold","title":"Manifolds.adjoint_action","text":"adjoint_action(::SpecialEuclidean{3}, p, fX::TFVector{<:Any,VeeOrthogonalBasis{ℝ}})\n\nAdjoint action of the SpecialEuclidean group on the vector with coefficients fX tangent at point p.\n\nThe formula for the coefficients reads t(Rω) + Rr for the translation part and Rω for the rotation part, where t is the translation part of p, R is the rotation matrix part of p, r is the translation part of fX and ω is the rotation part of fX, is the cross product and is the matrix product.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.affine_matrix-Union{Tuple{n}, Tuple{SpecialEuclidean{n}, Any}} where n","page":"Group manifold","title":"Manifolds.affine_matrix","text":"affine_matrix(G::SpecialEuclidean, p) -> AbstractMatrix\n\nRepresent the point p mathrmSE(n) as an affine matrix. For p = (t R) mathrmSE(n), where t mathrmT(n) R mathrmSO(n), the affine representation is the n + 1 n + 1 matrix\n\nbeginpmatrix\nR t \n0^mathrmT 1\nendpmatrix\n\nThis function embeds mathrmSE(n) in the general linear group mathrmGL(n+1). It is an isometric embedding and group homomorphism [RicoMartinez1988].\n\nSee also screw_matrix for matrix representations of the Lie algebra.\n\n[RicoMartinez1988]: Rico Martinez, J. M., “Representations of the Euclidean group and its applications to the kinematics of spatial chains,” PhD Thesis, University of Florida, 1988.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.exp_lie-Tuple{GroupManifold{ℝ, ProductManifold{ℝ, Tuple{TranslationGroup{Tuple{2}, ℝ}, SpecialOrthogonal{2}}}, Manifolds.SemidirectProductOperation{RotationAction{TranslationGroup{Tuple{2}, ℝ}, SpecialOrthogonal{2}, LeftForwardAction}}}, Any}","page":"Group manifold","title":"Manifolds.exp_lie","text":"exp_lie(G::SpecialEuclidean{2}, X)\n\nCompute the group exponential of X = (b Ω) 𝔰𝔢(2), where b 𝔱(2) and Ω 𝔰𝔬(2):\n\nexp X = (t R) = (U(θ) b exp Ω)\n\nwhere t mathrmT(2), R = exp Ω is the group exponential on mathrmSO(2),\n\nU(θ) = fracsin θθ I_2 + frac1 - cos θθ^2 Ω\n\nand θ = frac1sqrt2 lVert Ω rVert_e (see norm) is the angle of the rotation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.exp_lie-Tuple{GroupManifold{ℝ, ProductManifold{ℝ, Tuple{TranslationGroup{Tuple{3}, ℝ}, SpecialOrthogonal{3}}}, Manifolds.SemidirectProductOperation{RotationAction{TranslationGroup{Tuple{3}, ℝ}, SpecialOrthogonal{3}, LeftForwardAction}}}, Any}","page":"Group manifold","title":"Manifolds.exp_lie","text":"exp_lie(G::SpecialEuclidean{3}, X)\n\nCompute the group exponential of X = (b Ω) 𝔰𝔢(3), where b 𝔱(3) and Ω 𝔰𝔬(3):\n\nexp X = (t R) = (U(θ) b exp Ω)\n\nwhere t mathrmT(3), R = exp Ω is the group exponential on mathrmSO(3),\n\nU(θ) = I_3 + frac1 - cos θθ^2 Ω + fracθ - sin θθ^3 Ω^2\n\nand θ = frac1sqrt2 lVert Ω rVert_e (see norm) is the angle of the rotation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.exp_lie-Tuple{SpecialEuclidean, Any}","page":"Group manifold","title":"Manifolds.exp_lie","text":"exp_lie(G::SpecialEuclidean{n}, X)\n\nCompute the group exponential of X = (b Ω) 𝔰𝔢(n), where b 𝔱(n) and Ω 𝔰𝔬(n):\n\nexp X = (t R)\n\nwhere t mathrmT(n) and R = exp Ω is the group exponential on mathrmSO(n).\n\nIn the screw_matrix representation, the group exponential is the matrix exponential (see exp_lie).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.lie_bracket-Tuple{SpecialEuclidean, ProductRepr, ProductRepr}","page":"Group manifold","title":"Manifolds.lie_bracket","text":"lie_bracket(G::SpecialEuclidean, X::ProductRepr, Y::ProductRepr)\nlie_bracket(G::SpecialEuclidean, X::ArrayPartition, Y::ArrayPartition)\nlie_bracket(G::SpecialEuclidean, X::AbstractMatrix, Y::AbstractMatrix)\n\nCalculate the Lie bracket between elements X and Y of the special Euclidean Lie algebra. For the matrix representation (which can be obtained using screw_matrix) the formula is X Y = XY-YX, while in the ProductRepr representation the formula reads X Y = (t_1 R_1) (t_2 R_2) = (R_1 t_2 - R_2 t_1 R_1 R_2 - R_2 R_1).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.log_lie-Tuple{GroupManifold{ℝ, ProductManifold{ℝ, Tuple{TranslationGroup{Tuple{2}, ℝ}, SpecialOrthogonal{2}}}, Manifolds.SemidirectProductOperation{RotationAction{TranslationGroup{Tuple{2}, ℝ}, SpecialOrthogonal{2}, LeftForwardAction}}}, Any}","page":"Group manifold","title":"Manifolds.log_lie","text":"log_lie(G::SpecialEuclidean{2}, p)\n\nCompute the group logarithm of p = (t R) mathrmSE(2), where t mathrmT(2) and R mathrmSO(2):\n\nlog p = (b Ω) = (U(θ)^-1 t log R)\n\nwhere b 𝔱(2), Ω = log R 𝔰𝔬(2) is the group logarithm on mathrmSO(2),\n\nU(θ) = fracsin θθ I_2 + frac1 - cos θθ^2 Ω\n\nand θ = frac1sqrt2 lVert Ω rVert_e (see norm) is the angle of the rotation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.log_lie-Tuple{GroupManifold{ℝ, ProductManifold{ℝ, Tuple{TranslationGroup{Tuple{3}, ℝ}, SpecialOrthogonal{3}}}, Manifolds.SemidirectProductOperation{RotationAction{TranslationGroup{Tuple{3}, ℝ}, SpecialOrthogonal{3}, LeftForwardAction}}}, Any}","page":"Group manifold","title":"Manifolds.log_lie","text":"log_lie(G::SpecialEuclidean{3}, p)\n\nCompute the group logarithm of p = (t R) mathrmSE(3), where t mathrmT(3) and R mathrmSO(3):\n\nlog p = (b Ω) = (U(θ)^-1 t log R)\n\nwhere b 𝔱(3), Ω = log R 𝔰𝔬(3) is the group logarithm on mathrmSO(3),\n\nU(θ) = I_3 + frac1 - cos θθ^2 Ω + fracθ - sin θθ^3 Ω^2\n\nand θ = frac1sqrt2 lVert Ω rVert_e (see norm) is the angle of the rotation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.log_lie-Tuple{SpecialEuclidean, Any}","page":"Group manifold","title":"Manifolds.log_lie","text":"log_lie(G::SpecialEuclidean{n}, p) where {n}\n\nCompute the group logarithm of p = (t R) mathrmSE(n), where t mathrmT(n) and R mathrmSO(n):\n\nlog p = (b Ω)\n\nwhere b 𝔱(n) and Ω = log R 𝔰𝔬(n) is the group logarithm on mathrmSO(n).\n\nIn the affine_matrix representation, the group logarithm is the matrix logarithm (see log_lie):\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.screw_matrix-Union{Tuple{n}, Tuple{SpecialEuclidean{n}, Any}} where n","page":"Group manifold","title":"Manifolds.screw_matrix","text":"screw_matrix(G::SpecialEuclidean, X) -> AbstractMatrix\n\nRepresent the Lie algebra element X 𝔰𝔢(n) = T_e mathrmSE(n) as a screw matrix. For X = (b Ω) 𝔰𝔢(n), where Ω 𝔰𝔬(n) = T_e mathrmSO(n), the screw representation is the n + 1 n + 1 matrix\n\nbeginpmatrix\nΩ b \n0^mathrmT 0\nendpmatrix\n\nThis function embeds 𝔰𝔢(n) in the general linear Lie algebra 𝔤𝔩(n+1) but it's not a homomorphic embedding (see SpecialEuclideanInGeneralLinear for a homomorphic one).\n\nSee also affine_matrix for matrix representations of the Lie group.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.translate_diff-Tuple{SpecialEuclidean, Any, Any, Any, RightBackwardAction}","page":"Group manifold","title":"Manifolds.translate_diff","text":"translate_diff(G::SpecialEuclidean, p, q, X, ::RightBackwardAction)\n\nDifferential of the right action of the SpecialEuclidean group on itself. The formula for the rotation part is the differential of the right rotation action, while the formula for the translation part reads\n\nR_qX_Rt_p + X_t\n\nwhere R_q is the rotation part of q, X_R is the rotation part of X, t_p is the translation part of p and X_t is the translation part of X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.embed-Tuple{EmbeddedManifold{ℝ, <:SpecialEuclidean, <:GeneralLinear}, Any, Any}","page":"Group manifold","title":"ManifoldsBase.embed","text":"embed(M::SpecialEuclideanInGeneralLinear, p, X)\n\nEmbed the tangent vector X at point p on SpecialEuclidean in the GeneralLinear group. Point p can use any representation valid for SpecialEuclidean. The embedding is similar from the one defined by screw_matrix but the translation part is multiplied by inverse of the rotation part.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.embed-Tuple{EmbeddedManifold{ℝ, <:SpecialEuclidean, <:GeneralLinear}, Any}","page":"Group manifold","title":"ManifoldsBase.embed","text":"embed(M::SpecialEuclideanInGeneralLinear, p)\n\nEmbed the point p on SpecialEuclidean in the GeneralLinear group. The embedding is calculated using affine_matrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.project-Tuple{EmbeddedManifold{ℝ, <:SpecialEuclidean, <:GeneralLinear}, Any, Any}","page":"Group manifold","title":"ManifoldsBase.project","text":"project(M::SpecialEuclideanInGeneralLinear, p, X)\n\nProject tangent vector X at point p in GeneralLinear to the SpecialEuclidean Lie algebra. This reverses the transformation performed by embed\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.project-Tuple{EmbeddedManifold{ℝ, <:SpecialEuclidean, <:GeneralLinear}, Any}","page":"Group manifold","title":"ManifoldsBase.project","text":"project(M::SpecialEuclideanInGeneralLinear, p)\n\nProject point p in GeneralLinear to the SpecialEuclidean group. This is performed by extracting the rotation and translation part as in affine_matrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Special-linear-group","page":"Group manifold","title":"Special linear group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/special_linear.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.SpecialLinear","page":"Group manifold","title":"Manifolds.SpecialLinear","text":"SpecialLinear{n,𝔽} <: AbstractDecoratorManifold\n\nThe special linear group mathrmSL(n𝔽) that is, the group of all invertible matrices with unit determinant in 𝔽^nn.\n\nThe Lie algebra 𝔰𝔩(n 𝔽) = T_e mathrmSL(n𝔽) is the set of all matrices in 𝔽^nn with trace of zero. By default, tangent vectors X_p T_p mathrmSL(n𝔽) for p mathrmSL(n𝔽) are represented with their corresponding Lie algebra vector X_e = p^-1X_p 𝔰𝔩(n 𝔽).\n\nThe default metric is the same left-mathrmGL(n)-right-mathrmO(n)-invariant metric used for GeneralLinear(n, 𝔽). The resulting geodesic on mathrmGL(n𝔽) emanating from an element of mathrmSL(n𝔽) in the direction of an element of 𝔰𝔩(n 𝔽) is a closed subgroup of mathrmSL(n𝔽). As a result, most metric functions forward to GeneralLinear.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#ManifoldsBase.project-Tuple{SpecialLinear, Any, Any}","page":"Group manifold","title":"ManifoldsBase.project","text":"project(G::SpecialLinear, p, X)\n\nOrthogonally project X 𝔽^n n onto the tangent space of p to the SpecialLinear G = mathrmSL(n 𝔽). The formula reads\n\noperatornameproj_p\n = (mathrmdL_p)_e operatornameproj_𝔰𝔩(n 𝔽) (mathrmdL_p^-1)_p\n colon X X - fracoperatornametr(X)n I\n\nwhere the last expression uses the tangent space representation as the Lie algebra.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.project-Tuple{SpecialLinear, Any}","page":"Group manifold","title":"ManifoldsBase.project","text":"project(G::SpecialLinear, p)\n\nProject p mathrmGL(n 𝔽) to the SpecialLinear group G=mathrmSL(n 𝔽).\n\nGiven the singular value decomposition of p, written p = U S V^mathrmH, the formula for the projection is\n\noperatornameproj_mathrmSL(n 𝔽)(p) = U S D V^mathrmH\n\nwhere\n\nD_ij = δ_ij begincases\n 1 text if i n \n det(p)^-1 text if i = n\nendcases\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Translation-group","page":"Group manifold","title":"Translation group","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/translation_group.jl\"]\nOrder = [:constant, :type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.TranslationGroup","page":"Group manifold","title":"Manifolds.TranslationGroup","text":"TranslationGroup{T<:Tuple,𝔽} <: GroupManifold{Euclidean{T,𝔽},AdditionOperation}\n\nTranslation group mathrmT(n) represented by translation arrays.\n\nConstructor\n\nTranslationGroup(n₁,...,nᵢ; field = 𝔽)\n\nGenerate the translation group on 𝔽^n₁nᵢ = Euclidean(n₁,...,nᵢ; field = 𝔽), which is isomorphic to the group itself.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Group-actions","page":"Group manifold","title":"Group actions","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Group actions represent actions of a given group on a specified manifold. The following operations are available:","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"apply: performs given action of an element of the group on an object of compatible type.\napply_diff: differential of apply with respect to the object it acts upon.\ndirection: tells whether a given action is LeftForwardAction, RightForwardAction, LeftBackwardAction or RightBackwardAction.\ninverse_apply: performs given action of the inverse of an element of the group on an object of compatible type. By default inverts the element and calls apply but it may be have a faster implementation for some actions.\ninverse_apply_diff: counterpart of apply_diff for inverse_apply.\noptimal_alignment: determine the element of a group that, when it acts upon a point, produces the element closest to another given point in the metric of the G-manifold.","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Furthermore, group operation action features the following:","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"translate: an operation that performs either left (LeftForwardAction) or right (RightBackwardAction) translation, or actions by inverses of elements (RightForwardAction and LeftBackwardAction). This is by default performed by calling compose with appropriate order of arguments. This function is separated from compose mostly to easily represent its differential, translate_diff.\ntranslate_diff: differential of translate with respect to the point being translated.\nadjoint_action: adjoint action of a given element of a Lie group on an element of its Lie algebra.\nlie_bracket: Lie bracket of two vectors from a Lie algebra corresponding to a given group.","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"The following group actions are available:","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Group operation action GroupOperationAction that describes action of a group on itself.\nRotationAction, that is action of SpecialOrthogonal group on different manifolds.\nTranslationAction, which is the action of TranslationGroup group on different manifolds.","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/group_action.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.AbstractGroupAction","page":"Group manifold","title":"Manifolds.AbstractGroupAction","text":"AbstractGroupAction\n\nAn abstract group action on a manifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.adjoint_apply_diff_group-Tuple{AbstractGroupAction, Any, Any, Any}","page":"Group manifold","title":"Manifolds.adjoint_apply_diff_group","text":"adjoint_apply_diff_group(A::AbstractGroupAction, a, X, p)\n\nPullback with respect to group element of group action A.\n\n(mathrmdτ^p*) T_τ_a p mathcal M T_a mathcal G\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.apply!-Tuple{AbstractGroupAction{LeftForwardAction}, Any, Any, Any}","page":"Group manifold","title":"Manifolds.apply!","text":"apply!(A::AbstractGroupAction, q, a, p)\n\nApply action a to the point p with the rule specified by A. The result is saved in q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.apply-Tuple{AbstractGroupAction, Any, Any}","page":"Group manifold","title":"Manifolds.apply","text":"apply(A::AbstractGroupAction, a, p)\n\nApply action a to the point p using map τ_a, specified by A. Unless otherwise specified, the right action is defined in terms of the left action:\n\nmathrmR_a = mathrmL_a^-1\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.apply_diff-Tuple{AbstractGroupAction, Any, Any, Any}","page":"Group manifold","title":"Manifolds.apply_diff","text":"apply_diff(A::AbstractGroupAction, a, p, X)\n\nFor point p mathcal M and tangent vector X T_p mathcal M, compute the action on X of the differential of the action of a mathcalG, specified by rule A. Written as (mathrmdτ_a)_p, with the specified left or right convention, the differential transports vectors\n\n(mathrmdτ_a)_p T_p mathcal M T_τ_a p mathcal M\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.apply_diff_group-Tuple{AbstractGroupAction, Any, Any, Any}","page":"Group manifold","title":"Manifolds.apply_diff_group","text":"apply_diff_group(A::AbstractGroupAction, a, X, p)\n\nCompute the value of differential of action AbstractGroupAction A on vector X, where element a is acting on p, with respect to the group element.\n\nLet mathcal G be the group acting on manifold mathcal M by the action A. The action is of element g mathcal G on a point p mathcal M. The differential transforms vector X from the tangent space at a ∈ \\mathcal G, X T_a mathcal G into a tangent space of the manifold mathcal M. When action on element p is written as mathrmdτ^p, with the specified left or right convention, the differential transforms vectors\n\n(mathrmdτ^p) T_a mathcal G T_τ_a p mathcal M\n\nSee also\n\napply, apply_diff\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.base_group-Tuple{AbstractGroupAction}","page":"Group manifold","title":"Manifolds.base_group","text":"base_group(A::AbstractGroupAction)\n\nThe group that acts in action A.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.center_of_orbit","page":"Group manifold","title":"Manifolds.center_of_orbit","text":"center_of_orbit(\n A::AbstractGroupAction,\n pts,\n p,\n mean_method::AbstractEstimationMethod = GradientDescentEstimation(),\n)\n\nCalculate an action element a of action A that is the mean element of the orbit of p with respect to given set of points pts. The mean is calculated using the method mean_method.\n\nThe orbit of p with respect to the action of a group mathcalG is the set\n\nO = τ_a p a mathcalG \n\nThis function is useful for computing means on quotients of manifolds by a Lie group action.\n\n\n\n\n\n","category":"function"},{"location":"manifolds/group.html#Manifolds.direction-Union{Tuple{AbstractGroupAction{AD}}, Tuple{AD}} where AD","page":"Group manifold","title":"Manifolds.direction","text":"direction(::AbstractGroupAction{AD}) -> AD\n\nGet the direction of the action\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.group_manifold-Tuple{AbstractGroupAction}","page":"Group manifold","title":"Manifolds.group_manifold","text":"group_manifold(A::AbstractGroupAction)\n\nThe manifold the action A acts upon.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.inverse_apply!-Tuple{AbstractGroupAction, Any, Any, Any}","page":"Group manifold","title":"Manifolds.inverse_apply!","text":"inverse_apply!(A::AbstractGroupAction, q, a, p)\n\nApply inverse of action a to the point p with the rule specified by A. The result is saved in q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.inverse_apply-Tuple{AbstractGroupAction, Any, Any}","page":"Group manifold","title":"Manifolds.inverse_apply","text":"inverse_apply(A::AbstractGroupAction, a, p)\n\nApply inverse of action a to the point p. The action is specified by A.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.inverse_apply_diff-Tuple{AbstractGroupAction, Any, Any, Any}","page":"Group manifold","title":"Manifolds.inverse_apply_diff","text":"inverse_apply_diff(A::AbstractGroupAction, a, p, X)\n\nFor group point p mathcal M and tangent vector X T_p mathcal M, compute the action on X of the differential of the inverse action of a mathcalG, specified by rule A. Written as (mathrmdτ_a^-1)_p, with the specified left or right convention, the differential transports vectors\n\n(mathrmdτ_a^-1)_p T_p mathcal M T_τ_a^-1 p mathcal M\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.optimal_alignment!-Tuple{AbstractGroupAction, Any, Any, Any}","page":"Group manifold","title":"Manifolds.optimal_alignment!","text":"optimal_alignment!(A::AbstractGroupAction, x, p, q)\n\nCalculate an action element of action A that acts upon p to produce the element closest to q. The result is written to x.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.optimal_alignment-Tuple{AbstractGroupAction, Any, Any}","page":"Group manifold","title":"Manifolds.optimal_alignment","text":"optimal_alignment(A::AbstractGroupAction, p, q)\n\nCalculate an action element a of action A that acts upon p to produce the element closest to q in the metric of the G-manifold:\n\nargmin_a mathcalG d_mathcal M(τ_a p q)\n\nwhere mathcalG is the group that acts on the G-manifold mathcal M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Group-operation-action","page":"Group manifold","title":"Group operation action","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/group_operation_action.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.GroupOperationAction","page":"Group manifold","title":"Manifolds.GroupOperationAction","text":"GroupOperationAction(group::AbstractDecoratorManifold, AD::ActionDirection = LeftForwardAction())\n\nAction of a group upon itself via left or right translation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Rotation-action","page":"Group manifold","title":"Rotation action","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/rotation_action.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.ColumnwiseMultiplicationAction","page":"Group manifold","title":"Manifolds.ColumnwiseMultiplicationAction","text":"ColumnwiseMultiplicationAction{\n TM<:AbstractManifold,\n TO<:GeneralUnitaryMultiplicationGroup,\n TAD<:ActionDirection,\n} <: AbstractGroupAction{TAD}\n\nAction of the (special) unitary or orthogonal group GeneralUnitaryMultiplicationGroup of type On columns of points on a matrix manifold M.\n\nConstructor\n\nColumnwiseMultiplicationAction(\n M::AbstractManifold,\n On::GeneralUnitaryMultiplicationGroup,\n AD::ActionDirection = LeftForwardAction(),\n)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.RotationAction","page":"Group manifold","title":"Manifolds.RotationAction","text":"RotationAction(\n M::AbstractManifold,\n SOn::SpecialOrthogonal,\n AD::ActionDirection = LeftForwardAction(),\n)\n\nSpace of actions of the SpecialOrthogonal group mathrmSO(n) on a Euclidean-like manifold M of dimension n.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.RotationAroundAxisAction","page":"Group manifold","title":"Manifolds.RotationAroundAxisAction","text":"RotationAroundAxisAction(axis::AbstractVector)\n\nSpace of actions of the circle group RealCircleGroup on ℝ^3 around given axis.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.RowwiseMultiplicationAction","page":"Group manifold","title":"Manifolds.RowwiseMultiplicationAction","text":"RowwiseMultiplicationAction{\n TM<:AbstractManifold,\n TO<:GeneralUnitaryMultiplicationGroup,\n TAD<:ActionDirection,\n} <: AbstractGroupAction{TAD}\n\nAction of the (special) unitary or orthogonal group GeneralUnitaryMultiplicationGroup of type On columns of points on a matrix manifold M.\n\nConstructor\n\nRowwiseMultiplicationAction(\n M::AbstractManifold,\n On::GeneralUnitaryMultiplicationGroup,\n AD::ActionDirection = LeftForwardAction(),\n)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.apply-Tuple{Manifolds.RotationAroundAxisAction, Any, Any}","page":"Group manifold","title":"Manifolds.apply","text":"apply(A::RotationAroundAxisAction, θ, p)\n\nRotate point p from Euclidean(3) manifold around axis A.axis by angle θ. The formula reads\n\np_rot = (cos(θ))p + (kp) sin(θ) + k (kp) (1-cos(θ))\n\nwhere k is the vector A.axis and ⋅ is the dot product.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.optimal_alignment-Tuple{Manifolds.ColumnwiseMultiplicationAction{TM, TO, LeftForwardAction} where {TM<:AbstractManifold, TO<:Manifolds.GeneralUnitaryMultiplicationGroup}, Any, Any}","page":"Group manifold","title":"Manifolds.optimal_alignment","text":"optimal_alignment(A::LeftColumnwiseMultiplicationAction, p, q)\n\nCompute optimal alignment for the left ColumnwiseMultiplicationAction, i.e. the group element O^* that, when it acts on p, returns the point closest to q. Details of computation are described in Section 2.2.1 of [Srivastava2016].\n\nThe formula reads\n\nO^* = begincases\nUV^T textif operatornamedet(p q^mathrmT)\nU K V^mathrmT textotherwise\nendcases\n\nwhere U Sigma V^mathrmT is the SVD decomposition of p q^mathrmT and K is the unit diagonal matrix with the last element on the diagonal replaced with -1.\n\nReferences\n\n[Srivastava2016]: A. Srivastava and E. P. Klassen, Functional and Shape Data Analysis. Springer New York, 2016. ISBN: 978-1-4939-4018-9. doi: 10.1007/978-1-4939-4020-2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Translation-action","page":"Group manifold","title":"Translation action","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/translation_action.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.TranslationAction","page":"Group manifold","title":"Manifolds.TranslationAction","text":"TranslationAction(\n M::AbstractManifold,\n Rn::TranslationGroup,\n AD::ActionDirection = LeftForwardAction(),\n)\n\nSpace of actions of the TranslationGroup mathrmT(n) on a Euclidean-like manifold M.\n\nThe left and right actions are equivalent.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Metrics-on-groups","page":"Group manifold","title":"Metrics on groups","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Lie groups by default typically forward all metric-related operations like exponential or logarithmic map to the underlying manifold, for example SpecialOrthogonal uses methods for Rotations (which is, incidentally, bi-invariant), or SpecialEuclidean uses product metric of the translation and rotation parts (which is not invariant under group operation).","category":"page"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"It is, however, possible to change the metric used by a group by wrapping it in a MetricManifold decorator.","category":"page"},{"location":"manifolds/group.html#Invariant-metrics","page":"Group manifold","title":"Invariant metrics","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/metric.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.LeftInvariantMetric","page":"Group manifold","title":"Manifolds.LeftInvariantMetric","text":"LeftInvariantMetric <: AbstractMetric\n\nAn AbstractMetric that changes the metric of a Lie group to the left-invariant metric obtained by left-translations to the identity. Adds the HasLeftInvariantMetric trait.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.RightInvariantMetric","page":"Group manifold","title":"Manifolds.RightInvariantMetric","text":"RightInvariantMetric <: AbstractMetric\n\nAn AbstractMetric that changes the metric of a Lie group to the right-invariant metric obtained by right-translations to the identity. Adds the HasRightInvariantMetric trait.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.direction-Tuple{AbstractDecoratorManifold}","page":"Group manifold","title":"Manifolds.direction","text":"direction(::AbstractDecoratorManifold) -> AD\n\nGet the direction of the action a certain Lie group with its implicit metric has\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Manifolds.has_approx_invariant_metric-Tuple{AbstractDecoratorManifold, Any, Any, Any, Any, ActionDirection}","page":"Group manifold","title":"Manifolds.has_approx_invariant_metric","text":"has_approx_invariant_metric(\n G::AbstractDecoratorManifold,\n p,\n X,\n Y,\n qs::AbstractVector,\n conv::ActionDirection = LeftForwardAction();\n kwargs...,\n) -> Bool\n\nCheck whether the metric on the group mathcalG is (approximately) invariant using a set of predefined points. Namely, for p mathcalG, XY T_p mathcalG, a metric g, and a translation map τ_q in the specified direction, check for each q mathcalG that the following condition holds:\n\ng_p(X Y) g_τ_q p((mathrmdτ_q)_p X (mathrmdτ_q)_p Y)\n\nThis is necessary but not sufficient for invariance.\n\nOptionally, kwargs passed to isapprox may be provided.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Cartan-Schouten-connections","page":"Group manifold","title":"Cartan-Schouten connections","text":"","category":"section"},{"location":"manifolds/group.html","page":"Group manifold","title":"Group manifold","text":"Modules = [Manifolds]\nPages = [\"groups/connections.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/group.html#Manifolds.AbstractCartanSchoutenConnection","page":"Group manifold","title":"Manifolds.AbstractCartanSchoutenConnection","text":"AbstractCartanSchoutenConnection\n\nAbstract type for Cartan-Schouten connections, that is connections whose geodesics going through group identity are one-parameter subgroups. See[Pennec2020] for details.\n\n[Pennec2020]: X. Pennec and M. Lorenzi, “5 - Beyond Riemannian geometry: The affine connection setting for transformation groups,” in Riemannian Geometric Statistics in Medical Image Analysis, X. Pennec, S. Sommer, and T. Fletcher, Eds. Academic Press, 2020, pp. 169–229. doi: 10.1016/B978-0-12-814725-2.00012-1.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.CartanSchoutenMinus","page":"Group manifold","title":"Manifolds.CartanSchoutenMinus","text":"CartanSchoutenMinus\n\nThe unique Cartan-Schouten connection such that all left-invariant vector fields are globally defined by their value at identity. It is biinvariant with respect to the group operation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.CartanSchoutenPlus","page":"Group manifold","title":"Manifolds.CartanSchoutenPlus","text":"CartanSchoutenPlus\n\nThe unique Cartan-Schouten connection such that all right-invariant vector fields are globally defined by their value at identity. It is biinvariant with respect to the group operation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Manifolds.CartanSchoutenZero","page":"Group manifold","title":"Manifolds.CartanSchoutenZero","text":"CartanSchoutenZero\n\nThe unique torsion-free Cartan-Schouten connection. It is biinvariant with respect to the group operation.\n\nIf the metric on the underlying manifold is bi-invariant then it is equivalent to the Levi-Civita connection of that metric.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/group.html#Base.exp-Union{Tuple{𝔽}, Tuple{ConnectionManifold{𝔽, <:AbstractDecoratorManifold{𝔽}, <:AbstractCartanSchoutenConnection}, Any, Any}} where 𝔽","page":"Group manifold","title":"Base.exp","text":"exp(M::ConnectionManifold{𝔽,<:AbstractDecoratorManifold{𝔽},<:AbstractCartanSchoutenConnection}, p, X) where {𝔽}\n\nCompute the exponential map on the ConnectionManifold M with a Cartan-Schouten connection. See Sections 5.3.2 and 5.3.3 of [Pennec2020] for details.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#Base.log-Union{Tuple{𝔽}, Tuple{ConnectionManifold{𝔽, <:AbstractDecoratorManifold{𝔽}, <:AbstractCartanSchoutenConnection}, Any, Any}} where 𝔽","page":"Group manifold","title":"Base.log","text":"log(M::ConnectionManifold{𝔽,<:AbstractDecoratorManifold{𝔽},<:AbstractCartanSchoutenConnection}, p, q) where {𝔽}\n\nCompute the logarithmic map on the ConnectionManifold M with a Cartan-Schouten connection. See Sections 5.3.2 and 5.3.3 of [Pennec2020] for details.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.parallel_transport_direction-Tuple{ConnectionManifold{𝔽, M, CartanSchoutenZero} where {𝔽, M}, Identity, Any, Any}","page":"Group manifold","title":"ManifoldsBase.parallel_transport_direction","text":"parallel_transport_direction(M::CartanSchoutenZeroGroup, ::Identity, X, d)\n\nTransport tangent vector X at identity on the group manifold with the CartanSchoutenZero connection in the direction d. See [Pennec2020] for details.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.parallel_transport_to-Tuple{ConnectionManifold{𝔽, M, CartanSchoutenMinus} where {𝔽, M}, Any, Any, Any}","page":"Group manifold","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::CartanSchoutenMinusGroup, p, X, q)\n\nTransport tangent vector X at point p on the group manifold M with the CartanSchoutenMinus connection to point q. See [Pennec2020] for details.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.parallel_transport_to-Tuple{ConnectionManifold{𝔽, M, CartanSchoutenPlus} where {𝔽, M}, Any, Any, Any}","page":"Group manifold","title":"ManifoldsBase.parallel_transport_to","text":"vector_transport_to(M::CartanSchoutenPlusGroup, p, X, q)\n\nTransport tangent vector X at point p on the group manifold M with the CartanSchoutenPlus connection to point q. See [Pennec2020] for details.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/group.html#ManifoldsBase.parallel_transport_to-Tuple{ConnectionManifold{𝔽, M, CartanSchoutenZero} where {𝔽, M}, Identity, Any, Any}","page":"Group manifold","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::CartanSchoutenZeroGroup, p::Identity, X, q)\n\nTransport vector X at identity of group M equipped with the CartanSchoutenZero connection to point q using parallel transport.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Metric-manifold","page":"Metric manifold","title":"Metric manifold","text":"","category":"section"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"A Riemannian manifold always consists of a topological manifold together with a smoothly varying metric g.","category":"page"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"However, often there is an implicitly assumed (default) metric, like the usual inner product on Euclidean space. This decorator takes this into account. It is not necessary to use this decorator if you implement just one (or the first) metric. If you later introduce a second, the old (first) metric can be used with the (non MetricManifold) AbstractManifold, i.e. without an explicitly stated metric.","category":"page"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"This manifold decorator serves two purposes:","category":"page"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"to implement different metrics (e.g. in closed form) for one AbstractManifold\nto provide a way to compute geodesics on manifolds, where this AbstractMetric does not yield closed formula.","category":"page"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"Pages = [\"metric.md\"]\nDepth = 2","category":"page"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"Note that a metric manifold is has a IsConnectionManifold trait referring to the LeviCivitaConnection of the metric g, and thus a large part of metric manifold's functionality relies on this.","category":"page"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"Let's first look at the provided types.","category":"page"},{"location":"manifolds/metric.html#Types","page":"Metric manifold","title":"Types","text":"","category":"section"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/MetricManifold.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/metric.html#Manifolds.IsDefaultMetric","page":"Metric manifold","title":"Manifolds.IsDefaultMetric","text":"IsDefaultMetric{G<:AbstractMetric}\n\nSpecify that a certain AbstractMetric is the default metric for a manifold. This way the corresponding MetricManifold falls back to the default methods of the manifold it decorates.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/metric.html#Manifolds.IsMetricManifold","page":"Metric manifold","title":"Manifolds.IsMetricManifold","text":"IsMetricManifold <: AbstractTrait\n\nSpecify that a certain decorated Manifold is a metric manifold in the sence that it provides explicit metric properties, extending/changing the default metric properties of a manifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/metric.html#Manifolds.MetricManifold","page":"Metric manifold","title":"Manifolds.MetricManifold","text":"MetricManifold{𝔽,M<:AbstractManifold{𝔽},G<:AbstractMetric} <: AbstractDecoratorManifold{𝔽}\n\nEquip a AbstractManifold explicitly with an AbstractMetric G.\n\nFor a Metric AbstractManifold, by default, assumes, that you implement the linear form from local_metric in order to evaluate the exponential map.\n\nIf the corresponding AbstractMetric G yields closed form formulae for e.g. the exponential map and this is implemented directly (without solving the ode), you can of course still implement that directly.\n\nConstructor\n\nMetricManifold(M, G)\n\nGenerate the AbstractManifold M as a manifold with the AbstractMetric G.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/metric.html#Implement-Different-Metrics-on-the-same-Manifold","page":"Metric manifold","title":"Implement Different Metrics on the same Manifold","text":"","category":"section"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"In order to distinguish different metrics on one manifold, one can introduce two AbstractMetrics and use this type to dispatch on the metric, see SymmetricPositiveDefinite. To avoid overhead, one AbstractMetric can then be marked as being the default, i.e. the one that is used, when no MetricManifold decorator is present. This avoids reimplementation of the first existing metric, access to the metric-dependent functions that were implemented using the undecorated manifold, as well as the transparent fallback of the corresponding MetricManifold with default metric to the undecorated implementations. This does not cause any runtime overhead. Introducing a default AbstractMetric serves a better readability of the code when working with different metrics.","category":"page"},{"location":"manifolds/metric.html#Implementation-of-Metrics","page":"Metric manifold","title":"Implementation of Metrics","text":"","category":"section"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"For the case that a local_metric is implemented as a bilinear form that is positive definite, the following further functions are provided, unless the corresponding AbstractMetric is marked as default – then the fallbacks mentioned in the last section are used for e.g. the exponential map.","category":"page"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"Modules = [Manifolds, ManifoldsBase]\nPages = [\"manifolds/MetricManifold.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/metric.html#Base.log-Tuple{MetricManifold, Vararg{Any}}","page":"Metric manifold","title":"Base.log","text":"log(N::MetricManifold{M,G}, p, q)\n\nCopute the logarithmic map on the AbstractManifold M equipped with the AbstractMetric G.\n\nIf the metric was declared the default metric using the IsDefaultMetric trait or is_default_metric, this method falls back to log(M,p,q). Otherwise, you have to provide an implementation for the non-default AbstractMetric G metric within its MetricManifold{M,G}.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.connection-Tuple{MetricManifold}","page":"Metric manifold","title":"Manifolds.connection","text":"connection(::MetricManifold)\n\nReturn the LeviCivitaConnection for a metric manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.det_local_metric-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Metric manifold","title":"Manifolds.det_local_metric","text":"det_local_metric(M::AbstractManifold, p, B::AbstractBasis)\n\nReturn the determinant of local matrix representation of the metric tensor g, i.e. of the matrix G(p) representing the metric in the tangent space at p with as a matrix.\n\nSee also local_metric\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.einstein_tensor-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Metric manifold","title":"Manifolds.einstein_tensor","text":"einstein_tensor(M::AbstractManifold, p, B::AbstractBasis; backend::AbstractDiffBackend = diff_badefault_differential_backendckend())\n\nCompute the Einstein tensor of the manifold M at the point p, see https://en.wikipedia.org/wiki/Einstein_tensor\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.flat-Tuple{MetricManifold, Any, TFVector}","page":"Metric manifold","title":"Manifolds.flat","text":"flat(N::MetricManifold{M,G}, p, X::TFVector)\n\nCompute the musical isomorphism to transform the tangent vector X from the AbstractManifold M equipped with AbstractMetric G to a cotangent by computing\n\nX^= G_p X\n\nwhere G_p is the local matrix representation of G, see local_metric\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.inverse_local_metric-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Metric manifold","title":"Manifolds.inverse_local_metric","text":"inverse_local_metric(M::AbstractcManifold{𝔽}, p, B::AbstractBasis)\n\nReturn the local matrix representation of the inverse metric (cometric) tensor of the tangent space at p on the AbstractManifold M with respect to the AbstractBasis basis B.\n\nThe metric tensor (see local_metric) is usually denoted by G = (g_ij) 𝔽^dd, where d is the dimension of the manifold.\n\nThen the inverse local metric is denoted by G^-1 = g^ij.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.is_default_metric-Tuple{AbstractManifold, AbstractMetric}","page":"Metric manifold","title":"Manifolds.is_default_metric","text":"is_default_metric(M::AbstractManifold, G::AbstractMetric)\n\nreturns whether an AbstractMetric is the default metric on the manifold M or not. This can be set by defining this function, or setting the IsDefaultMetric trait for an AbstractDecoratorManifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.local_metric-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Metric manifold","title":"Manifolds.local_metric","text":"local_metric(M::AbstractManifold{𝔽}, p, B::AbstractBasis)\n\nReturn the local matrix representation at the point p of the metric tensor g with respect to the AbstractBasis B on the AbstractManifold M. Let ddenote the dimension of the manifold and b_1ldotsb_d the basis vectors. Then the local matrix representation is a matrix Gin 𝔽^ntimes n whose entries are given by g_ij = g_p(b_ib_j) ijin1d.\n\nThis yields the property for two tangent vectors (using Einstein summation convention) X = X^ib_i Y=Y^ib_i in T_pmathcal M we get g_p(X Y) = g_ij X^i Y^j.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.local_metric_jacobian-Tuple{AbstractManifold, Any, AbstractBasis, ManifoldDiff.AbstractDiffBackend}","page":"Metric manifold","title":"Manifolds.local_metric_jacobian","text":"local_metric_jacobian(\n M::AbstractManifold,\n p,\n B::AbstractBasis;\n backend::AbstractDiffBackend,\n)\n\nGet partial derivatives of the local metric of M at p in basis B with respect to the coordinates of p, frac p^k g_ij = g_ijk. The dimensions of the resulting multi-dimensional array are ordered (ijk).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.log_local_metric_density-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Metric manifold","title":"Manifolds.log_local_metric_density","text":"log_local_metric_density(M::AbstractManifold, p, B::AbstractBasis)\n\nReturn the natural logarithm of the metric density ρ of M at p, which is given by ρ = log sqrtdet g_ij for the metric tensor expressed in basis B.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.metric-Tuple{MetricManifold}","page":"Metric manifold","title":"Manifolds.metric","text":"metric(M::MetricManifold)\n\nGet the metric g of the manifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.ricci_curvature-Tuple{AbstractManifold, Any, AbstractBasis}","page":"Metric manifold","title":"Manifolds.ricci_curvature","text":"ricci_curvature(M::AbstractManifold, p, B::AbstractBasis; backend::AbstractDiffBackend = default_differential_backend())\n\nCompute the Ricci scalar curvature of the manifold M at the point p using basis B. The curvature is computed as the trace of the Ricci curvature tensor with respect to the metric, that is R=g^ijR_ij where R is the scalar Ricci curvature at p, g^ij is the inverse local metric (see inverse_local_metric) at p and R_ij is the Riccie curvature tensor, see ricci_tensor. Both the tensor and inverse local metric are expressed in local coordinates defined by B, and the formula uses the Einstein summation convention.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Manifolds.sharp-Tuple{MetricManifold, Any, CoTFVector}","page":"Metric manifold","title":"Manifolds.sharp","text":"sharp(N::MetricManifold{M,G}, p, ξ::CoTFVector)\n\nCompute the musical isomorphism to transform the cotangent vector ξ from the AbstractManifold M equipped with AbstractMetric G to a tangent by computing\n\nξ^ = G_p^-1 ξ\n\nwhere G_p is the local matrix representation of G, i.e. one employs inverse_local_metric here to obtain G_p^-1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#ManifoldsBase.inner-Tuple{MetricManifold, Any, Any, Any}","page":"Metric manifold","title":"ManifoldsBase.inner","text":"inner(N::MetricManifold{M,G}, p, X, Y)\n\nCompute the inner product of X and Y from the tangent space at p on the AbstractManifold M using the AbstractMetric G. If M has G as its IsDefaultMetric trait, this is done using inner(M, p, X, Y), otherwise the local_metric(M, p) is employed as\n\ng_p(X Y) = X G_p Y\n\nwhere G_p is the loal matrix representation of the AbstractMetric G.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/metric.html#Metrics,-charts-and-bases-of-vector-spaces","page":"Metric manifold","title":"Metrics, charts and bases of vector spaces","text":"","category":"section"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"Metric-related functions, similarly to connection-related functions, need to operate in a basis of a vector space, see here.","category":"page"},{"location":"manifolds/metric.html","page":"Metric manifold","title":"Metric manifold","text":"Metric-related functions can take bases of associated tangent spaces as arguments. For example local_metric can take the basis of the tangent space it is supposed to operate on instead of a custom basis of the space of symmetric bilinear operators.","category":"page"},{"location":"manifolds/symmetric.html#Symmetric-matrices","page":"Symmetric matrices","title":"Symmetric matrices","text":"","category":"section"},{"location":"manifolds/symmetric.html","page":"Symmetric matrices","title":"Symmetric matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/Symmetric.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/symmetric.html#Manifolds.SymmetricMatrices","page":"Symmetric matrices","title":"Manifolds.SymmetricMatrices","text":"SymmetricMatrices{n,𝔽} <: AbstractDecoratorManifold{𝔽}\n\nThe AbstractManifold $ \\operatorname{Sym}(n)$ consisting of the real- or complex-valued symmetric matrices of size n n, i.e. the set\n\noperatornameSym(n) = biglp 𝔽^n n big p^mathrmH = p bigr\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transpose, and the field 𝔽 ℝ ℂ.\n\nThough it is slightly redundant, usually the matrices are stored as n n arrays.\n\nNote that in this representation, the complex valued case has to have a real-valued diagonal, which is also reflected in the manifold_dimension.\n\nConstructor\n\nSymmetricMatrices(n::Int, field::AbstractNumbers=ℝ)\n\nGenerate the manifold of n n symmetric matrices.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symmetric.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{n}, Tuple{SymmetricMatrices{n, 𝔽}, Any}} where {n, 𝔽}","page":"Symmetric matrices","title":"ManifoldsBase.check_point","text":"check_point(M::SymmetricMatrices{n,𝔽}, p; kwargs...)\n\nCheck whether p is a valid manifold point on the SymmetricMatrices M, i.e. whether p is a symmetric matrix of size (n,n) with values from the corresponding AbstractNumbers 𝔽.\n\nThe tolerance for the symmetry of p can be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetric.html#ManifoldsBase.check_vector-Union{Tuple{𝔽}, Tuple{n}, Tuple{SymmetricMatrices{n, 𝔽}, Any, Any}} where {n, 𝔽}","page":"Symmetric matrices","title":"ManifoldsBase.check_vector","text":"check_vector(M::SymmetricMatrices{n,𝔽}, p, X; kwargs... )\n\nCheck whether X is a tangent vector to manifold point p on the SymmetricMatrices M, i.e. X has to be a symmetric matrix of size (n,n) and its values have to be from the correct AbstractNumbers.\n\nThe tolerance for the symmetry of X can be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetric.html#ManifoldsBase.is_flat-Tuple{SymmetricMatrices}","page":"Symmetric matrices","title":"ManifoldsBase.is_flat","text":"is_flat(::SymmetricMatrices)\n\nReturn true. SymmetricMatrices is a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetric.html#ManifoldsBase.manifold_dimension-Union{Tuple{SymmetricMatrices{N, 𝔽}}, Tuple{𝔽}, Tuple{N}} where {N, 𝔽}","page":"Symmetric matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::SymmetricMatrices{n,𝔽})\n\nReturn the dimension of the SymmetricMatrices matrix M over the number system 𝔽, i.e.\n\nbeginaligned\ndim mathrmSym(nℝ) = fracn(n+1)2\ndim mathrmSym(nℂ) = 2fracn(n+1)2 - n = n^2\nendaligned\n\nwhere the last -n is due to the zero imaginary part for Hermitian matrices\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetric.html#ManifoldsBase.project-Tuple{SymmetricMatrices, Any, Any}","page":"Symmetric matrices","title":"ManifoldsBase.project","text":"project(M::SymmetricMatrices, p, X)\n\nProject the matrix X onto the tangent space at p on the SymmetricMatrices M,\n\noperatornameproj_p(X) = frac12 bigl( X + X^mathrmH bigr)\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetric.html#ManifoldsBase.project-Tuple{SymmetricMatrices, Any}","page":"Symmetric matrices","title":"ManifoldsBase.project","text":"project(M::SymmetricMatrices, p)\n\nProjects p from the embedding onto the SymmetricMatrices M, i.e.\n\noperatornameproj_operatornameSym(n)(p) = frac12 bigl( p + p^mathrmH bigr)\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Grassmannian-manifold","page":"Grassmann","title":"Grassmannian manifold","text":"","category":"section"},{"location":"manifolds/grassmann.html","page":"Grassmann","title":"Grassmann","text":"Modules = [Manifolds]\nPages = [\"manifolds/Grassmann.jl\"]\nOrder = [:type,:function]","category":"page"},{"location":"manifolds/grassmann.html#Manifolds.Grassmann","page":"Grassmann","title":"Manifolds.Grassmann","text":"Grassmann{n,k,𝔽} <: AbstractDecoratorManifold{𝔽}\n\nThe Grassmann manifold operatornameGr(nk) consists of all subspaces spanned by k linear independent vectors 𝔽^n, where 𝔽 ℝ ℂ is either the real- (or complex-) valued vectors. This yields all k-dimensional subspaces of ℝ^n for the real-valued case and all 2k-dimensional subspaces of ℂ^n for the second.\n\nThe manifold can be represented as\n\noperatornameGr(nk) = bigl operatornamespan(p) p 𝔽^n k p^mathrmHp = I_k\n\nwhere cdot^mathrmH denotes the complex conjugate transpose or Hermitian and I_k is the k k identity matrix. This means, that the columns of p form an unitary basis of the subspace, that is a point on operatornameGr(nk), and hence the subspace can actually be represented by a whole equivalence class of representers. Another interpretation is, that\n\noperatornameGr(nk) = operatornameSt(nk) operatornameO(k)\n\ni.e the Grassmann manifold is the quotient of the Stiefel manifold and the orthogonal group operatornameO(k) of orthogonal k k matrices. Note that it doesn't matter whether we start from the Euclidean or canonical metric on the Stiefel manifold, the resulting quotient metric on Grassmann is the same.\n\nThe tangent space at a point (subspace) p is given by\n\nT_pmathrmGr(nk) = bigl\nX 𝔽^n k \nX^mathrmHp + p^mathrmHX = 0_k bigr\n\nwhere 0_k is the k k zero matrix.\n\nNote that a point p operatornameGr(nk) might be represented by different matrices (i.e. matrices with unitary column vectors that span the same subspace). Different representations of p also lead to different representation matrices for the tangent space T_pmathrmGr(nk)\n\nFor a representation of points as orthogonal projectors. Here\n\noperatornameGr(nk) = bigl p in mathbb R^nn p = p^mathrmT p^2 = p operatornamerank(p) = k\n\nwith tangent space\n\nT_pmathrmGr(nk) = bigl\nX mathbb R^n n X=X^mathrmT text and X = pX+Xp bigr\n\nsee also ProjectorPoint and ProjectorTVector.\n\nThe manifold is named after Hermann G. Graßmann (1809-1877).\n\nA good overview can be found in[BendokatZimmermannAbsil2020].\n\nConstructor\n\nGrassmann(n,k,field=ℝ)\n\nGenerate the Grassmann manifold operatornameGr(nk), where the real-valued case field = ℝ is the default.\n\n[BendokatZimmermannAbsil2020]: T. Bendokat, R. Zimmermann, and P. -A. Absil: A Grassmann Manifold Handbook: Basic Geometry and Computational Aspects, arXiv preprint 2011.13699, 2020.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/grassmann.html#Base.convert-Tuple{Type{ProjectorPoint}, AbstractMatrix}","page":"Grassmann","title":"Base.convert","text":"convert(::Type{ProjectorPoint}, p::AbstractMatrix)\n\nConvert a point p on Stiefel that also represents a point (i.e. subspace) on Grassmann to a projector representation of said subspace, i.e. compute the canonical_project! for\n\n π^mathrmSG(p) = pp^mathrmT)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Base.convert-Tuple{Type{ProjectorPoint}, StiefelPoint}","page":"Grassmann","title":"Base.convert","text":"convert(::Type{ProjectorPoint}, ::Stiefelpoint)\n\nConvert a point p on Stiefel that also represents a point (i.e. subspace) on Grassmann to a projector representation of said subspace, i.e. compute the canonical_project! for\n\n π^mathrmSG(p) = pp^mathrmT\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Manifolds.get_total_space-Union{Tuple{Grassmann{n, k, 𝔽}}, Tuple{𝔽}, Tuple{k}, Tuple{n}} where {n, k, 𝔽}","page":"Grassmann","title":"Manifolds.get_total_space","text":"get_total_space(::Grassmann{n,k})\n\nReturn the total space of the Grassmann manifold, which is the corresponding Stiefel manifold, independent of whether the points are represented already in the total space or as ProjectorPoints.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.change_metric-Tuple{Grassmann, EuclideanMetric, Any, Any}","page":"Grassmann","title":"ManifoldsBase.change_metric","text":"change_metric(M::Grassmann, ::EuclideanMetric, p X)\n\nChange X to the corresponding vector with respect to the metric of the Grassmann M, which is just the identity, since the manifold is isometrically embedded.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.change_representer-Tuple{Grassmann, EuclideanMetric, Any, Any}","page":"Grassmann","title":"ManifoldsBase.change_representer","text":"change_representer(M::Grassmann, ::EuclideanMetric, p, X)\n\nChange X to the corresponding representer of a cotangent vector at p. Since the Grassmann manifold M, is isometrically embedded, this is the identity\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.default_retraction_method-Tuple{Grassmann, Type{ProjectorPoint}}","page":"Grassmann","title":"ManifoldsBase.default_retraction_method","text":"default_retraction_method(M::Grassmann, ::Type{ProjectorPoint})\n\nReturn ExponentialRetraction as the default on the Grassmann manifold with projection matrices\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.default_retraction_method-Tuple{Grassmann}","page":"Grassmann","title":"ManifoldsBase.default_retraction_method","text":"default_retraction_method(M::Grassmann)\ndefault_retraction_method(M::Grassmann, ::Type{StiefelPoint})\n\nReturn PolarRetracion as the default on the Grassmann manifold with projection matrices\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.default_vector_transport_method-Tuple{Grassmann}","page":"Grassmann","title":"ManifoldsBase.default_vector_transport_method","text":"default_vector_transport_method(M::Grassmann)\n\nReturn the ProjectionTransport as the default vector transport method for the Grassmann manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.injectivity_radius-Tuple{Grassmann}","page":"Grassmann","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::Grassmann)\ninjectivity_radius(M::Grassmann, p)\n\nReturn the injectivity radius on the Grassmann M, which is fracπ2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.is_flat-Tuple{Grassmann}","page":"Grassmann","title":"ManifoldsBase.is_flat","text":"is_flat(M::Grassmann)\n\nReturn true if Grassmann M is one-dimensional.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.manifold_dimension-Union{Tuple{Grassmann{n, k, 𝔽}}, Tuple{𝔽}, Tuple{k}, Tuple{n}} where {n, k, 𝔽}","page":"Grassmann","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::Grassmann)\n\nReturn the dimension of the Grassmann(n,k,𝔽) manifold M, i.e.\n\ndim operatornameGr(nk) = k(n-k) dim_ℝ 𝔽\n\nwhere dim_ℝ 𝔽 is the real_dimension of 𝔽.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Statistics.mean-Tuple{Grassmann, Vararg{Any}}","page":"Grassmann","title":"Statistics.mean","text":"mean(\n M::Grassmann,\n x::AbstractVector,\n [w::AbstractWeights,]\n method = GeodesicInterpolationWithinRadius(π/4);\n kwargs...,\n)\n\nCompute the Riemannian mean of x using GeodesicInterpolationWithinRadius.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#The-Grassmanian-represented-as-points-on-the-[Stiefel](@ref)-manifold","page":"Grassmann","title":"The Grassmanian represented as points on the Stiefel manifold","text":"","category":"section"},{"location":"manifolds/grassmann.html","page":"Grassmann","title":"Grassmann","text":"Modules = [Manifolds]\nPages = [\"manifolds/GrassmannStiefel.jl\"]\nOrder = [:type,:function]","category":"page"},{"location":"manifolds/grassmann.html#Manifolds.StiefelPoint","page":"Grassmann","title":"Manifolds.StiefelPoint","text":"StiefelPoint <: AbstractManifoldPoint\n\nA point on a Stiefel manifold. This point is mainly used for representing points on the Grassmann where this is also the default representation and hence equivalent to using AbstractMatrices thereon. they can also used be used as points on Stiefel.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/grassmann.html#Manifolds.StiefelTVector","page":"Grassmann","title":"Manifolds.StiefelTVector","text":"StiefelTVector <: TVector\n\nA tangent vector on the Grassmann manifold represented by a tangent vector from the tangent space of a corresponding point from the Stiefel manifold, see StiefelPoint. This is the default representation so is can be used interchangeably with just abstract matrices.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/grassmann.html#Base.exp-Tuple{Grassmann, Vararg{Any}}","page":"Grassmann","title":"Base.exp","text":"exp(M::Grassmann, p, X)\n\nCompute the exponential map on the Grassmann M= mathrmGr(nk) starting in p with tangent vector (direction) X. Let X = USV denote the SVD decomposition of X. Then the exponential map is written using\n\nz = p Vcos(S)V^mathrmH + Usin(S)V^mathrmH\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian and the cosine and sine are applied element wise to the diagonal entries of S. A final QR decomposition z=QR is performed for numerical stability reasons, yielding the result as\n\nexp_p X = Q\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Base.log-Tuple{Grassmann, Vararg{Any}}","page":"Grassmann","title":"Base.log","text":"log(M::Grassmann, p, q)\n\nCompute the logarithmic map on the Grassmann M$ = \\mathcal M=\\mathrm{Gr}(n,k)$, i.e. the tangent vector X whose corresponding geodesic starting from p reaches q after time 1 on M. The formula reads\n\nlog_p q = Vcdot operatornameatan(S) cdot U^mathrmH\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian. The matrices U and V are the unitary matrices, and S is the diagonal matrix containing the singular values of the SVD-decomposition\n\nUSV = (q^mathrmHp)^-1 ( q^mathrmH - q^mathrmHpp^mathrmH)\n\nIn this formula the operatornameatan is meant elementwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Base.rand-Tuple{Grassmann}","page":"Grassmann","title":"Base.rand","text":"rand(M::Grassmann; σ::Real=1.0, vector_at=nothing)\n\nWhen vector_at is nothing, return a random point p on Grassmann manifold M by generating a random (Gaussian) matrix with standard deviation σ in matching size, which is orthonormal.\n\nWhen vector_at is not nothing, return a (Gaussian) random vector from the tangent space T_pmathrmGr(nk) with mean zero and standard deviation σ by projecting a random Matrix onto the tangent space at vector_at.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldDiff.riemannian_Hessian-Tuple{Grassmann, Vararg{Any, 4}}","page":"Grassmann","title":"ManifoldDiff.riemannian_Hessian","text":"riemannian_Hessian(M::Grassmann, p, G, H, X)\n\nThe Riemannian Hessian can be computed by adopting Eq. (6.6) [Ngu23], where we use for the EuclideanMetric α_0=α_1=1 in their formula. Let nabla f(p) denote the Euclidean gradient G, nabla^2 f(p)X the Euclidean Hessian H. Then the formula reads\n\n operatornameHessf(p)X\n =\n operatornameproj_T_pmathcal MBigl(\n ^2f(p)X - X p^mathrmHf(p)\n Bigr)\n\nCompared to Eq. (5.6) also the metric conversion simplifies to the identity.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Manifolds.uniform_distribution-Union{Tuple{k}, Tuple{n}, Tuple{Grassmann{n, k, ℝ}, Any}} where {n, k}","page":"Grassmann","title":"Manifolds.uniform_distribution","text":"uniform_distribution(M::Grassmann{n,k,ℝ}, p)\n\nUniform distribution on given (real-valued) Grassmann M. Specifically, this is the normalized Haar measure on M. Generated points will be of similar type as p.\n\nThe implementation is based on Section 2.5.1 in [Chikuse2003]; see also Theorem 2.2.2(iii) in [Chikuse2003].\n\n[Chikuse2003]: Y. Chikuse: \"Statistics on Special Manifolds\", Springer New York, 2003, doi: 10.1007/978-0-387-21540-2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.distance-Tuple{Grassmann, Any, Any}","page":"Grassmann","title":"ManifoldsBase.distance","text":"distance(M::Grassmann, p, q)\n\nCompute the Riemannian distance on Grassmann manifold M= mathrmGr(nk).\n\nThe distance is given by\n\nd_mathrmGr(nk)(pq) = operatornamenorm(log_p(q))\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.inner-Tuple{Grassmann, Any, Any, Any}","page":"Grassmann","title":"ManifoldsBase.inner","text":"inner(M::Grassmann, p, X, Y)\n\nCompute the inner product for two tangent vectors X, Y from the tangent space of p on the Grassmann manifold M. The formula reads\n\ng_p(XY) = operatornametr(X^mathrmHY)\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.inverse_retract-Tuple{Grassmann, Any, Any, PolarInverseRetraction}","page":"Grassmann","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::Grassmann, p, q, ::PolarInverseRetraction)\n\nCompute the inverse retraction for the PolarRetraction, on the Grassmann manifold M, i.e.,\n\noperatornameretr_p^-1q = q*(p^mathrmHq)^-1 - p\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.inverse_retract-Tuple{Grassmann, Any, Any, QRInverseRetraction}","page":"Grassmann","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M, p, q, ::QRInverseRetraction)\n\nCompute the inverse retraction for the QRRetraction, on the Grassmann manifold M, i.e.,\n\noperatornameretr_p^-1q = q(p^mathrmHq)^-1 - p\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.project-Tuple{Grassmann, Any}","page":"Grassmann","title":"ManifoldsBase.project","text":"project(M::Grassmann, p)\n\nProject p from the embedding onto the Grassmann M, i.e. compute q as the polar decomposition of p such that q^mathrmHq is the identity, where cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.project-Tuple{Grassmann, Vararg{Any}}","page":"Grassmann","title":"ManifoldsBase.project","text":"project(M::Grassmann, p, X)\n\nProject the n-by-k X onto the tangent space of p on the Grassmann M, which is computed by\n\noperatornameproj_p(X) = X - pp^mathrmHX\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.representation_size-Union{Tuple{Grassmann{n, k}}, Tuple{k}, Tuple{n}} where {n, k}","page":"Grassmann","title":"ManifoldsBase.representation_size","text":"representation_size(M::Grassmann{n,k})\n\nReturn the represenation size or matrix dimension of a point on the Grassmann M, i.e. (nk) for both the real-valued and the complex value case.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.retract-Tuple{Grassmann, Any, Any, PolarRetraction}","page":"Grassmann","title":"ManifoldsBase.retract","text":"retract(M::Grassmann, p, X, ::PolarRetraction)\n\nCompute the SVD-based retraction PolarRetraction on the Grassmann M. With USV = p + X the retraction reads\n\noperatornameretr_p X = UV^mathrmH\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.retract-Tuple{Grassmann, Any, Any, QRRetraction}","page":"Grassmann","title":"ManifoldsBase.retract","text":"retract(M::Grassmann, p, X, ::QRRetraction )\n\nCompute the QR-based retraction QRRetraction on the Grassmann M. With QR = p + X the retraction reads\n\noperatornameretr_p X = QD\n\nwhere D is a m n matrix with\n\nD = operatornamediagleft( operatornamesgnleft(R_ii+frac12right)_i=1^n right)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.riemann_tensor-Union{Tuple{k}, Tuple{n}, Tuple{Grassmann{n, k, ℝ}, Vararg{Any, 4}}} where {n, k}","page":"Grassmann","title":"ManifoldsBase.riemann_tensor","text":"riemann_tensor(::Grassmann{n,k,ℝ}, p, X, Y, Z) where {n,k}\n\nCompute the value of Riemann tensor on the real Grassmann manifold. The formula reads[Rentmeesters2011] R(XY)Z = (XY^mathrmT - YX^mathrmT)Z + Z(Y^mathrmTX - X^mathrmTY).\n\n[Rentmeesters2011]: Q. Rentmeesters, “A gradient method for geodesic data fitting on some symmetric Riemannian manifolds,” in 2011 50th IEEE Conference on Decision and Control and European Control Conference, Dec. 2011, pp. 7141–7146. doi: 10.1109/CDC.2011.6161280.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.vector_transport_to-Tuple{Grassmann, Any, Any, Any, ProjectionTransport}","page":"Grassmann","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::Grassmann,p,X,q,::ProjectionTransport)\n\ncompute the projection based transport on the Grassmann M by interpreting X from the tangent space at p as a point in the embedding and projecting it onto the tangent space at q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.zero_vector-Tuple{Grassmann, Vararg{Any}}","page":"Grassmann","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::Grassmann, p)\n\nReturn the zero tangent vector from the tangent space at p on the Grassmann M, which is given by a zero matrix the same size as p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#The-Grassmannian-represented-as-projectors","page":"Grassmann","title":"The Grassmannian represented as projectors","text":"","category":"section"},{"location":"manifolds/grassmann.html","page":"Grassmann","title":"Grassmann","text":"Modules = [Manifolds]\nPages = [\"manifolds/GrassmannProjector.jl\"]\nOrder = [:type,:function]","category":"page"},{"location":"manifolds/grassmann.html#Manifolds.ProjectorPoint","page":"Grassmann","title":"Manifolds.ProjectorPoint","text":"ProjectorPoint <: AbstractManifoldPoint\n\nA type to represent points on a manifold Grassmann that are orthogonal projectors, i.e. a matrix p mathbb F^nn projecting onto a k-dimensional subspace.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/grassmann.html#Manifolds.ProjectorTVector","page":"Grassmann","title":"Manifolds.ProjectorTVector","text":"ProjectorTVector <: TVector\n\nA type to represent tangent vectors to points on a Grassmann manifold that are orthogonal projectors.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/grassmann.html#Base.exp-Tuple{Grassmann, ProjectorPoint, ProjectorTVector}","page":"Grassmann","title":"Base.exp","text":"exp(M::Grassmann, p::ProjectorPoint, X::ProjectorTVector)\n\nCompute the exponential map on the Grassmann as\n\n exp_pX = operatornameExp(Xp)poperatornameExp(-Xp)\n\nwhere operatornameExp denotes the matrix exponential and AB = AB-BA denotes the matrix commutator.\n\nFor details, see Proposition 3.2 in [BendokatZimmermannAbsil2020].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Manifolds.canonical_project!-Union{Tuple{k}, Tuple{n}, Tuple{Grassmann{n, k}, ProjectorPoint, Any}} where {n, k}","page":"Grassmann","title":"Manifolds.canonical_project!","text":"canonical_project!(M::Grassmann{n,k}, q::ProjectorPoint, p)\n\nCompute the canonical projection π(p) from the Stiefel manifold onto the Grassmann manifold when represented as ProjectorPoint, i.e.\n\n π^mathrmSG(p) = pp^mathrmT\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Manifolds.differential_canonical_project!-Union{Tuple{k}, Tuple{n}, Tuple{Grassmann{n, k}, ProjectorTVector, Any, Any}} where {n, k}","page":"Grassmann","title":"Manifolds.differential_canonical_project!","text":"canonical_project!(M::Grassmann{n,k}, q::ProjectorPoint, p)\n\nCompute the canonical projection π(p) from the Stiefel manifold onto the Grassmann manifold when represented as ProjectorPoint, i.e.\n\n Dπ^mathrmSG(p)X = Xp^mathrmT + pX^mathrmT\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Manifolds.horizontal_lift-Tuple{Stiefel, Any, ProjectorTVector}","page":"Grassmann","title":"Manifolds.horizontal_lift","text":"horizontal_lift(N::Stiefel{n,k}, q, X::ProjectorTVector)\n\nCompute the horizontal lift of X from the tangent space at p=π(q) on the Grassmann manifold, i.e.\n\nY = Xq T_qmathrmSt(nk)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{Grassmann{n, k, 𝔽}, ProjectorPoint}} where {n, k, 𝔽}","page":"Grassmann","title":"ManifoldsBase.check_point","text":"check_point(::Grassmann{n,k}, p::ProjectorPoint; kwargs...)\n\nCheck whether an orthogonal projector is a point from the Grassmann(n,k) manifold, i.e. the ProjectorPoint p mathbb F^nn, mathbb F mathbb R mathbb C has to fulfill p^mathrmT = p, p^2=p, and `\\operatorname{rank} p = k.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.check_size-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{Grassmann{n, k, 𝔽}, ProjectorPoint}} where {n, k, 𝔽}","page":"Grassmann","title":"ManifoldsBase.check_size","text":"check_size(M::Grassmann{n,k,𝔽}, p::ProjectorPoint; kwargs...) where {n,k}\n\nCheck that the ProjectorPoint is of correct size, i.e. from mathbb F^nn\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.check_vector-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{Grassmann{n, k, 𝔽}, ProjectorPoint, ProjectorTVector}} where {n, k, 𝔽}","page":"Grassmann","title":"ManifoldsBase.check_vector","text":"check_vector(::Grassmann{n,k,𝔽}, p::ProjectorPoint, X::ProjectorTVector; kwargs...) where {n,k,𝔽}\n\nCheck whether the ProjectorTVector X is from the tangent space T_poperatornameGr(nk) at the ProjectorPoint p on the Grassmann manifold operatornameGr(nk). This means that X has to be symmetric and that\n\nXp + pX = X\n\nmust hold, where the kwargs can be used to check both for symmetrix of X` and this equality up to a certain tolerance.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.get_embedding-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{Grassmann{n, k, 𝔽}, ProjectorPoint}} where {n, k, 𝔽}","page":"Grassmann","title":"ManifoldsBase.get_embedding","text":"get_embedding(M::Grassmann{n,k,𝔽}, p::ProjectorPoint) where {n,k,𝔽}\n\nReturn the embedding of the ProjectorPoint representation of the Grassmann manifold, i.e. the Euclidean space mathbb F^nn.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.parallel_transport_direction-Tuple{Grassmann, ProjectorPoint, ProjectorTVector, ProjectorTVector}","page":"Grassmann","title":"ManifoldsBase.parallel_transport_direction","text":"parallel_transport_direction(\n M::Grassmann,\n p::ProjectorPoint,\n X::ProjectorTVector,\n d::ProjectorTVector\n)\n\nCompute the parallel transport of X from the tangent space at p into direction d, i.e. to q=exp_pd. The formula is given in Proposition 3.5 of [BendokatZimmermannAbsil2020] as\n\nmathcalP_q p(X) = operatornameExp(dp)XoperatornameExp(-dp)\n\nwhere operatornameExp denotes the matrix exponential and AB = AB-BA denotes the matrix commutator.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#ManifoldsBase.representation_size-Union{Tuple{k}, Tuple{n}, Tuple{Grassmann{n, k}, ProjectorPoint}} where {n, k}","page":"Grassmann","title":"ManifoldsBase.representation_size","text":"representation_size(M::Grassmann{n,k}, p::ProjectorPoint)\n\nReturn the represenation size or matrix dimension of a point on the Grassmann M when using ProjectorPoints, i.e. (nn).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/grassmann.html#Literature","page":"Grassmann","title":"Literature","text":"","category":"section"},{"location":"manifolds/grassmann.html","page":"Grassmann","title":"Grassmann","text":"Pages = [\"manifolds/grassmann.md\"]\nCanonical=false","category":"page"},{"location":"misc/references.html#Literature","page":"References","title":"Literature","text":"","category":"section"},{"location":"misc/references.html","page":"References","title":"References","text":"We are slowly moving to using DocumenterCitatiosn.jl. The goal is to have all references used / mentioned in the documentation of Manifolds.jl also listed here. If you notice a reference still defined in a footnote, please change it into a BibTeX reference and open a PR","category":"page"},{"location":"misc/references.html","page":"References","title":"References","text":"Usually you will find a small reference section at the end of every documentation page that contains references for just that page.","category":"page"},{"location":"misc/references.html","page":"References","title":"References","text":"","category":"page"},{"location":"manifolds/essentialmanifold.html#Essential-Manifold","page":"Essential manifold","title":"Essential Manifold","text":"","category":"section"},{"location":"manifolds/essentialmanifold.html","page":"Essential manifold","title":"Essential manifold","text":"The essential manifold is modeled as an AbstractPowerManifold of the 3times3 Rotations and uses NestedPowerRepresentation.","category":"page"},{"location":"manifolds/essentialmanifold.html","page":"Essential manifold","title":"Essential manifold","text":"Modules = [Manifolds]\nPages = [\"manifolds/EssentialManifold.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/essentialmanifold.html#Manifolds.EssentialManifold","page":"Essential manifold","title":"Manifolds.EssentialManifold","text":"EssentialManifold <: AbstractPowerManifold{ℝ}\n\nThe essential manifold is the space of the essential matrices which is represented as a quotient space of the Rotations manifold product mathrmSO(3)^2.\n\nLet R_x(θ) R_y(θ) R_x(θ) in ℝ^xtimes 3 denote the rotation around the z, y, and x axis in ℝ^3, respectively, and further the groups\n\nH_z = bigl(R_z(θ)R_z(θ)) big θ -ππ) bigr\n\nand\n\nH_π = bigl (II) (R_x(π) R_x(π)) (IR_z(π)) (R_x(π) R_y(π)) bigr\n\nacting elementwise on the left from mathrmSO(3)^2 (component wise).\n\nThen the unsigned Essential manifold mathcalM_textE can be identified with the quotient space\n\nmathcalM_textE = (textSO(3)textSO(3))(H_z H_π)\n\nand for the signed Essential manifold mathcalM_textƎ, the quotient reads\n\nmathcalM_textƎ = (textSO(3)textSO(3))(H_z)\n\nAn essential matrix is defined as\n\nE = (R_1)^T T_2 - T_1_ R_2\n\nwhere the poses of two cameras (R_i T_i) i=12, are contained in the space of rigid body transformations SE(3) and the operator _colon ℝ^3 to operatornameSkewSym(3) denotes the matrix representation of the cross product operator. For more details see [TronDaniilidis2017].\n\nConstructor\n\nEssentialManifold(is_signed=true)\n\nGenerate the manifold of essential matrices, either the signed (is_signed=true) or unsigned (is_signed=false) variant.\n\n[TronDaniilidis2017]: Tron R.; Daniilidis K.; The Space of Essential Matrices as a Riemannian Quotient AbstractManifold. SIAM Journal on Imaging Sciences (2017), DOI: 10.1137/16M1091332, PDF: https://www.cis.upenn.edu/~kostas/mypub.dir/tron17siam.pdf.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/essentialmanifold.html#Functions","page":"Essential manifold","title":"Functions","text":"","category":"section"},{"location":"manifolds/essentialmanifold.html","page":"Essential manifold","title":"Essential manifold","text":"Modules = [Manifolds]\nPrivate = false\nPages = [\"manifolds/EssentialManifold.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/essentialmanifold.html#Base.exp-Tuple{EssentialManifold, Vararg{Any}}","page":"Essential manifold","title":"Base.exp","text":"exp(M::EssentialManifold, p, X)\n\nCompute the exponential map on the EssentialManifold from p into direction X, i.e.\n\ntextexp_p(X) =textexp_g( tilde X) quad g in text(SO)(3)^2\n\nwhere tilde X is the horizontal lift of X[TronDaniilidis2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#Base.log-Tuple{EssentialManifold, Any, Any}","page":"Essential manifold","title":"Base.log","text":"log(M::EssentialManifold, p, q)\n\nCompute the logarithmic map on the EssentialManifold M, i.e. the tangent vector, whose geodesic starting from p reaches q after time 1. Here, p=(R_p_1R_p_2) and q=(R_q_1R_q_2) are elements of SO(3)^2. We use that any essential matrix can, up to scale, be decomposed to\n\nE = R_1^T e_z_R_2\n\nwhere (R_1R_2)SO(3)^2. Two points in SO(3)^2 are equivalent iff their corresponding essential matrices are equal (up to a sign flip). To compute the logarithm, we first move q to another representative of its equivalence class. For this, we find t= t_textopt for which the function\n\nf(t) = f_1 + f_2 quad f_i = frac12 θ^2_i(t) quad θ_i(t)=d(R_p_iR_z(t)R_b_i) text for i=12\n\nwhere d() is the distance function in SO(3), is minimized. Further, the group H_z acting on the left on SO(3)^2 is defined as\n\nH_z = (R_z(θ)R_z(θ))colon θ in -ππ) \n\nwhere R_z(θ) is the rotation around the z axis with angle θ. Points in H_z are denoted by S_z. Then, the logarithm is defined as\n\nlog_p (S_z(t_textopt)q) = textLog(R_p_i^T R_z(t_textopt)R_b_i)_i=12\n\nwhere textLog is the logarithm on SO(3). For more details see [TronDaniilidis2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#ManifoldsBase.check_point-Tuple{EssentialManifold, Any}","page":"Essential manifold","title":"ManifoldsBase.check_point","text":"check_point(M::EssentialManifold, p; kwargs...)\n\nCheck whether the matrix is a valid point on the EssentialManifold M, i.e. a 2-element array containing SO(3) matrices.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#ManifoldsBase.check_vector-Tuple{EssentialManifold, Any, Any}","page":"Essential manifold","title":"ManifoldsBase.check_vector","text":"check_vector(M::EssentialManifold, p, X; kwargs... )\n\nCheck whether X is a tangent vector to manifold point p on the EssentialManifold M, i.e. X has to be a 2-element array of 3-by-3 skew-symmetric matrices.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#ManifoldsBase.distance-Tuple{EssentialManifold, Any, Any}","page":"Essential manifold","title":"ManifoldsBase.distance","text":"distance(M::EssentialManifold, p, q)\n\nCompute the Riemannian distance between the two points p and q on the EssentialManifold. This is done by computing the distance of the equivalence classes p and q of the points p=(R_p_1R_p_2) q=(R_q_1R_q_2) SO(3)^2, respectively. Two points in SO(3)^2 are equivalent iff their corresponding essential matrices, given by\n\nE = R_1^T e_z_R_2\n\nare equal (up to a sign flip). Using the logarithmic map, the distance is given by\n\ntextdist(pq) = textlog_p q = log_p (S_z(t_textopt)q) \n\nwhere S_z H_z = (R_z(θ)R_z(θ))colon θ in -ππ) in which R_z(θ) is the rotation around the z axis with angle θ and t_textopt is the minimizer of the cost function\n\nf(t) = f_1 + f_2 quad f_i = frac12 θ^2_i(t) quad θ_i(t)=d(R_p_iR_z(t)R_b_i) text for i=12\n\nwhere d() is the distance function in SO(3)[TronDaniilidis2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#ManifoldsBase.is_flat-Tuple{EssentialManifold}","page":"Essential manifold","title":"ManifoldsBase.is_flat","text":"is_flat(::EssentialManifold)\n\nReturn false. EssentialManifold is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#ManifoldsBase.manifold_dimension-Tuple{EssentialManifold}","page":"Essential manifold","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::EssentialManifold{is_signed, ℝ})\n\nReturn the manifold dimension of the EssentialManifold, which is 5[TronDaniilidis2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#ManifoldsBase.parallel_transport_to-Tuple{EssentialManifold, Any, Any, Any}","page":"Essential manifold","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::EssentialManifold, p, X, q)\n\nCompute the vector transport of the tangent vector X at p to q on the EssentialManifold M using left translation of the ambient group.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#ManifoldsBase.project-Tuple{EssentialManifold, Any, Any}","page":"Essential manifold","title":"ManifoldsBase.project","text":"project(M::EssentialManifold, p, X)\n\nProject the matrix X onto the tangent space\n\nT_p textSO(3)^2 = T_textvptextSO(3)^2 T_texthptextSO(3)^2\n\nby first computing its projection onto the vertical space T_textvptextSO(3)^2 using vert_proj. Then the orthogonal projection of X onto the horizontal space T_texthptextSO(3)^2 is defined as\n\nPi_h(X) = X - fractextvert_proj_p(X)2 beginbmatrix R_1^T e_z R_2^T e_z endbmatrix\n\nwith R_i = R_0 R_i i=12 where R_i is part of the pose of camera i g_i = (R_iT_i) textSE(3) and R_0 textSO(3) such that R_0(T_2-T_1) = e_z.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#Internal-Functions","page":"Essential manifold","title":"Internal Functions","text":"","category":"section"},{"location":"manifolds/essentialmanifold.html","page":"Essential manifold","title":"Essential manifold","text":"Modules = [Manifolds]\nPublic = false\nPages = [\"manifolds/EssentialManifold.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/essentialmanifold.html#Manifolds.dist_min_angle_pair-Tuple{Any, Any}","page":"Essential manifold","title":"Manifolds.dist_min_angle_pair","text":"dist_min_angle_pair(p, q)\n\nThis function computes the global minimizer of the function\n\nf(t) = f_1 + f_2 quad f_i = frac12 θ^2_i(t) quad θ_i(t)=d(R_p_iR_z(t)R_b_i) text for i=12\n\nfor the given values. This is done by finding the discontinuity points t_d_i i=12 of its derivative and using Newton's method to minimize the function over the intervals t_d_1t_d_2 and t_d_2t_d_1+2π separately. Then, the minimizer for which f is minimal is chosen and given back together with the minimal value. For more details see Algorithm 1 in [TronDaniilidis2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#Manifolds.dist_min_angle_pair_compute_df_break-Tuple{Any, Any}","page":"Essential manifold","title":"Manifolds.dist_min_angle_pair_compute_df_break","text":"dist_min_angle_pair_compute_df_break(t_break, q)\n\nThis function computes the derivatives of each term f_i i=12 at discontinuity point t_break. For more details see [TronDaniilidis2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#Manifolds.dist_min_angle_pair_df_newton-NTuple{9, Any}","page":"Essential manifold","title":"Manifolds.dist_min_angle_pair_df_newton","text":"dist_min_angle_pair_df_newton(m1, Φ1, c1, m2, Φ2, c2, t_min, t_low, t_high)\n\nThis function computes the minimizer of the function\n\nf(t) = f_1 + f_2 quad f_i = frac12 θ^2_i(t) quad θ_i(t)=d(R_p_iR_z(t)R_b_i) text for i=12\n\nin the interval t_low, t_high using Newton's method. For more details see [TronDaniilidis2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#Manifolds.dist_min_angle_pair_discontinuity_distance-Tuple{Any}","page":"Essential manifold","title":"Manifolds.dist_min_angle_pair_discontinuity_distance","text":"dist_min_angle_pair_discontinuity_distance(q)\n\nThis function computes the point t_textdi for which the first derivative of\n\nf(t) = f_1 + f_2 quad f_i = frac12 θ^2_i(t) quad θ_i(t)=d(R_p_iR_z(t)R_b_i) text for i=12\n\ndoes not exist. This is the case for sin(θ_i(t_textdi)) = 0. For more details see Proposition 9 and its proof, as well as Lemma 1 in [TronDaniilidis2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#Manifolds.vert_proj-Tuple{EssentialManifold, Any, Any}","page":"Essential manifold","title":"Manifolds.vert_proj","text":"vert_proj(M::EssentialManifold, p, X)\n\nProject X onto the vertical space T_textvptextSO(3)^2 with\n\ntextvert_proj_p(X) = e_z^T(R_1 X_1 + R_2 X_2)\n\nwhere e_z is the third unit vector, X_i T_ptextSO(3) for i=12 and it holds R_i = R_0 R_i i=12 where R_i is part of the pose of camera i g_i = (R_iT_i) textSE(3) and R_0 textSO(3) such that R_0(T_2-T_1) = e_z [TronDaniilidis2017].\n\n\n\n\n\n","category":"method"},{"location":"manifolds/essentialmanifold.html#Literature","page":"Essential manifold","title":"Literature","text":"","category":"section"},{"location":"manifolds/power.html#PowerManifoldSection","page":"Power manifold","title":"Power manifold","text":"","category":"section"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"A power manifold is based on a AbstractManifold mathcal M to build a mathcal M^n_1 times n_2 times cdots times n_m. In the case where m=1 we can represent a manifold-valued vector of data of length n_1, for example a time series. The case where m=2 is useful for representing manifold-valued matrices of data of size n_1 times n_2, for example certain types of images.","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"There are three available representations for points and vectors on a power manifold:","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"ArrayPowerRepresentation (the default one), very efficient but only applicable when points on the underlying manifold are represented using plain AbstractArrays.\nNestedPowerRepresentation, applicable to any manifold. It assumes that points on the underlying manifold are represented using mutable data types.\nNestedReplacingPowerRepresentation, applicable to any manifold. It does not mutate points on the underlying manifold, replacing them instead when appropriate.","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"Below are some examples of usage of these representations.","category":"page"},{"location":"manifolds/power.html#Example","page":"Power manifold","title":"Example","text":"","category":"section"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"There are two ways to store the data: in a multidimensional array or in a nested array.","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"Let's look at an example for both. Let mathcal M be Sphere(2) the 2-sphere and we want to look at vectors of length 4.","category":"page"},{"location":"manifolds/power.html#ArrayPowerRepresentation","page":"Power manifold","title":"ArrayPowerRepresentation","text":"","category":"section"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"For the default, the ArrayPowerRepresentation, we store the data in a multidimensional array,","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"using Manifolds\nM = PowerManifold(Sphere(2), 4)\np = cat([1.0, 0.0, 0.0],\n [1/sqrt(2.0), 1/sqrt(2.0), 0.0],\n [1/sqrt(2.0), 0.0, 1/sqrt(2.0)],\n [0.0, 1.0, 0.0]\n ,dims=2)","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"which is a valid point i.e.","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"is_point(M, p)","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"This can also be used in combination with HybridArrays.jl and StaticArrays.jl, by setting","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"using HybridArrays, StaticArrays\nq = HybridArray{Tuple{3,StaticArrays.Dynamic()},Float64,2}(p)","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"which is still a valid point on M and PowerManifold works with these, too.","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"An advantage of this representation is that it is quite efficient, especially when a HybridArray (from the HybridArrays.jl package) is used to represent a point on the power manifold. A disadvantage is not being able to easily identify parts of the multidimensional array that correspond to a single point on the base manifold. Another problem is, that accessing a single point is p[:, 1] which might be unintuitive.","category":"page"},{"location":"manifolds/power.html#NestedPowerRepresentation","page":"Power manifold","title":"NestedPowerRepresentation","text":"","category":"section"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"For the NestedPowerRepresentation we can now do","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"using Manifolds\nM = PowerManifold(Sphere(2), NestedPowerRepresentation(), 4)\np = [ [1.0, 0.0, 0.0],\n [1/sqrt(2.0), 1/sqrt(2.0), 0.0],\n [1/sqrt(2.0), 0.0, 1/sqrt(2.0)],\n [0.0, 1.0, 0.0],\n ]","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"which is again a valid point so is_point(M, p) here also yields true. A disadvantage might be that with nested arrays one loses a little bit of performance. The data however is nicely encapsulated. Accessing the first data item is just p[1].","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"For accessing points on power manifolds in both representations you can use get_component and set_component! functions. They work work both point representations.","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"using Manifolds\nM = PowerManifold(Sphere(2), NestedPowerRepresentation(), 4)\np = [ [1.0, 0.0, 0.0],\n [1/sqrt(2.0), 1/sqrt(2.0), 0.0],\n [1/sqrt(2.0), 0.0, 1/sqrt(2.0)],\n [0.0, 1.0, 0.0],\n ]\nset_component!(M, p, [0.0, 0.0, 1.0], 4)\nget_component(M, p, 4)","category":"page"},{"location":"manifolds/power.html#NestedReplacingPowerRepresentation","page":"Power manifold","title":"NestedReplacingPowerRepresentation","text":"","category":"section"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"The final representation is the NestedReplacingPowerRepresentation. It is similar to the NestedPowerRepresentation but it does not perform in-place operations on the points on the underlying manifold. The example below uses this representation to store points on a power manifold of the SpecialEuclidean group in-line in an Vector for improved efficiency. When having a mixture of both, i.e. an array structure that is nested (like ´NestedPowerRepresentation) in the sense that the elements of the main vector are immutable, then changing the elements can not be done in an in-place way and hence NestedReplacingPowerRepresentation has to be used.","category":"page"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"using Manifolds, StaticArrays\nR2 = Rotations(2)\n\nG = SpecialEuclidean(2)\nN = 5\nGN = PowerManifold(G, NestedReplacingPowerRepresentation(), N)\n\nq = [1.0 0.0; 0.0 1.0]\np1 = [ProductRepr(SVector{2,Float64}([i - 0.1, -i]), SMatrix{2,2,Float64}(exp(R2, q, hat(R2, q, i)))) for i in 1:N]\np2 = [ProductRepr(SVector{2,Float64}([i - 0.1, -i]), SMatrix{2,2,Float64}(exp(R2, q, hat(R2, q, -i)))) for i in 1:N]\n\nX = similar(p1);\n\nlog!(GN, X, p1, p2)","category":"page"},{"location":"manifolds/power.html#Types-and-Functions","page":"Power manifold","title":"Types and Functions","text":"","category":"section"},{"location":"manifolds/power.html","page":"Power manifold","title":"Power manifold","text":"Modules = [Manifolds]\nPages = [\"manifolds/PowerManifold.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/power.html#Manifolds.ArrayPowerRepresentation","page":"Power manifold","title":"Manifolds.ArrayPowerRepresentation","text":"ArrayPowerRepresentation\n\nRepresentation of points and tangent vectors on a power manifold using multidimensional arrays where first dimensions are equal to representation_size of the wrapped manifold and the following ones are equal to the number of elements in each direction.\n\nTorus uses this representation.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/power.html#Manifolds.PowerFVectorDistribution","page":"Power manifold","title":"Manifolds.PowerFVectorDistribution","text":"PowerFVectorDistribution([type::VectorBundleFibers], [x], distr)\n\nGenerates a random vector at a point from vector space (a fiber of a tangent bundle) of type type using the power distribution of distr.\n\nVector space type and point can be automatically inferred from distribution distr.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/power.html#Manifolds.PowerMetric","page":"Power manifold","title":"Manifolds.PowerMetric","text":"PowerMetric <: AbstractMetric\n\nRepresent the AbstractMetric on an AbstractPowerManifold, i.e. the inner product on the tangent space is the sum of the inner product of each elements tangent space of the power manifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/power.html#Manifolds.PowerPointDistribution","page":"Power manifold","title":"Manifolds.PowerPointDistribution","text":"PowerPointDistribution(M::AbstractPowerManifold, distribution)\n\nPower distribution on manifold M, based on distribution.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/power.html#Manifolds.flat-Tuple{AbstractPowerManifold, Vararg{Any}}","page":"Power manifold","title":"Manifolds.flat","text":"flat(M::AbstractPowerManifold, p, X)\n\nuse the musical isomorphism to transform the tangent vector X from the tangent space at p on an AbstractPowerManifold M to a cotangent vector. This can be done elementwise for each entry of X (and p).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/power.html#Manifolds.sharp-Tuple{AbstractPowerManifold, Vararg{Any}}","page":"Power manifold","title":"Manifolds.sharp","text":"sharp(M::AbstractPowerManifold, p, ξ::RieszRepresenterCotangentVector)\n\nUse the musical isomorphism to transform the cotangent vector ξ from the tangent space at p on an AbstractPowerManifold M to a tangent vector. This can be done elementwise for every entry of ξ (and p).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/power.html#ManifoldsBase.change_metric-Tuple{AbstractPowerManifold, AbstractMetric, Any, Any}","page":"Power manifold","title":"ManifoldsBase.change_metric","text":"change_metric(M::AbstractPowerManifold, ::AbstractMetric, p, X)\n\nSince the metric on a power manifold decouples, the change of metric can be done elementwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/power.html#ManifoldsBase.change_representer-Tuple{AbstractPowerManifold, AbstractMetric, Any, Any}","page":"Power manifold","title":"ManifoldsBase.change_representer","text":"change_representer(M::AbstractPowerManifold, ::AbstractMetric, p, X)\n\nSince the metric on a power manifold decouples, the change of a representer can be done elementwise\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#Rotations","page":"Rotations","title":"Rotations","text":"","category":"section"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"The manifold mathrmSO(n) of orthogonal matrices with determinant +1 in ℝ^n n, i.e.","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"mathrmSO(n) = biglR ℝ^n n big R R^mathrmT =\nR^mathrmTR = I_n det(R) = 1 bigr","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"The Lie group mathrmSO(n) is a subgroup of the orthogonal group mathrmO(n) and also known as the special orthogonal group or the set of rotations group. See also SpecialOrthogonal, which is this manifold equipped with the group operation.","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"The tangent space to a point p mathrmSO(n) is given by","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"T_pmathrmSO(n) = X X=pYqquad Y=-Y^mathrmT","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"i.e. all vectors that are a product of a skew symmetric matrix multiplied with p.","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"Since the orthogonal matrices mathrmSO(n) are a Lie group, tangent vectors can also be represented by elements of the corresponding Lie algebra, which is the tangent space at the identity element. In the notation above, this means we just store the component Y of X.","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"This convention allows for more efficient operations on tangent vectors. Tangent spaces at different points are different vector spaces.","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"Let L_R mathrmSO(n) mathrmSO(n) where R mathrmSO(n) be the left-multiplication by R, that is L_R(S) = RS. The tangent space at rotation R, T_R mathrmSO(n), is related to the tangent space at the identity rotation I_n by the differential of L_R at identity, (mathrmdL_R)_I_n T_I_n mathrmSO(n) T_R mathrmSO(n). To convert the tangent vector representation at the identity rotation X T_I_n mathrmSO(n) (i.e., the default) to the matrix representation of the corresponding tangent vector Y at a rotation R use the embed which implements the following multiplication: Y = RX T_R mathrmSO(n). You can compare the functions log and exp to see how it works in practice.","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"Several common functions are also implemented together with orthogonal and unitary matrices.","category":"page"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"Modules = [Manifolds]\nPages = [\"manifolds/Rotations.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/rotations.html#Manifolds.NormalRotationDistribution","page":"Rotations","title":"Manifolds.NormalRotationDistribution","text":"NormalRotationDistribution(M::Rotations, d::Distribution, x::TResult)\n\nDistribution that returns a random point on the manifold Rotations M. Random point is generated using base distribution d and the type of the result is adjusted to TResult.\n\nSee normal_rotation_distribution for details.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/rotations.html#Manifolds.Rotations","page":"Rotations","title":"Manifolds.Rotations","text":"Rotations{N} <: AbstractManifold{ℝ}\n\nThe manifold of rotation matrices of sice n n, i.e. real-valued orthogonal matrices with determinant +1.\n\nConstructor\n\nRotations(n)\n\nGenerate the manifold of n n rotation matrices.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/rotations.html#ManifoldDiff.riemannian_Hessian-Tuple{Rotations, Vararg{Any, 4}}","page":"Rotations","title":"ManifoldDiff.riemannian_Hessian","text":"riemannian_Hessian(M::Rotations, p, G, H, X)\n\nThe Riemannian Hessian can be computed by adopting Eq. (5.6) [Ngu23], so very similar to the Stiefel manifold. The only difference is, that here the tangent vectors are stored in the Lie algebra, u.e. the update direction is actually pX instead of jst X (in Stiefel). and that means the inverse has to be appliead to the (Euclidean) Hessian to map it into the Lie algebra.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#Manifolds.angles_4d_skew_sym_matrix-Tuple{Any}","page":"Rotations","title":"Manifolds.angles_4d_skew_sym_matrix","text":"angles_4d_skew_sym_matrix(A)\n\nThe Lie algebra of Rotations(4) in ℝ^4 4, 𝔰𝔬(4), consists of 4 4 skew-symmetric matrices. The unique imaginary components of their eigenvalues are the angles of the two plane rotations. This function computes these more efficiently than eigvals.\n\nBy convention, the returned values are sorted in decreasing order (corresponding to the same ordering of angles as cos_angles_4d_rotation_matrix).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#Manifolds.normal_rotation_distribution-Union{Tuple{N}, Tuple{Rotations{N}, Any, Real}} where N","page":"Rotations","title":"Manifolds.normal_rotation_distribution","text":"normal_rotation_distribution(M::Rotations, p, σ::Real)\n\nReturn a random point on the manifold Rotations M by generating a (Gaussian) random orthogonal matrix with determinant +1. Let\n\nQR = A\n\nbe the QR decomposition of a random matrix A, then the formula reads\n\np = QD\n\nwhere D is a diagonal matrix with the signs of the diagonal entries of R, i.e.\n\nD_ij=begincases operatornamesgn(R_ij) textif i=j 0 textotherwise endcases\n\nIt can happen that the matrix gets -1 as a determinant. In this case, the first and second columns are swapped.\n\nThe argument p is used to determine the type of returned points.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#ManifoldsBase.Weingarten-Tuple{Rotations, Any, Any, Any}","page":"Rotations","title":"ManifoldsBase.Weingarten","text":"Weingarten(M::Rotations, p, X, V)\n\nCompute the Weingarten map mathcal W_p at p on the Stiefel M with respect to the tangent vector X in T_pmathcal M and the normal vector V in N_pmathcal M.\n\nThe formula is due to [AMT13] given by\n\nmathcal W_p(XV) = -frac12pbigl(V^mathrmTX - X^mathrmTVbigr)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#ManifoldsBase.injectivity_radius-Tuple{Rotations, PolarRetraction}","page":"Rotations","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::Rotations, ::PolarRetraction)\n\nReturn the radius of injectivity for the PolarRetraction on the Rotations M which is fracπsqrt2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#ManifoldsBase.inverse_retract-Tuple{Rotations, Any, Any, PolarInverseRetraction}","page":"Rotations","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M, p, q, ::PolarInverseRetraction)\n\nCompute a vector from the tangent space T_pmathrmSO(n) of the point p on the Rotations manifold M with which the point q can be reached by the PolarRetraction from the point p after time 1.\n\nThe formula reads\n\noperatornameretr^-1_p(q)\n= -frac12(p^mathrmTqs - (p^mathrmTqs)^mathrmT)\n\nwhere s is the solution to the Sylvester equation\n\np^mathrmTqs + s(p^mathrmTq)^mathrmT + 2I_n = 0\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#ManifoldsBase.inverse_retract-Tuple{Rotations, Any, Any, QRInverseRetraction}","page":"Rotations","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::Rotations, p, q, ::QRInverseRetraction)\n\nCompute a vector from the tangent space T_pmathrmSO(n) of the point p on the Rotations manifold M with which the point q can be reached by the QRRetraction from the point q after time 1.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#ManifoldsBase.parallel_transport_direction-Tuple{Rotations, Any, Any, Any}","page":"Rotations","title":"ManifoldsBase.parallel_transport_direction","text":"parallel_transport_direction(M::Rotations, p, X, d)\n\nCompute parallel transport of vector X tangent at p on the Rotations manifold in the direction d. The formula, provided in [Rentmeesters2011], reads:\n\nmathcal P_qgets pX = q^mathrmTp operatornameExp(d2) X operatornameExp(d2)\n\nwhere q=exp_p d.\n\nThe formula simplifies to identity for 2-D rotations.\n\n[Rentmeesters2011]: Rentmeesters Q., “A gradient method for geodesic data fitting on some symmetric Riemannian manifolds,” in 2011 50th IEEE Conference on Decision and Control and European Control Conference, Dec. 2011, pp. 7141–7146. doi: 10.1109/CDC.2011.6161280.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#ManifoldsBase.project-Tuple{Rotations, Any}","page":"Rotations","title":"ManifoldsBase.project","text":"project(M::Rotations, p; check_det = true)\n\nProject p to the nearest point on manifold M.\n\nGiven the singular value decomposition p = U Σ V^mathrmT, with the singular values sorted in descending order, the projection is\n\noperatornameproj_mathrmSO(n)(p) =\nUoperatornamediagleft11det(U V^mathrmT)right V^mathrmT\n\nThe diagonal matrix ensures that the determinant of the result is +1. If p is expected to be almost special orthogonal, then you may avoid this check with check_det = false.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#ManifoldsBase.zero_vector-Tuple{Rotations, Any}","page":"Rotations","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::Rotations, p)\n\nReturn the zero tangent vector from the tangent space art p on the Rotations as an element of the Lie group, i.e. the zero matrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/rotations.html#Literature","page":"Rotations","title":"Literature","text":"","category":"section"},{"location":"manifolds/rotations.html","page":"Rotations","title":"Rotations","text":"Pages = [\"manifolds/rotations.md\"]\nCanonical=false","category":"page"},{"location":"manifolds/generalizedgrassmann.html#Generalized-Grassmann","page":"Generalized Grassmann","title":"Generalized Grassmann","text":"","category":"section"},{"location":"manifolds/generalizedgrassmann.html","page":"Generalized Grassmann","title":"Generalized Grassmann","text":"Modules = [Manifolds]\nPages = [\"manifolds/GeneralizedGrassmann.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/generalizedgrassmann.html#Manifolds.GeneralizedGrassmann","page":"Generalized Grassmann","title":"Manifolds.GeneralizedGrassmann","text":"GeneralizedGrassmann{n,k,𝔽} <: AbstractDecoratorManifold{𝔽}\n\nThe generalized Grassmann manifold operatornameGr(nkB) consists of all subspaces spanned by k linear independent vectors 𝔽^n, where 𝔽 ℝ ℂ is either the real- (or complex-) valued vectors. This yields all k-dimensional subspaces of ℝ^n for the real-valued case and all 2k-dimensional subspaces of ℂ^n for the second.\n\nThe manifold can be represented as\n\noperatornameGr(n k B) = bigl operatornamespan(p) big p 𝔽^n k p^mathrmHBp = I_k\n\nwhere cdot^mathrmH denotes the complex conjugate (or Hermitian) transpose and I_k is the k k identity matrix. This means, that the columns of p form an unitary basis of the subspace with respect to the scaled inner product, that is a point on operatornameGr(nkB), and hence the subspace can actually be represented by a whole equivalence class of representers. For B=I_n this simplifies to the Grassmann manifold.\n\nThe tangent space at a point (subspace) p is given by\n\nT_xmathrmGr(nkB) = bigl\nX 𝔽^n k \nX^mathrmHBp + p^mathrmHBX = 0_k bigr\n\nwhere 0_k denotes the k k zero matrix.\n\nNote that a point p operatornameGr(nkB) might be represented by different matrices (i.e. matrices with B-unitary column vectors that span the same subspace). Different representations of p also lead to different representation matrices for the tangent space T_pmathrmGr(nkB)\n\nThe manifold is named after Hermann G. Graßmann (1809-1877).\n\nConstructor\n\nGeneralizedGrassmann(n, k, B=I_n, field=ℝ)\n\nGenerate the (real-valued) Generalized Grassmann manifold of ntimes k dimensional orthonormal matrices with scalar product B.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/generalizedgrassmann.html#Base.exp-Tuple{GeneralizedGrassmann, Vararg{Any}}","page":"Generalized Grassmann","title":"Base.exp","text":"exp(M::GeneralizedGrassmann, p, X)\n\nCompute the exponential map on the GeneralizedGrassmann M= mathrmGr(nkB) starting in p with tangent vector (direction) X. Let X^mathrmHBX = USV denote the SVD decomposition of X^mathrmHBX. Then the exponential map is written using\n\nexp_p X = p Vcos(S)V^mathrmH + Usin(S)V^mathrmH\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian and the cosine and sine are applied element wise to the diagonal entries of S.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#Base.log-Tuple{GeneralizedGrassmann, Vararg{Any}}","page":"Generalized Grassmann","title":"Base.log","text":"log(M::GeneralizedGrassmann, p, q)\n\nCompute the logarithmic map on the GeneralizedGrassmann M$ = \\mathcal M=\\mathrm{Gr}(n,k,B)$, i.e. the tangent vector X whose corresponding geodesic starting from p reaches q after time 1 on M. The formula reads\n\nlog_p q = Vcdot operatornameatan(S) cdot U^mathrmH\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian. The matrices U and V are the unitary matrices, and S is the diagonal matrix containing the singular values of the SVD-decomposition\n\nUSV = (q^mathrmHBp)^-1 ( q^mathrmH - q^mathrmHBpp^mathrmH)\n\nIn this formula the operatornameatan is meant elementwise.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#Base.rand-Tuple{GeneralizedGrassmann}","page":"Generalized Grassmann","title":"Base.rand","text":"rand(::GeneralizedGrassmann; vector_at=nothing, σ::Real=1.0)\n\nWhen vector_at is nothing, return a random (Gaussian) point p on the GeneralizedGrassmann manifold M by generating a (Gaussian) matrix with standard deviation σ and return the (generalized) orthogonalized version, i.e. return the projection onto the manifold of the Q component of the QR decomposition of the random matrix of size nk.\n\nWhen vector_at is not nothing, return a (Gaussian) random vector from the tangent space T_vector_atmathrmSt(nk) with mean zero and standard deviation σ by projecting a random Matrix onto the tangent vector at vector_at.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.change_metric-Tuple{GeneralizedGrassmann, EuclideanMetric, Any, Any}","page":"Generalized Grassmann","title":"ManifoldsBase.change_metric","text":"change_metric(M::GeneralizedGrassmann, ::EuclideanMetric, p X)\n\nChange X to the corresponding vector with respect to the metric of the GeneralizedGrassmann M, i.e. let B=LL be the Cholesky decomposition of the matrix M.B, then the corresponding vector is LX.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.change_representer-Tuple{GeneralizedGrassmann, EuclideanMetric, Any, Any}","page":"Generalized Grassmann","title":"ManifoldsBase.change_representer","text":"change_representer(M::GeneralizedGrassmann, ::EuclideanMetric, p, X)\n\nChange X to the corresponding representer of a cotangent vector at p with respect to the scaled metric of the GeneralizedGrassmann M, i.e, since\n\ng_p(XY) = operatornametr(Y^mathrmHBZ) = operatornametr(X^mathrmHZ) = XZ\n\nhas to hold for all Z, where the repreenter X is given, the resulting representer with respect to the metric on the GeneralizedGrassmann is given by Y = B^-1X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{GeneralizedGrassmann{n, k, 𝔽}, Any}} where {n, k, 𝔽}","page":"Generalized Grassmann","title":"ManifoldsBase.check_point","text":"check_point(M::GeneralizedGrassmann{n,k,𝔽}, p)\n\nCheck whether p is representing a point on the GeneralizedGrassmann M, i.e. its a n-by-k matrix of unitary column vectors with respect to the B inner prudct and of correct eltype with respect to 𝔽.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.check_vector-Union{Tuple{𝔽}, Tuple{k}, Tuple{n}, Tuple{GeneralizedGrassmann{n, k, 𝔽}, Any, Any}} where {n, k, 𝔽}","page":"Generalized Grassmann","title":"ManifoldsBase.check_vector","text":"check_vector(M::GeneralizedGrassmann{n,k,𝔽}, p, X; kwargs...)\n\nCheck whether X is a tangent vector in the tangent space of p on the GeneralizedGrassmann M, i.e. that X is of size and type as well as that\n\n p^mathrmHBX + overlineX^mathrmHBp = 0_k\n\nwhere cdot^mathrmH denotes the complex conjugate transpose or Hermitian, overlinecdot the (elementwise) complex conjugate, and 0_k denotes the k k zero natrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.distance-Tuple{GeneralizedGrassmann, Any, Any}","page":"Generalized Grassmann","title":"ManifoldsBase.distance","text":"distance(M::GeneralizedGrassmann, p, q)\n\nCompute the Riemannian distance on GeneralizedGrassmann manifold M= mathrmGr(nkB).\n\nThe distance is given by\n\nd_mathrmGr(nkB)(pq) = operatornamenorm(log_p(q))\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.injectivity_radius-Tuple{GeneralizedGrassmann}","page":"Generalized Grassmann","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::GeneralizedGrassmann)\ninjectivity_radius(M::GeneralizedGrassmann, p)\n\nReturn the injectivity radius on the GeneralizedGrassmann M, which is fracπ2.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.inner-Union{Tuple{k}, Tuple{n}, Tuple{GeneralizedGrassmann{n, k}, Any, Any, Any}} where {n, k}","page":"Generalized Grassmann","title":"ManifoldsBase.inner","text":"inner(M::GeneralizedGrassmann, p, X, Y)\n\nCompute the inner product for two tangent vectors X, Y from the tangent space of p on the GeneralizedGrassmann manifold M. The formula reads\n\ng_p(XY) = operatornametr(X^mathrmHBY)\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.is_flat-Tuple{GeneralizedGrassmann}","page":"Generalized Grassmann","title":"ManifoldsBase.is_flat","text":"is_flat(M::GeneralizedGrassmann)\n\nReturn true if GeneralizedGrassmann M is one-dimensional.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.manifold_dimension-Union{Tuple{GeneralizedGrassmann{n, k, 𝔽}}, Tuple{𝔽}, Tuple{k}, Tuple{n}} where {n, k, 𝔽}","page":"Generalized Grassmann","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::GeneralizedGrassmann)\n\nReturn the dimension of the GeneralizedGrassmann(n,k,𝔽) manifold M, i.e.\n\ndim operatornameGr(nkB) = k(n-k) dim_ℝ 𝔽\n\nwhere dim_ℝ 𝔽 is the real_dimension of 𝔽.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.project-Tuple{GeneralizedGrassmann, Any, Any}","page":"Generalized Grassmann","title":"ManifoldsBase.project","text":"project(M::GeneralizedGrassmann, p, X)\n\nProject the n-by-k X onto the tangent space of p on the GeneralizedGrassmann M, which is computed by\n\noperatornameproj_p(X) = X - pp^mathrmHB^mathrmTX\n\nwhere cdot^mathrmH denotes the complex conjugate transposed or Hermitian and cdot^mathrmT the transpose.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.project-Tuple{GeneralizedGrassmann, Any}","page":"Generalized Grassmann","title":"ManifoldsBase.project","text":"project(M::GeneralizedGrassmann, p)\n\nProject p from the embedding onto the GeneralizedGrassmann M, i.e. compute q as the polar decomposition of p such that q^mathrmHBq is the identity, where cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transpose.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.representation_size-Union{Tuple{GeneralizedGrassmann{n, k}}, Tuple{k}, Tuple{n}} where {n, k}","page":"Generalized Grassmann","title":"ManifoldsBase.representation_size","text":"representation_size(M::GeneralizedGrassmann{n,k})\n\nReturn the represenation size or matrix dimension of a point on the GeneralizedGrassmann M, i.e. (nk) for both the real-valued and the complex value case.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.retract-Tuple{GeneralizedGrassmann, Any, Any, PolarRetraction}","page":"Generalized Grassmann","title":"ManifoldsBase.retract","text":"retract(M::GeneralizedGrassmann, p, X, ::PolarRetraction)\n\nCompute the SVD-based retraction PolarRetraction on the GeneralizedGrassmann M, by projecting p + X onto M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#ManifoldsBase.zero_vector-Tuple{GeneralizedGrassmann, Vararg{Any}}","page":"Generalized Grassmann","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::GeneralizedGrassmann, p)\n\nReturn the zero tangent vector from the tangent space at p on the GeneralizedGrassmann M, which is given by a zero matrix the same size as p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/generalizedgrassmann.html#Statistics.mean-Tuple{GeneralizedGrassmann, Vararg{Any}}","page":"Generalized Grassmann","title":"Statistics.mean","text":"mean(\n M::GeneralizedGrassmann,\n x::AbstractVector,\n [w::AbstractWeights,]\n method = GeodesicInterpolationWithinRadius(π/4);\n kwargs...,\n)\n\nCompute the Riemannian mean of x using GeodesicInterpolationWithinRadius.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/skewhermitian.html#Skew-hermitian-matrices","page":"Skew-Hermitian matrices","title":"Skew-hermitian matrices","text":"","category":"section"},{"location":"manifolds/skewhermitian.html","page":"Skew-Hermitian matrices","title":"Skew-Hermitian matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/SkewHermitian.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/skewhermitian.html#Manifolds.SkewHermitianMatrices","page":"Skew-Hermitian matrices","title":"Manifolds.SkewHermitianMatrices","text":"SkewHermitianMatrices{n,𝔽} <: AbstractDecoratorManifold{𝔽}\n\nThe AbstractManifold $ \\operatorname{SkewHerm}(n)$ consisting of the real- or complex-valued skew-hermitian matrices of size n n, i.e. the set\n\noperatornameSkewHerm(n) = biglp 𝔽^n n big p^mathrmH = -p bigr\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transpose, and the field 𝔽 ℝ ℂ ℍ.\n\nThough it is slightly redundant, usually the matrices are stored as n n arrays.\n\nNote that in this representation, the real-valued part of the diagonal must be zero, which is also reflected in the manifold_dimension.\n\nConstructor\n\nSkewHermitianMatrices(n::Int, field::AbstractNumbers=ℝ)\n\nGenerate the manifold of n n skew-hermitian matrices.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/skewhermitian.html#Manifolds.SkewSymmetricMatrices","page":"Skew-Hermitian matrices","title":"Manifolds.SkewSymmetricMatrices","text":"SkewSymmetricMatrices{n}\n\nGenerate the manifold of n n real skew-symmetric matrices. This is equivalent to SkewHermitianMatrices(n, ℝ).\n\nConstructor\n\nSkewSymmetricMatrices(n::Int)\n\n\n\n\n\n","category":"type"},{"location":"manifolds/skewhermitian.html#ManifoldsBase.check_point-Union{Tuple{𝔽}, Tuple{n}, Tuple{SkewHermitianMatrices{n, 𝔽}, Any}} where {n, 𝔽}","page":"Skew-Hermitian matrices","title":"ManifoldsBase.check_point","text":"check_point(M::SkewHermitianMatrices{n,𝔽}, p; kwargs...)\n\nCheck whether p is a valid manifold point on the SkewHermitianMatrices M, i.e. whether p is a skew-hermitian matrix of size (n,n) with values from the corresponding AbstractNumbers 𝔽.\n\nThe tolerance for the skew-symmetry of p can be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/skewhermitian.html#ManifoldsBase.check_vector-Tuple{SkewHermitianMatrices, Any, Any}","page":"Skew-Hermitian matrices","title":"ManifoldsBase.check_vector","text":"check_vector(M::SkewHermitianMatrices{n}, p, X; kwargs... )\n\nCheck whether X is a tangent vector to manifold point p on the SkewHermitianMatrices M, i.e. X must be a skew-hermitian matrix of size (n,n) and its values have to be from the correct AbstractNumbers. The tolerance for the skew-symmetry of p and X can be set using kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/skewhermitian.html#ManifoldsBase.is_flat-Tuple{SkewHermitianMatrices}","page":"Skew-Hermitian matrices","title":"ManifoldsBase.is_flat","text":"is_flat(::SkewHermitianMatrices)\n\nReturn true. SkewHermitianMatrices is a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/skewhermitian.html#ManifoldsBase.manifold_dimension-Union{Tuple{SkewHermitianMatrices{N, 𝔽}}, Tuple{𝔽}, Tuple{N}} where {N, 𝔽}","page":"Skew-Hermitian matrices","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::SkewHermitianMatrices{n,𝔽})\n\nReturn the dimension of the SkewHermitianMatrices matrix M over the number system 𝔽, i.e.\n\ndim mathrmSkewHerm(nℝ) = fracn(n+1)2 dim_ℝ 𝔽 - n\n\nwhere dim_ℝ 𝔽 is the real_dimension of 𝔽. The first term corresponds to only the upper triangular elements of the matrix being unique, and the second term corresponds to the constraint that the real part of the diagonal be zero.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/skewhermitian.html#ManifoldsBase.project-Tuple{SkewHermitianMatrices, Any, Any}","page":"Skew-Hermitian matrices","title":"ManifoldsBase.project","text":"project(M::SkewHermitianMatrices, p, X)\n\nProject the matrix X onto the tangent space at p on the SkewHermitianMatrices M,\n\noperatornameproj_p(X) = frac12 bigl( X - X^mathrmH bigr)\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/skewhermitian.html#ManifoldsBase.project-Tuple{SkewHermitianMatrices, Any}","page":"Skew-Hermitian matrices","title":"ManifoldsBase.project","text":"project(M::SkewHermitianMatrices, p)\n\nProjects p from the embedding onto the SkewHermitianMatrices M, i.e.\n\noperatornameproj_operatornameSkewHerm(n)(p) = frac12 bigl( p - p^mathrmH bigr)\n\nwhere cdot^mathrmH denotes the Hermitian, i.e. complex conjugate transposed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#Tucker","page":"Tucker","title":"Tucker manifold","text":"","category":"section"},{"location":"manifolds/tucker.html","page":"Tucker","title":"Tucker","text":"Modules = [Manifolds]\nPages = [\"Tucker.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/tucker.html#Manifolds.Tucker","page":"Tucker","title":"Manifolds.Tucker","text":"Tucker{N, R, D, 𝔽} <: AbstractManifold{𝔽}\n\nThe manifold of N_1 times dots times N_D real-valued or complex-valued tensors of fixed multilinear rank (R_1 dots R_D) . If R_1 = dots = R_D = 1, this is the Segre manifold, i.e., the set of rank-1 tensors.\n\nRepresentation in HOSVD format\n\nLet mathbbF be the real or complex numbers. Any tensor p on the Tucker manifold can be represented as a multilinear product in HOSVD [DeLathauwer2000] form\n\np = (U_1dotsU_D) cdot mathcalC\n\nwhere mathcal C in mathbbF^R_1 times dots times R_D and, for d=1dotsD, the matrix U_d in mathbbF^N_d times R_d contains the singular vectors of the dth unfolding of mathcalA\n\nTangent space\n\nThe tangent space to the Tucker manifold at p = (U_1dotsU_D) cdot mathcalC is [Koch2010]\n\nT_p mathcalM =\nbigl\n(U_1dotsU_D) cdot mathcalC^prime\n+ sum_d=1^D bigl(\n (U_1 dots U_d-1 U_d^prime U_d+1 dots U_D)\n cdot mathcalC\nbigr)\nbigr\n\nwhere mathcalC^prime is arbitrary, U_d^mathrmH is the Hermitian adjoint of U_d, and U_d^mathrmH U_d^prime = 0 for all d.\n\nConstructor\n\nTucker(N::NTuple{D, Int}, R::NTuple{D, Int}[, field = ℝ])\n\nGenerate the manifold of field-valued tensors of dimensions N[1] × … × N[D] and multilinear rank R = (R[1], …, R[D]).\n\n[DeLathauwer2000]: Lieven De Lathauwer, Bart De Moor, Joos Vandewalle: \"A multilinear singular value decomposition\" SIAM Journal on Matrix Analysis and Applications, 21(4), pp. 1253-1278, 2000 doi: 10.1137/S0895479896305696\n\n[Koch2010]: Othmar Koch, Christian Lubic, \"Dynamical Tensor approximation\" SIAM Journal on Matrix Analysis and Applications, 31(5), pp. 2360-2375, 2010 doi: 10.1137/09076578X\n\n\n\n\n\n","category":"type"},{"location":"manifolds/tucker.html#Manifolds.TuckerPoint","page":"Tucker","title":"Manifolds.TuckerPoint","text":"TuckerPoint{T,D}\n\nAn order D tensor of fixed multilinear rank and entries of type T, which makes it a point on the Tucker manifold. The tensor is represented in HOSVD form.\n\nConstructors:\n\nTuckerPoint(core::AbstractArray{T,D}, factors::Vararg{<:AbstractMatrix{T},D}) where {T,D}\n\nConstruct an order D tensor of element type T that can be represented as the multilinear product (factors[1], …, factors[D]) ⋅ core. It is assumed that the dimensions of the core are the multilinear rank of the tensor and that the matrices factors each have full rank. No further assumptions are made.\n\nTuckerPoint(p::AbstractArray{T,D}, mlrank::NTuple{D,Int}) where {T,D}\n\nThe low-multilinear rank tensor arising from the sequentially truncated the higher-order singular value decomposition of the D-dimensional array p of type T. The singular values are truncated to get a multilinear rank mlrank [Vannieuwenhoven2012].\n\n[Vannieuwenhoven2012]: Nick Vannieuwenhoven, Raf Vandebril, Karl Meerbergen: \"A new truncation strategy for the higher-order singular value decomposition\" SIAM Journal on Scientific Computing, 34(2), pp. 1027-1052, 2012 doi: 10.1137/110836067\n\n\n\n\n\n","category":"type"},{"location":"manifolds/tucker.html#Manifolds.TuckerTVector","page":"Tucker","title":"Manifolds.TuckerTVector","text":"TuckerTVector{T, D} <: TVector\n\nTangent vector to the D-th order Tucker manifold at p = (U_1dotsU_D) mathcalC. The numbers are of type T and the vector is represented as\n\nX =\n(U_1dotsU_D) cdot mathcalC^prime +\nsum_d=1^D (U_1dotsU_d-1U_d^primeU_d+1dotsU_D) cdot mathcalC\n\nwhere U_d^mathrmH U_d^prime = 0.\n\nConstructor\n\nTuckerTVector(C′::Array{T,D}, U′::NTuple{D,Matrix{T}}) where {T,D}\n\nConstructs a Dth order TuckerTVector of number type T with C^prime and U^prime, so that, together with a TuckerPoint p as above, the tangent vector can be represented as X in the above expression.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/tucker.html#Base.convert-Union{Tuple{D}, Tuple{T}, Tuple{𝔽}, Tuple{Type{Matrix{T}}, CachedBasis{𝔽, DefaultOrthonormalBasis{𝔽, ManifoldsBase.TangentSpaceType}, Manifolds.HOSVDBasis{T, D}}}} where {𝔽, T, D}","page":"Tucker","title":"Base.convert","text":"Base.convert(::Type{Matrix{T}}, basis::CachedBasis{𝔽,DefaultOrthonormalBasis{𝔽, TangentSpaceType},HOSVDBasis{T, D}}) where {𝔽, T, D}\nBase.convert(::Type{Matrix}, basis::CachedBasis{𝔽,DefaultOrthonormalBasis{𝔽, TangentSpaceType},HOSVDBasis{T, D}}) where {𝔽, T, D}\n\nConvert a HOSVD-derived cached basis from [Dewaele2021] of the Dth order Tucker manifold with number type T to a matrix. The columns of this matrix are the vectorisations of the embeddings of the basis vectors.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#Base.foreach","page":"Tucker","title":"Base.foreach","text":"Base.foreach(f, M::Tucker, p::TuckerPoint, basis::AbstractBasis, indices=1:manifold_dimension(M))\n\nLet basis be and AbstractBasis at a point p on M. Suppose f is a function that takes an index and a vector as an argument. This function applies f to i and the ith basis vector sequentially for each i in indices. Using a CachedBasis may speed up the computation.\n\nNOTE: The i'th basis vector is overwritten in each iteration. If any information about the vector is to be stored, f must make a copy.\n\n\n\n\n\n","category":"function"},{"location":"manifolds/tucker.html#Base.ndims-Union{Tuple{TuckerPoint{T, D}}, Tuple{D}, Tuple{T}} where {T, D}","page":"Tucker","title":"Base.ndims","text":"Base.ndims(p::TuckerPoint{T,D}) where {T,D}\n\nThe order of the tensor corresponding to the TuckerPoint p, i.e., D.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#Base.size-Tuple{TuckerPoint}","page":"Tucker","title":"Base.size","text":"Base.size(p::TuckerPoint)\n\nThe dimensions of a TuckerPoint p, when regarded as a full tensor (see embed).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.check_point-Union{Tuple{D}, Tuple{R}, Tuple{N}, Tuple{Tucker{N, R, D}, Any}} where {N, R, D}","page":"Tucker","title":"ManifoldsBase.check_point","text":"check_point(M::Tucker{N,R,D}, p; kwargs...) where {N,R,D}\n\nCheck whether the multidimensional array or TuckerPoint p is a point on the Tucker manifold, i.e. it is a Dth order N[1] × … × N[D] tensor of multilinear rank (R[1], …, R[D]). The keyword arguments are passed to the matrix rank function applied to the unfoldings. For a TuckerPoint it is checked that the point is in correct HOSVD form.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.check_vector-Union{Tuple{D}, Tuple{T}, Tuple{R}, Tuple{N}, Tuple{Tucker{N, R, D}, TuckerPoint{T, D}, TuckerTVector}} where {N, R, T, D}","page":"Tucker","title":"ManifoldsBase.check_vector","text":"check_vector(M::Tucker{N,R,D}, p::TuckerPoint{T,D}, X::TuckerTVector) where {N,R,T,D}\n\nCheck whether a TuckerTVector X is is in the tangent space to the Dth order Tucker manifold M at the Dth order TuckerPoint p. This is the case when the dimensions of the factors in X agree with those of p and the factor matrices of X are in the orthogonal complement of the HOSVD factors of p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.embed-Tuple{Tucker, Any, TuckerPoint}","page":"Tucker","title":"ManifoldsBase.embed","text":"embed(::Tucker{N,R,D}, p::TuckerPoint) where {N,R,D}\n\nConvert a TuckerPoint p on the rank R Tucker manifold to a full N[1] × … × N[D]-array by evaluating the Tucker decomposition.\n\nembed(::Tucker{N,R,D}, p::TuckerPoint, X::TuckerTVector) where {N,R,D}\n\nConvert a tangent vector X with base point p on the rank R Tucker manifold to a full tensor, represented as an N[1] × … × N[D]-array.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.get_basis-Union{Tuple{𝔽}, Tuple{Tucker, TuckerPoint}, Tuple{Tucker, TuckerPoint, DefaultOrthonormalBasis{𝔽, ManifoldsBase.TangentSpaceType}}} where 𝔽","page":"Tucker","title":"ManifoldsBase.get_basis","text":"get_basis(:: Tucker, p::TuckerPoint, basisType::DefaultOrthonormalBasis{𝔽, TangentSpaceType}) where 𝔽\n\nAn implicitly stored basis of the tangent space to the Tucker manifold. Assume p = (U_1dotsU_D) cdot mathcalC is in HOSVD format and that, for d=1dotsD, the singular values of the d'th unfolding are sigma_dj, with j = 1dotsR_d. The basis of the tangent space is as follows: [Dewaele2021]\n\nbigl\n(U_1dotsU_D) e_i\nbigr cup bigl\n(U_1dots sigma_dj^-1 U_d^perp e_i e_j^TdotsU_D) cdot mathcalC\nbigr\n\nfor all d = 1dotsD and all canonical basis vectors e_i and e_j. Every U_d^perp is such that U_d quad U_d^perp forms an orthonormal basis of mathbbR^N_d.\n\n[Dewaele2021]: Nick Dewaele, Paul Breiding, Nick Vannieuwenhoven, \"The condition number of many tensor decompositions is invariant under Tucker compression\" arxiv: 2106.13034\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.inner-Tuple{Tucker, TuckerPoint, TuckerTVector, TuckerTVector}","page":"Tucker","title":"ManifoldsBase.inner","text":"inner(M::Tucker, p::TuckerPoint, X::TuckerTVector, Y::TuckerTVector)\n\nThe Euclidean inner product between tangent vectors X and X at the point p on the Tucker manifold. This is equal to embed(M, p, X) ⋅ embed(M, p, Y).\n\ninner(::Tucker, A::TuckerPoint, X::TuckerTVector, Y)\ninner(::Tucker, A::TuckerPoint, X, Y::TuckerTVector)\n\nThe Euclidean inner product between X and Y where X is a vector tangent to the Tucker manifold at p and Y is a vector in the ambient space or vice versa. The vector in the ambient space is represented as a full tensor, i.e., a multidimensional array.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.inverse_retract-Tuple{Tucker, Any, TuckerPoint, TuckerPoint, ProjectionInverseRetraction}","page":"Tucker","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::Tucker, p::TuckerPoint, q::TuckerPoint, ::ProjectionInverseRetraction)\n\nThe projection inverse retraction on the Tucker manifold interprets q as a point in the ambient Euclidean space (see embed) and projects it onto the tangent space at to M at p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.is_flat-Tuple{Tucker}","page":"Tucker","title":"ManifoldsBase.is_flat","text":"is_flat(::Tucker)\n\nReturn false. Tucker is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.manifold_dimension-Union{Tuple{Tucker{n⃗, r⃗}}, Tuple{r⃗}, Tuple{n⃗}} where {n⃗, r⃗}","page":"Tucker","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(::Tucker{N,R,D}) where {N,R,D}\n\nThe dimension of the manifold of N_1 times dots times N_D tensors of multilinear rank (R_1 dots R_D), i.e.\n\nmathrmdim(mathcalM) = prod_d=1^D R_d + sum_d=1^D R_d (N_d - R_d)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.project-Tuple{Tucker, Any, TuckerPoint, Any}","page":"Tucker","title":"ManifoldsBase.project","text":"project(M::Tucker, p::TuckerPoint, X)\n\nThe least-squares projection of a dense tensor X onto the tangent space to M at p.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.retract-Tuple{Tucker, Any, Any, PolarRetraction}","page":"Tucker","title":"ManifoldsBase.retract","text":"retract(::Tucker, p::TuckerPoint, X::TuckerTVector, ::PolarRetraction)\n\nThe truncated HOSVD-based retraction [Kressner2014] to the Tucker manifold, i.e. the result is the sequentially tuncated HOSVD approximation of p + X.\n\nIn the exceptional case that the multilinear rank of p + X is lower than that of p, this retraction produces a boundary point, which is outside the manifold.\n\n[Kressner2014]: Daniel Kressner, Michael Steinlechner, Bart Vandereycken: \"Low-rank tensor completion by Riemannian optimization\" BIT Numerical Mathematics, 54(2), pp. 447-468, 2014 doi: 10.1007/s10543-013-0455-z\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#ManifoldsBase.zero_vector-Tuple{Tucker, TuckerPoint}","page":"Tucker","title":"ManifoldsBase.zero_vector","text":"zero_vector(::Tucker, p::TuckerPoint)\n\nThe zero element in the tangent space to p on the Tucker manifold, represented as a TuckerTVector.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/tucker.html#Literature","page":"Tucker","title":"Literature","text":"","category":"section"},{"location":"manifolds/elliptope.html#Elliptope","page":"Elliptope","title":"Elliptope","text":"","category":"section"},{"location":"manifolds/elliptope.html","page":"Elliptope","title":"Elliptope","text":"Modules = [Manifolds]\nPages = [\"manifolds/Elliptope.jl\"]\nOrder = [:type,:function]","category":"page"},{"location":"manifolds/elliptope.html#Manifolds.Elliptope","page":"Elliptope","title":"Manifolds.Elliptope","text":"Elliptope{N,K} <: AbstractDecoratorManifold{ℝ}\n\nThe Elliptope manifold, also known as the set of correlation matrices, consists of all symmetric positive semidefinite matrices of rank k with unit diagonal, i.e.,\n\nbeginaligned\nmathcal E(nk) =\nbiglp ℝ^n n big a^mathrmTpa geq 0 text for all a ℝ^n\np_ii = 1 text for all i=1ldotsn\ntextand p = qq^mathrmT text for q in ℝ^n k text with operatornamerank(p) = operatornamerank(q) = k\nbigr\nendaligned\n\nAnd this manifold is working solely on the matrices q. Note that this q is not unique, indeed for any orthogonal matrix A we have (qA)(qA)^mathrmT = qq^mathrmT = p, so the manifold implemented here is the quotient manifold. The unit diagonal translates to unit norm columns of q.\n\nThe tangent space at p, denoted T_pmathcal E(nk), is also represented by matrices Yin ℝ^n k and reads as\n\nT_pmathcal E(nk) = bigl\nX ℝ^n nX = qY^mathrmT + Yq^mathrmT text with X_ii = 0 text for i=1ldotsn\nbigr\n\nendowed with the Euclidean metric from the embedding, i.e. from the ℝ^n k\n\nThis manifold was for example investigated in[JourneeBachAbsilSepulchre2010].\n\nConstructor\n\nElliptope(n,k)\n\ngenerates the manifold mathcal E(nk) subset ℝ^n n.\n\n[JourneeBachAbsilSepulchre2010]: Journée, M., Bach, F., Absil, P.-A., and Sepulchre, R.: “Low-Rank Optimization on the Cone of Positive Semidefinite Matrices”, SIAM Journal on Optimization (20)5, pp. 2327–2351, 2010. doi: 10.1137/080731359, arXiv: 0807.4423.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/elliptope.html#ManifoldsBase.check_point-Union{Tuple{K}, Tuple{N}, Tuple{Elliptope{N, K}, Any}} where {N, K}","page":"Elliptope","title":"ManifoldsBase.check_point","text":"check_point(M::Elliptope, q; kwargs...)\n\nchecks, whether q is a valid reprsentation of a point p=qq^mathrmT on the Elliptope M, i.e. is a matrix of size (N,K), such that p is symmetric positive semidefinite and has unit trace. Since by construction p is symmetric, this is not explicitly checked. Since p is by construction positive semidefinite, this is not checked. The tolerances for positive semidefiniteness and unit trace can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#ManifoldsBase.check_vector-Union{Tuple{K}, Tuple{N}, Tuple{Elliptope{N, K}, Any, Any}} where {N, K}","page":"Elliptope","title":"ManifoldsBase.check_vector","text":"check_vector(M::Elliptope, q, Y; kwargs... )\n\nCheck whether X = qY^mathrmT + Yq^mathrmT is a tangent vector to p=qq^mathrmT on the Elliptope M, i.e. Y has to be of same dimension as q and a X has to be a symmetric matrix with zero diagonal.\n\nThe tolerance for the base point check and zero diagonal can be set using the kwargs.... Note that symmetric of X holds by construction an is not explicitly checked.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#ManifoldsBase.is_flat-Tuple{Elliptope}","page":"Elliptope","title":"ManifoldsBase.is_flat","text":"is_flat(::Elliptope)\n\nReturn false. Elliptope is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#ManifoldsBase.manifold_dimension-Union{Tuple{Elliptope{N, K}}, Tuple{K}, Tuple{N}} where {N, K}","page":"Elliptope","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::Elliptope)\n\nreturns the dimension of Elliptope M=mathcal E(nk) nk ℕ, i.e.\n\ndim mathcal E(nk) = n(k-1) - frack(k-1)2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#ManifoldsBase.project-Tuple{Elliptope, Any}","page":"Elliptope","title":"ManifoldsBase.project","text":"project(M::Elliptope, q)\n\nproject q onto the manifold Elliptope M, by normalizing the rows of q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#ManifoldsBase.project-Tuple{Elliptope, Vararg{Any}}","page":"Elliptope","title":"ManifoldsBase.project","text":"project(M::Elliptope, q, Y)\n\nProject Y onto the tangent space at q, i.e. row-wise onto the oblique manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#ManifoldsBase.representation_size-Union{Tuple{Elliptope{N, K}}, Tuple{K}, Tuple{N}} where {N, K}","page":"Elliptope","title":"ManifoldsBase.representation_size","text":"representation_size(M::Elliptope)\n\nReturn the size of an array representing an element on the Elliptope manifold M, i.e. n k, the size of such factor of p=qq^mathrmT on mathcal M = mathcal E(nk).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#ManifoldsBase.retract-Tuple{Elliptope, Any, Any, ProjectionRetraction}","page":"Elliptope","title":"ManifoldsBase.retract","text":"retract(M::Elliptope, q, Y, ::ProjectionRetraction)\n\ncompute a projection based retraction by projecting q+Y back onto the manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#ManifoldsBase.vector_transport_to-Tuple{Elliptope, Any, Any, Any, ProjectionTransport}","page":"Elliptope","title":"ManifoldsBase.vector_transport_to","text":"vector_transport_to(M::Elliptope, p, X, q)\n\ntransport the tangent vector X at p to q by projecting it onto the tangent space at q.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#ManifoldsBase.zero_vector-Tuple{Elliptope, Vararg{Any}}","page":"Elliptope","title":"ManifoldsBase.zero_vector","text":"zero_vector(M::Elliptope,p)\n\nreturns the zero tangent vector in the tangent space of the symmetric positive definite matrix p on the Elliptope manifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/elliptope.html#Literature","page":"Elliptope","title":"Literature","text":"","category":"section"},{"location":"manifolds/multinomial.html#Multinomial-matrices","page":"Multinomial matrices","title":"Multinomial matrices","text":"","category":"section"},{"location":"manifolds/multinomial.html","page":"Multinomial matrices","title":"Multinomial matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/Multinomial.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/multinomial.html#Manifolds.MultinomialMatrices","page":"Multinomial matrices","title":"Manifolds.MultinomialMatrices","text":"MultinomialMatrices{n,m} <: AbstractPowerManifold{ℝ}\n\nThe multinomial manifold consists of m column vectors, where each column is of length n and unit norm, i.e.\n\nmathcalMN(nm) coloneqq bigl p ℝ^nm big p_ij 0 text for all i=1n j=1m text and p^mathrmTmathbb1_m = mathbb1_nbigr\n\nwhere mathbb1_k is the vector of length k containing ones.\n\nThis yields exactly the same metric as considering the product metric of the probablity vectors, i.e. PowerManifold of the (n-1)-dimensional ProbabilitySimplex.\n\nThe ProbabilitySimplex is stored internally within M.manifold, such that all functions of AbstractPowerManifold can be used directly.\n\nConstructor\n\nMultinomialMatrices(n, m)\n\nGenerate the manifold of matrices mathbb R^nm such that the m columns are discrete probability distributions, i.e. sum up to one.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/multinomial.html#Functions","page":"Multinomial matrices","title":"Functions","text":"","category":"section"},{"location":"manifolds/multinomial.html","page":"Multinomial matrices","title":"Multinomial matrices","text":"Most functions are directly implemented for an AbstractPowerManifold with ArrayPowerRepresentation except the following special cases:","category":"page"},{"location":"manifolds/multinomial.html","page":"Multinomial matrices","title":"Multinomial matrices","text":"Modules = [Manifolds]\nPages = [\"manifolds/Multinomial.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/multinomial.html#ManifoldsBase.check_point-Tuple{MultinomialMatrices, Any}","page":"Multinomial matrices","title":"ManifoldsBase.check_point","text":"check_point(M::MultinomialMatrices, p)\n\nChecks whether p is a valid point on the MultinomialMatrices(m,n) M, i.e. is a matrix of m discrete probability distributions as columns from mathbb R^n, i.e. each column is a point from ProbabilitySimplex(n-1).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/multinomial.html#ManifoldsBase.check_vector-Union{Tuple{m}, Tuple{n}, Tuple{MultinomialMatrices{n, m}, Any, Any}} where {n, m}","page":"Multinomial matrices","title":"ManifoldsBase.check_vector","text":"check_vector(M::MultinomialMatrices p, X; kwargs...)\n\nChecks whether X is a valid tangent vector to p on the MultinomialMatrices M. This means, that p is valid, that X is of correct dimension and columnswise a tangent vector to the columns of p on the ProbabilitySimplex.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#Symplectic","page":"Symplectic","title":"Symplectic","text":"","category":"section"},{"location":"manifolds/symplectic.html","page":"Symplectic","title":"Symplectic","text":"The Symplectic manifold, denoted operatornameSp(2n mathbbF), is a closed, embedded, submanifold of mathbbF^2n times 2n that represents transformations into symplectic subspaces which keep the canonical symplectic form over mathbbF^2n times 2n invariant under the standard embedding inner product. The canonical symplectic form is a non-degenerate bilinear and skew symmetric map omegacolon mathbbF^2n times mathbbF^2n rightarrow mathbbF, given by omega(x y) = x^T Q_2n y for elements x y in mathbbF^2n, with","category":"page"},{"location":"manifolds/symplectic.html","page":"Symplectic","title":"Symplectic","text":" Q_2n = \n beginbmatrix\n 0_n I_n \n -I_n 0_n\n endbmatrix","category":"page"},{"location":"manifolds/symplectic.html","page":"Symplectic","title":"Symplectic","text":"That means that an element p in operatornameSp(2n) must fulfill the requirement that ","category":"page"},{"location":"manifolds/symplectic.html","page":"Symplectic","title":"Symplectic","text":" omega (p x p y) = x^T(p^TQp)y = x^TQy = omega(x y)","category":"page"},{"location":"manifolds/symplectic.html","page":"Symplectic","title":"Symplectic","text":"leading to the requirement on p that p^TQp = Q.","category":"page"},{"location":"manifolds/symplectic.html","page":"Symplectic","title":"Symplectic","text":"The symplectic manifold also forms a group under matrix multiplication, called the textitsymplectic group. Since all the symplectic matrices necessarily have determinant one, the symplectic group operatornameSp(2n mathbbF) is a subgroup of the special linear group, operatornameSL(2n mathbbF). When the underlying field is either mathbbR or mathbbC the symplectic group with a manifold structure constitutes a Lie group, with the Lie Algebra ","category":"page"},{"location":"manifolds/symplectic.html","page":"Symplectic","title":"Symplectic","text":" mathfraksp(2nF) = H in mathbbF^2n times 2n Q H + H^T Q = 0","category":"page"},{"location":"manifolds/symplectic.html","page":"Symplectic","title":"Symplectic","text":"This set is also known as the Hamiltonian matrices, which have the property that (QH)^T = QH and are commonly used in physics.","category":"page"},{"location":"manifolds/symplectic.html","page":"Symplectic","title":"Symplectic","text":"Modules = [Manifolds]\nPages = [\"manifolds/Symplectic.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/symplectic.html#Manifolds.ExtendedSymplecticMetric","page":"Symplectic","title":"Manifolds.ExtendedSymplecticMetric","text":"ExtendedSymplecticMetric <: AbstractMetric\n\nThe extension of the RealSymplecticMetric at a point p \\in \\operatorname{Sp}(2n) as an inner product over the embedding space ℝ^2n times 2n, i.e.\n\n langle x y rangle_p = langle p^-1x p^-1rangle_operatornameFr\n = operatornametr(x^mathrmT(pp^mathrmT)^-1y) forall x y in ℝ^2n times 2n\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symplectic.html#Manifolds.RealSymplecticMetric","page":"Symplectic","title":"Manifolds.RealSymplecticMetric","text":"RealSymplecticMetric <: RiemannianMetric\n\nThe canonical Riemannian metric on the symplectic manifold, defined pointwise for p in operatornameSp(2n) by [Fiori2011]\n\nbeginalign*\n g_p colon T_poperatornameSp(2n) times T_poperatornameSp(2n) rightarrow ℝ \n g_p(Z_1 Z_2) = operatornametr((p^-1Z_1)^mathrmT (p^-1Z_2))\nendalign*\n\nThis metric is also the default metric for the Symplectic manifold.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symplectic.html#Manifolds.Symplectic","page":"Symplectic","title":"Manifolds.Symplectic","text":"Symplectic{n, 𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType}\n\nThe symplectic manifold consists of all 2n times 2n matrices which preserve the canonical symplectic form over 𝔽^2n 2n times 𝔽^2n 2n,\n\n omegacolon 𝔽^2n 2n times 𝔽^2n 2n rightarrow 𝔽\n quad omega(x y) = p^mathrmT Q_2n q x y in 𝔽^2n 2n\n\nwhere\n\nQ_2n =\nbeginbmatrix\n 0_n I_n \n -I_n 0_n\nendbmatrix\n\nThat is, the symplectic manifold consists of\n\noperatornameSp(2n ℝ) = bigl p ℝ^2n 2n big p^mathrmTQ_2np = Q_2n bigr\n\nwith 0_n and I_n denoting the n n zero-matrix and indentity matrix in ℝ^n times n respectively.\n\nThe tangent space at a point p is given by [BendokatZimmermann2021]\n\nbeginalign*\n T_poperatornameSp(2n)\n = X in mathbbR^2n times 2n p^TQ_2nX + X^TQ_2np = 0 \n = X = pQS S R^2n 2n S^mathrmT = S \nendalign*\n\nConstructor\n\nSymplectic(2n, field=ℝ) -> Symplectic{div(2n, 2), field}()\n\nGenerate the (real-valued) symplectic manifold of 2n times 2n symplectic matrices. The constructor for the Symplectic manifold accepts the even column/row embedding dimension 2n for the real symplectic manifold, ℝ^2n 2n.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symplectic.html#Manifolds.SymplecticMatrix","page":"Symplectic","title":"Manifolds.SymplecticMatrix","text":"SymplecticMatrix{T}\n\nA lightweight structure to represent the action of the matrix representation of the canonical symplectic form,\n\nQ_2n(λ) = λ\nbeginbmatrix\n0_n I_n \n -I_n 0_n\nendbmatrix quad in ℝ^2n times 2n\n\nsuch that the canonical symplectic form is represented by\n\nomega_2n(x y) = x^mathrmTQ_2n(1)y quad x y in ℝ^2n\n\nThe entire matrix is however not instantiated in memory, instead a scalar λ of type T is stored, which is used to keep track of scaling and transpose operations applied to each SymplecticMatrix. For example, given Q = SymplecticMatrix(1.0) represented as 1.0*[0 I; -I 0], the adjoint Q' returns SymplecticMatrix(-1.0) = (-1.0)*[0 I; -I 0].\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symplectic.html#Base.exp-Tuple{Symplectic, Vararg{Any}}","page":"Symplectic","title":"Base.exp","text":"exp(M::Symplectic, p, X)\nexp!(M::Symplectic, q, p, X)\n\nThe Exponential mapping on the Symplectic manifold with the RealSymplecticMetric Riemannian metric.\n\nFor the point p in operatornameSp(2n) the exponential mapping along the tangent vector X in T_poperatornameSp(2n) is computed as [WangSunFiori2018]\n\n operatornameexp_p(X) = p operatornameExp((p^-1X)^mathrmT)\n operatornameExp(p^-1X - (p^-1X)^mathrmT)\n\nwhere operatornameExp(cdot) denotes the matrix exponential.\n\n[WangSunFiori2018]: Wang, Jing and Sun, Huafei and Fiori, Simone: A Riemannian-steepest-descent approach for optimization on the real symplectic group, Mathematical Methods in the Applied Sciences, 41(11) pp. 4273-4286, 2018 doi 10.1002/mma.4890\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#Base.inv-Union{Tuple{n}, Tuple{Symplectic{n, ℝ}, Any}} where n","page":"Symplectic","title":"Base.inv","text":"inv(::Symplectic, A)\ninv!(::Symplectic, A)\n\nCompute the symplectic inverse A^+ of matrix A ℝ^2n 2n. Given a matrix\n\nA ℝ^2n 2nquad\nA =\nbeginbmatrix\nA_11 A_12 \nA_21 A_2 2\nendbmatrix\n\nthe symplectic inverse is defined as:\n\nA^+ = Q_2n^mathrmT A^mathrmT Q_2n\n\nwhere\n\nQ_2n =\nbeginbmatrix\n0_n I_n \n -I_n 0_n\nendbmatrix\n\nThe symplectic inverse of A can be expressed explicitly as:\n\nA^+ =\nbeginbmatrix\n A_2 2^mathrmT -A_1 2^mathrmT 12mm\n -A_2 1^mathrmT A_1 1^mathrmT\nendbmatrix\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#Base.rand-Tuple{Symplectic}","page":"Symplectic","title":"Base.rand","text":"rand(::SymplecticStiefel; vector_at=nothing,\n hamiltonian_norm = (vector_at === nothing ? 1/2 : 1.0))\n\nGenerate a random point on operatornameSp(2n) or a random tangent vector X in T_poperatornameSp(2n) if vector_at is set to a point p in operatornameSp(2n).\n\nA random point on operatornameSp(2n) is constructed by generating a random Hamiltonian matrix Ω in mathfraksp(2nF) with norm hamiltonian_norm, and then transforming it to a symplectic matrix by applying the Cayley transform\n\n operatornamecaycolon mathfraksp(2nF) rightarrow operatornameSp(2n)\n Omega mapsto (I - Omega)^-1(I + Omega)\n\nTo generate a random tangent vector in T_poperatornameSp(2n), this code employs the second tangent vector space parametrization of Symplectic. It first generates a random symmetric matrix S by S = randn(2n, 2n) and then symmetrizes it as S = S + S'. Then S is normalized to have Frobenius norm of hamiltonian_norm and X = pQS is returned, where Q is the SymplecticMatrix.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldDiff.gradient-Tuple{Symplectic, Any, Any, ManifoldDiff.RiemannianProjectionBackend}","page":"Symplectic","title":"ManifoldDiff.gradient","text":"gradient(M::Symplectic, f, p, backend::RiemannianProjectionBackend;\n extended_metric=true)\ngradient!(M::Symplectic, f, p, backend::RiemannianProjectionBackend;\n extended_metric=true)\n\nCompute the manifold gradient textgradf(p) of a scalar function f colon operatornameSp(2n) rightarrow ℝ at p in operatornameSp(2n).\n\nThe element textgradf(p) is found as the Riesz representer of the differential textDf(p) colon T_poperatornameSp(2n) rightarrow ℝ w.r.t. the Riemannian metric inner product at p [Fiori2011]. That is, textgradf(p) in T_poperatornameSp(2n) solves the relation\n\n g_p(textgradf(p) X) = textDf(p) quadforall X in T_poperatornameSp(2n)\n\nThe default behaviour is to first change the representation of the Euclidean gradient from the Euclidean metric to the RealSymplecticMetric at p, and then we projecting the result onto the correct tangent tangent space T_poperatornameSp(2n ℝ) w.r.t the Riemannian metric g_p extended to the entire embedding space.\n\nArguments:\n\nextended_metric = true: If true, compute the gradient textgradf(p) by first changing the representer of the Euclidean gradient of a smooth extension of f, f(p), w.r.t. the RealSymplecticMetric at p extended to the entire embedding space, before projecting onto the correct tangent vector space w.r.t. the same extended metric g_p. If false, compute the gradient by first projecting f(p) onto the tangent vector space, before changing the representer in the tangent vector space to comply with the RealSymplecticMetric.\n\n[Fiori2011]: Simone Fiori: Solving minimal-distance problems over the manifold of real-symplectic matrices, SIAM Journal on Matrix Analysis and Applications 32(3), pp. 938-968, 2011. doi 10.1137/100817115.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#Manifolds.project_normal!-Union{Tuple{𝔽}, Tuple{n}, Tuple{m}, Tuple{MetricManifold{𝔽, Euclidean{Tuple{m, n}, 𝔽}, ExtendedSymplecticMetric}, Any, Any, Any}} where {m, n, 𝔽}","page":"Symplectic","title":"Manifolds.project_normal!","text":"project_normal!(::MetricManifold{𝔽,Euclidean,ExtendedSymplecticMetric}, Y, p, X)\n\nProject onto the normal of the tangent space (T_poperatornameSp(2n))^perp_g at a point p operatornameSp(2n), relative to the riemannian metric g RealSymplecticMetric. That is,\n\n(T_poperatornameSp(2n))^perp_g = Y in mathbbR^2n times 2n \n g_p(Y X) = 0 forall X in T_poperatornameSp(2n)\n\nThe closed form projection operator onto the normal space is given by [GaoSonAbsilStykel2021]\n\noperatornameP^(T_poperatornameSp(2n))perp_g_p(X) = pQoperatornameskew(p^mathrmTQ^mathrmTX)\n\nwhere operatornameskew(A) = frac12(A - A^mathrmT). This function is not exported.\n\n[GaoSonAbsilStykel2021]: Gao, Bin and Son, Nguyen Thanh and Absil, P-A and Stykel, Tatjana: Riemannian optimization on the symplectic Stiefel manifold, SIAM Journal on Optimization 31(2), pp. 1546-1575, 2021. doi 10.1137/20M1348522\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#Manifolds.symplectic_inverse_times-Union{Tuple{n}, Tuple{Symplectic{n}, Any, Any}} where n","page":"Symplectic","title":"Manifolds.symplectic_inverse_times","text":"symplectic_inverse_times(::Symplectic, p, q)\nsymplectic_inverse_times!(::Symplectic, A, p, q)\n\nDirectly compute the symplectic inverse of p in operatornameSp(2n), multiplied with q in operatornameSp(2n). That is, this function efficiently computes p^+q = (Q_2np^mathrmTQ_2n)q in ℝ^2n times 2n, where Q_2n is the SymplecticMatrix of size 2n times 2n.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.change_representer-Tuple{Symplectic, EuclideanMetric, Any, Any}","page":"Symplectic","title":"ManifoldsBase.change_representer","text":"change_representer(::Symplectic, ::EuclideanMetric, p, X)\nchange_representer!(::Symplectic, Y, ::EuclideanMetric, p, X)\n\nCompute the representation of a tangent vector ξ T_poperatornameSp(2n ℝ) s.t.\n\n g_p(c_p(ξ) η) = ξ η^textEuc η T_poperatornameSp(2n ℝ)\n\nwith the conversion function\n\n c_p T_poperatornameSp(2n ℝ) rightarrow T_poperatornameSp(2n ℝ) quad\n c_p(ξ) = frac12 pp^mathrmT ξ + frac12 pQ ξ^mathrmT pQ\n\nEach of the terms c_p^1(ξ) = p p^mathrmT ξ and c_p^2(ξ) = pQ ξ^mathrmT pQ from the above definition of c_p(η) are themselves metric compatible in the sense that\n\n c_p^i T_poperatornameSp(2n ℝ) rightarrow mathbbR^2n times 2nquad\n g_p^i(c_p(ξ) η) = ξ η^textEuc η T_poperatornameSp(2n ℝ)\n\nfor i in 1 2. However the range of each function alone is not confined to T_poperatornameSp(2n ℝ), but the convex combination\n\n c_p(ξ) = frac12c_p^1(ξ) + frac12c_p^2(ξ)\n\ndoes have the correct range T_poperatornameSp(2n ℝ).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.change_representer-Union{Tuple{n}, Tuple{m}, Tuple{𝔽}, Tuple{MetricManifold{𝔽, Euclidean{Tuple{m, n}, 𝔽}, ExtendedSymplecticMetric}, EuclideanMetric, Any, Any}} where {𝔽, m, n}","page":"Symplectic","title":"ManifoldsBase.change_representer","text":"change_representer(MetMan::MetricManifold{𝔽, Euclidean{Tuple{m, n}, 𝔽}, ExtendedSymplecticMetric},\n EucMet::EuclideanMetric, p, X)\nchange_representer!(MetMan::MetricManifold{𝔽, Euclidean{Tuple{m, n}, 𝔽}, ExtendedSymplecticMetric},\n Y, EucMet::EuclideanMetric, p, X)\n\nChange the representation of a matrix ξ mathbbR^2n times 2n into the inner product space (ℝ^2n times 2n g_p) where the inner product is given by g_p(ξ η) = langle p^-1ξ p^-1η rangle = operatornametr(ξ^mathrmT(pp^mathrmT)^-1η), as the extension of the RealSymplecticMetric onto the entire embedding space.\n\nBy changing the representation we mean to apply a mapping\n\n c_p mathbbR^2n times 2n rightarrow mathbbR^2n times 2n\n\ndefined by requiring that it satisfy the metric compatibility condition\n\n g_p(c_p(ξ) η) = p^-1c_p(ξ) p^-1η = ξ η^textEuc\n η T_poperatornameSp(2n ℝ)\n\nIn this case, we compute the mapping\n\n c_p(ξ) = pp^mathrmT ξ\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.check_point-Union{Tuple{ℝ}, Tuple{n}, Tuple{Symplectic{n, ℝ}, Any}} where {n, ℝ}","page":"Symplectic","title":"ManifoldsBase.check_point","text":"check_point(M::Symplectic, p; kwargs...)\n\nCheck whether p is a valid point on the Symplectic M=operatornameSp(2n), i.e. that it has the right AbstractNumbers type and p^+p is (approximately) the identity, where A^+ = Q_2n^mathrmTA^mathrmTQ_2n is the symplectic inverse, with\n\nQ_2n =\nbeginbmatrix\n0_n I_n \n -I_n 0_n\nendbmatrix\n\nThe tolerance can be set with kwargs... (e.g. atol = 1.0e-14).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.check_vector-Tuple{Symplectic, Vararg{Any}}","page":"Symplectic","title":"ManifoldsBase.check_vector","text":"check_vector(M::Symplectic, p, X; kwargs...)\n\nChecks whether X is a valid tangent vector at p on the Symplectic M=operatornameSp(2n), i.e. the AbstractNumbers fits and it (approximately) holds that p^TQ_2nX + X^TQ_2np = 0, where\n\nQ_2n =\nbeginbmatrix\n0_n I_n \n -I_n 0_n\nendbmatrix\n\nThe tolerance can be set with kwargs... (e.g. atol = 1.0e-14).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.distance-Union{Tuple{n}, Tuple{Symplectic{n}, Any, Any}} where n","page":"Symplectic","title":"ManifoldsBase.distance","text":"distance(M::Symplectic, p, q)\n\nCompute an approximate geodesic distance between two Symplectic matrices p q in operatornameSp(2n), as done in [WangSunFiori2018].\n\n operatornamedist(p q)\n operatornameLog(p^+q)_operatornameFr\n\nwhere the operatornameLog(cdot) operator is the matrix logarithm.\n\nThis approximation is justified by first recalling the Baker-Campbell-Hausdorf formula,\n\noperatornameLog(operatornameExp(A)operatornameExp(B))\n = A + B + frac12A B + frac112A A B + frac112B B A\n + ldots \n\nThen we write the expression for the exponential map from p to q as\n\n q =\n operatornameexp_p(X)\n =\n p operatornameExp((p^+X)^mathrmT)\n operatornameExp(p^+X - (p^+X)^mathrmT)\n X in T_poperatornameSp\n\nand with the geodesic distance between p and q given by operatornamedist(p q) = X_p = p^+X_operatornameFr we see that\n\n beginalign*\n operatornameLog(p^+q)_operatornameFr\n = operatornameLogleft(\n operatornameExp((p^+X)^mathrmT)\n operatornameExp(p^+X - (p^+X)^mathrmT)\n right)_operatornameFr \n = p^+X + frac12(p^+X)^mathrmT p^+X - (p^+X)^mathrmT\n + ldots _operatornameFr \n p^+X_operatornameFr = operatornamedist(p q)\n endalign*\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.inner-Union{Tuple{n}, Tuple{Symplectic{n, ℝ}, Any, Any, Any}} where n","page":"Symplectic","title":"ManifoldsBase.inner","text":"inner(::Symplectic{n, ℝ}, p, X, Y)\n\nCompute the canonical Riemannian inner product RealSymplecticMetric\n\n g_p(X Y) = operatornametr((p^-1X)^mathrmT (p^-1Y))\n\nbetween the two tangent vectors X Y in T_poperatornameSp(2n).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.inverse_retract-Tuple{Symplectic, Any, Any, CayleyInverseRetraction}","page":"Symplectic","title":"ManifoldsBase.inverse_retract","text":"inverse_retract(M::Symplectic, p, q, ::CayleyInverseRetraction)\n\nCompute the Cayley Inverse Retraction X = mathcalL_p^operatornameSp(q) such that the Cayley Retraction from p along X lands at q, i.e. mathcalR_p(X) = q [BendokatZimmermann2021].\n\nFirst, recall the definition the standard symplectic matrix\n\nQ =\nbeginbmatrix\n 0 I \n-I 0\nendbmatrix\n\nas well as the symplectic inverse of a matrix A, A^+ = Q^mathrmT A^mathrmT Q.\n\nFor p q operatornameSp(2n ℝ) then, we can then define the inverse cayley retraction as long as the following matrices exist.\n\n U = (I + p^+ q)^-1 quad V = (I + q^+ p)^-1\n\nIf that is the case, the inverse cayley retration at p applied to q is\n\nmathcalL_p^operatornameSp(q) = 2pbigl(V - Ubigr) + 2bigl((p + q)U - pbigr)\n T_poperatornameSp(2n)\n\n[BendokatZimmermann2021]: Bendokat, Thomas and Zimmermann, Ralf: The real symplectic Stiefel and Grassmann manifolds: metrics, geodesics and applications arXiv preprint arXiv:2108.12447, 2021.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.is_flat-Tuple{Symplectic}","page":"Symplectic","title":"ManifoldsBase.is_flat","text":"is_flat(::Symplectic)\n\nReturn false. Symplectic is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.manifold_dimension-Union{Tuple{Symplectic{n}}, Tuple{n}} where n","page":"Symplectic","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(::Symplectic{n})\n\nReturns the dimension of the symplectic manifold embedded in ℝ^2n times 2n, i.e.\n\n operatornamedim(operatornameSp(2n)) = (2n + 1)n\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.project!-Union{Tuple{𝔽}, Tuple{n}, Tuple{m}, Tuple{MetricManifold{𝔽, Euclidean{Tuple{m, n}, 𝔽}, ExtendedSymplecticMetric}, Any, Any, Any}} where {m, n, 𝔽}","page":"Symplectic","title":"ManifoldsBase.project!","text":"project!(::MetricManifold{𝔽,Euclidean,ExtendedSymplecticMetric}, Y, p, X) where {𝔽}\n\nCompute the projection of X R^2n 2n onto T_poperatornameSp(2n ℝ) w.r.t. the Riemannian metric g RealSymplecticMetric. The closed form projection mapping is given by [GaoSonAbsilStykel2021]\n\n operatornameP^T_poperatornameSp(2n)_g_p(X) = pQoperatornamesym(p^mathrmTQ^mathrmTX)\n\nwhere operatornamesym(A) = frac12(A + A^mathrmT). This function is not exported.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.project-Tuple{Symplectic, Any, Any}","page":"Symplectic","title":"ManifoldsBase.project","text":"project(::Symplectic, p, A)\nproject!(::Symplectic, Y, p, A)\n\nGiven a point p in operatornameSp(2n), project an element A in mathbbR^2n times 2n onto the tangent space T_poperatornameSp(2n) relative to the euclidean metric of the embedding mathbbR^2n times 2n.\n\nThat is, we find the element X in T_poperatornameSpSt(2n 2k) which solves the constrained optimization problem\n\n operatornamemin_X in mathbbR^2n times 2n frac12X - A^2 quad\n textst\n h(X) colon= X^mathrmT Q p + p^mathrmT Q X = 0\n\nwhere hcolonmathbbR^2n times 2n rightarrow operatornameskew(2n) defines the restriction of X onto the tangent space T_poperatornameSpSt(2n 2k).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#ManifoldsBase.retract-Tuple{Symplectic, Any, Any}","page":"Symplectic","title":"ManifoldsBase.retract","text":"retract(::Symplectic, p, X, ::CayleyRetraction)\nretract!(::Symplectic, q, p, X, ::CayleyRetraction)\n\nCompute the Cayley retraction on p operatornameSp(2n ℝ) in the direction of tangent vector X T_poperatornameSp(2n ℝ), as defined in by Birtea et al in proposition 2 [BirteaCaşuComănescu2020].\n\nUsing the symplectic inverse of a matrix A in ℝ^2n times 2n, A^+ = Q_2n^mathrmT A^mathrmT Q_2n where\n\nQ_2n =\nbeginbmatrix\n0_n I_n \n -I_n 0_n\nendbmatrix\n\nthe retraction mathcalRcolon ToperatornameSp(2n) rightarrow operatornameSp(2n) is defined pointwise as\n\nbeginalign*\nmathcalR_p(X) = p operatornamecayleft(frac12p^+Xright) \n = p operatornameexp_11(p^+X) \n = p (2I - p^+X)^-1(2I + p^+X)\nendalign*\n\nHere operatornameexp_11(z) = (2 - z)^-1(2 + z) denotes the Padé (1, 1) approximation to operatornameexp(z).\n\n[BirteaCaşuComănescu2020]: Birtea, Petre and Caşu, Ioan and Comănescu, Dan: Optimization on the real symplectic group, Monatshefte f{\"u}r Mathematik, Springer, 2020. doi 10.1007/s00605-020-01369-9\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symplectic.html#Literature","page":"Symplectic","title":"Literature","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html#SymmetricPositiveDefiniteSection","page":"Symmetric positive definite","title":"Symmetric positive definite matrices","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"SymmetricPositiveDefinite","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.SymmetricPositiveDefinite","page":"Symmetric positive definite","title":"Manifolds.SymmetricPositiveDefinite","text":"SymmetricPositiveDefinite{N} <: AbstractDecoratorManifold{ℝ}\n\nThe manifold of symmetric positive definite matrices, i.e.\n\nmathcal P(n) =\nbigl\np ℝ^n n big a^mathrmTpa 0 text for all a ℝ^nbackslash0\nbigr\n\nThe tangent space at T_pmathcal P(n) reads\n\n T_pmathcal P(n) =\n bigl\n X in mathbb R^nn big X=X^mathrmT\n bigr\n\ni.e. the set of symmetric matrices,\n\nConstructor\n\nSymmetricPositiveDefinite(n)\n\ngenerates the manifold mathcal P(n) subset ℝ^n n\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"This manifold can – for example – be illustrated as ellipsoids: since the eigenvalues are all positive they can be taken as lengths of the axes of an ellipsoids while the directions are given by the eigenvectors.","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"(Image: An example set of data)","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"The manifold can be equipped with different metrics","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Common-and-metric-independent-functions","page":"Symmetric positive definite","title":"Common and metric independent functions","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"Modules = [Manifolds]\nPages = [\"manifolds/SymmetricPositiveDefinite.jl\"]\nOrder = [:function]\nPublic=true\nPrivate=false\nFilter = t -> t !== mean","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Base.convert-Tuple{Type{AbstractMatrix}, SPDPoint}","page":"Symmetric positive definite","title":"Base.convert","text":"convert(::Type{AbstractMatrix}, p::SPDPoint)\n\nreturn the point p as a matrix. The matrix is either stored within the SPDPoint or reconstructed from p.eigen.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Base.rand-Tuple{SymmetricPositiveDefinite}","page":"Symmetric positive definite","title":"Base.rand","text":"rand(M::SymmetricPositiveDefinite; σ::Real=1)\n\nGenerate a random symmetric positive definite matrix on the SymmetricPositiveDefinite manifold M.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.check_point-Union{Tuple{N}, Tuple{SymmetricPositiveDefinite{N}, Any}} where N","page":"Symmetric positive definite","title":"ManifoldsBase.check_point","text":"check_point(M::SymmetricPositiveDefinite, p; kwargs...)\n\nchecks, whether p is a valid point on the SymmetricPositiveDefinite M, i.e. is a matrix of size (N,N), symmetric and positive definite. The tolerance for the second to last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.check_vector-Union{Tuple{N}, Tuple{SymmetricPositiveDefinite{N}, Any, Any}} where N","page":"Symmetric positive definite","title":"ManifoldsBase.check_vector","text":"check_vector(M::SymmetricPositiveDefinite, p, X; kwargs... )\n\nCheck whether X is a tangent vector to p on the SymmetricPositiveDefinite M, i.e. atfer check_point(M,p), X has to be of same dimension as p and a symmetric matrix, i.e. this stores tangent vetors as elements of the corresponding Lie group. The tolerance for the last test can be set using the kwargs....\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.injectivity_radius-Tuple{SymmetricPositiveDefinite}","page":"Symmetric positive definite","title":"ManifoldsBase.injectivity_radius","text":"injectivity_radius(M::SymmetricPositiveDefinite[, p])\ninjectivity_radius(M::MetricManifold{SymmetricPositiveDefinite,AffineInvariantMetric}[, p])\ninjectivity_radius(M::MetricManifold{SymmetricPositiveDefinite,LogCholeskyMetric}[, p])\n\nReturn the injectivity radius of the SymmetricPositiveDefinite. Since M is a Hadamard manifold with respect to the AffineInvariantMetric and the LogCholeskyMetric, the injectivity radius is globally .\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.is_flat-Tuple{SymmetricPositiveDefinite}","page":"Symmetric positive definite","title":"ManifoldsBase.is_flat","text":"is_flat(::SymmetricPositiveDefinite)\n\nReturn false. SymmetricPositiveDefinite is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.manifold_dimension-Union{Tuple{SymmetricPositiveDefinite{N}}, Tuple{N}} where N","page":"Symmetric positive definite","title":"ManifoldsBase.manifold_dimension","text":"manifold_dimension(M::SymmetricPositiveDefinite)\n\nreturns the dimension of SymmetricPositiveDefinite M=mathcal P(n) n ℕ, i.e.\n\ndim mathcal P(n) = fracn(n+1)2\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.project-Tuple{SymmetricPositiveDefinite, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.project","text":"project(M::SymmetricPositiveDefinite, p, X)\n\nproject a matrix from the embedding onto the tangent space T_pmathcal P(n) of the SymmetricPositiveDefinite matrices, i.e. the set of symmetric matrices.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.representation_size-Union{Tuple{SymmetricPositiveDefinite{N}}, Tuple{N}} where N","page":"Symmetric positive definite","title":"ManifoldsBase.representation_size","text":"representation_size(M::SymmetricPositiveDefinite)\n\nReturn the size of an array representing an element on the SymmetricPositiveDefinite manifold M, i.e. n n, the size of such a symmetric positive definite matrix on mathcal M = mathcal P(n).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Default-metric:-the-affine-invariant-metric","page":"Symmetric positive definite","title":"Default metric: the affine invariant metric","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"Modules = [Manifolds]\nPages = [\"manifolds/SymmetricPositiveDefiniteAffineInvariant.jl\"]\nOrder = [:type]","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.AffineInvariantMetric","page":"Symmetric positive definite","title":"Manifolds.AffineInvariantMetric","text":"AffineInvariantMetric <: AbstractMetric\n\nThe linear affine metric is the metric for symmetric positive definite matrices, that employs matrix logarithms and exponentials, which yields a linear and affine metric.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"This metric is also the default metric, i.e. any call of the following functions with P=SymmetricPositiveDefinite(3) will result in MetricManifold(P,AffineInvariantMetric())and hence yield the formulae described in this seciton.","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"Modules = [Manifolds]\nPages = [\"manifolds/SymmetricPositiveDefiniteAffineInvariant.jl\"]\nOrder = [:function]","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Base.exp-Tuple{SymmetricPositiveDefinite, Vararg{Any}}","page":"Symmetric positive definite","title":"Base.exp","text":"exp(M::SymmetricPositiveDefinite, p, X)\nexp(M::MetricManifold{SymmetricPositiveDefinite{N},AffineInvariantMetric}, p, X)\n\nCompute the exponential map from p with tangent vector X on the SymmetricPositiveDefinite M with its default MetricManifold having the AffineInvariantMetric. The formula reads\n\nexp_p X = p^frac12operatornameExp(p^-frac12 X p^-frac12)p^frac12\n\nwhere operatornameExp denotes to the matrix exponential.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Base.log-Tuple{SymmetricPositiveDefinite, Vararg{Any}}","page":"Symmetric positive definite","title":"Base.log","text":"log(M::SymmetricPositiveDefinite, p, q)\nlog(M::MetricManifold{SymmetricPositiveDefinite,AffineInvariantMetric}, p, q)\n\nCompute the logarithmic map from p to q on the SymmetricPositiveDefinite as a MetricManifold with AffineInvariantMetric. The formula reads\n\nlog_p q =\np^frac12operatornameLog(p^-frac12qp^-frac12)p^frac12\n\nwhere operatornameLog denotes to the matrix logarithm.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldDiff.riemannian_Hessian-Tuple{SymmetricPositiveDefinite, Vararg{Any, 4}}","page":"Symmetric positive definite","title":"ManifoldDiff.riemannian_Hessian","text":"riemannian_Hessian(M::SymmetricPositiveDefinite, p, g, H, X)\n\nThe Riemannian Hessian can be computed as stated in Eq. (7.3) [Ngu23]. Let nabla f(p) denote the Euclidean gradient G, nabla^2 f(p)X the Euclidean Hessian H, and operatornamesym(X) = frac12bigl(X^mathrmT+Xbigr)` the symmetrization operator. Then the formula reads\n\n operatornameHessf(p)X\n =\n poperatornamesym(^2 f(p)X)p\n + operatornamesymBigl( Xoperatornamesymbigl( f(p)bigr)p)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.change_metric-Tuple{SymmetricPositiveDefinite, EuclideanMetric, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.change_metric","text":"change_metric(M::SymmetricPositiveDefinite{n}, E::EuclideanMetric, p, X)\n\nGiven a tangent vector X T_pmathcal P(n) with respect to the EuclideanMetric g_E, this function changes into the AffineInvariantMetric (default) metric on the SymmetricPositiveDefinite M.\n\nTo be precise we are looking for ccolon T_pmathcal P(n) to T_pmathcal P(n) such that for all YZ T_pmathcal P(n)` it holds\n\nYZ = operatornametr(YZ) = operatornametr(p^-1c(Y)p^-1c(Z)) = g_p(c(Z)c(Y))\n\nand hence c(X) = pX is computed.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.change_representer-Tuple{SymmetricPositiveDefinite, EuclideanMetric, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.change_representer","text":"change_representer(M::SymmetricPositiveDefinite, E::EuclideanMetric, p, X)\n\nGiven a tangent vector X T_pmathcal M representing a linear function on the tangent space at p with respect to the EuclideanMetric g_E, this is turned into the representer with respect to the (default) metric, the AffineInvariantMetric on the SymmetricPositiveDefinite M.\n\nTo be precise we are looking for ZT_pmathcal P(n) such that for all YT_pmathcal P(n)` it holds\n\nXY = operatornametr(XY) = operatornametr(p^-1Zp^-1Y) = g_p(ZY)\n\nand hence Z = pXp.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.distance-Union{Tuple{N}, Tuple{SymmetricPositiveDefinite{N}, Any, Any}} where N","page":"Symmetric positive definite","title":"ManifoldsBase.distance","text":"distance(M::SymmetricPositiveDefinite, p, q)\ndistance(M::MetricManifold{SymmetricPositiveDefinite,AffineInvariantMetric}, p, q)\n\nCompute the distance on the SymmetricPositiveDefinite manifold between p and q, as a MetricManifold with AffineInvariantMetric. The formula reads\n\nd_mathcal P(n)(pq)\n= lVert operatornameLog(p^-frac12qp^-frac12)rVert_mathrmF\n\nwhere operatornameLog denotes the matrix logarithm and lVertcdotrVert_mathrmF denotes the matrix Frobenius norm.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.get_basis-Tuple{SymmetricPositiveDefinite, Any, DefaultOrthonormalBasis}","page":"Symmetric positive definite","title":"ManifoldsBase.get_basis","text":"[Ξ,κ] = get_basis(M::SymmetricPositiveDefinite, p, B::DefaultOrthonormalBasis)\n[Ξ,κ] = get_basis(M::MetricManifold{SymmetricPositiveDefinite{N},AffineInvariantMetric}, p, B::DefaultOrthonormalBasis)\n\nReturn a default ONB for the tangent space T_pmathcal P(n) of the SymmetricPositiveDefinite with respect to the AffineInvariantMetric.\n\n g_p(XY) = operatornametr(p^-1 X p^-1 Y)\n\nThe basis constructed here is based on the ONB for symmetric matrices constructed as follows. Let\n\nDelta_ij = (a_kl)_kl=1^n quad text with \na_kl =\nbegincases\n 1 mbox for k=l text if i=j\n frac1sqrt2 mbox for k=i l=j text or k=j l=i\n 0 text else\nendcases\n\nwhich forms an ONB for the space of symmetric matrices.\n\nWe then form the ONB by\n\n Xi_ij = p^frac12Delta_ijp^frac12qquad i=1ldotsn j=ildotsn\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.get_basis_diagonalizing-Union{Tuple{N}, Tuple{SymmetricPositiveDefinite{N}, Any, DiagonalizingOrthonormalBasis}} where N","page":"Symmetric positive definite","title":"ManifoldsBase.get_basis_diagonalizing","text":"[Ξ,κ] = get_basis_diagonalizing(M::SymmetricPositiveDefinite, p, B::DiagonalizingOrthonormalBasis)\n[Ξ,κ] = get_basis_diagonalizing(M::MetricManifold{SymmetricPositiveDefinite{N},AffineInvariantMetric}, p, B::DiagonalizingOrthonormalBasis)\n\nReturn a orthonormal basis Ξ as a vector of tangent vectors (of length manifold_dimension of M) in the tangent space of p on the MetricManifold of SymmetricPositiveDefinite manifold M with AffineInvariantMetric that diagonalizes the curvature tensor R(uv)w with eigenvalues κ and where the direction B.frame_direction V has curvature 0.\n\nThe construction is based on an ONB for the symmetric matrices similar to get_basis(::SymmetricPositiveDefinite, p, ::DefaultOrthonormalBasis just that the ONB here is build from the eigen vectors of p^frac12Vp^frac12.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.get_coordinates-Tuple{SymmetricPositiveDefinite, Any, Any, Any, DefaultOrthonormalBasis}","page":"Symmetric positive definite","title":"ManifoldsBase.get_coordinates","text":"get_coordinates(::SymmetricPositiveDefinite, p, X, ::DefaultOrthonormalBasis)\n\nUsing the basis from get_basis the coordinates with respect to this ONB can be simplified to\n\n c_k = mathrmtr(p^-frac12Delta_ij X)\n\nwhere k is trhe linearized index of the i=1ldotsn j=ildotsn.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.get_vector-Tuple{SymmetricPositiveDefinite, Any, Any, Any, DefaultOrthonormalBasis}","page":"Symmetric positive definite","title":"ManifoldsBase.get_vector","text":"get_vector(::SymmetricPositiveDefinite, p, c, ::DefaultOrthonormalBasis)\n\nUsing the basis from get_basis the vector reconstruction with respect to this ONB can be simplified to\n\n X = p^frac12 Biggl( sum_i=1j=i^n c_k Delta_ij Biggr) p^frac12\n\nwhere k is the linearized index of the i=1ldotsn j=ildotsn.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.inner-Tuple{SymmetricPositiveDefinite, Any, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.inner","text":"inner(M::SymmetricPositiveDefinite, p, X, Y)\ninner(M::MetricManifold{SymmetricPositiveDefinite,AffineInvariantMetric}, p, X, Y)\n\nCompute the inner product of X, Y in the tangent space of p on the SymmetricPositiveDefinite manifold M, as a MetricManifold with AffineInvariantMetric. The formula reads\n\ng_p(XY) = operatornametr(p^-1 X p^-1 Y)\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.is_flat-Tuple{MetricManifold{ℝ, <:SymmetricPositiveDefinite, AffineInvariantMetric}}","page":"Symmetric positive definite","title":"ManifoldsBase.is_flat","text":"is_flat(::MetricManifold{ℝ,<:SymmetricPositiveDefinite,AffineInvariantMetric})\n\nReturn false. SymmetricPositiveDefinite with AffineInvariantMetric is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.parallel_transport_to-Tuple{SymmetricPositiveDefinite, Any, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.parallel_transport_to","text":"parallel_transport_to(M::SymmetricPositiveDefinite, p, X, q)\nparallel_transport_to(M::MetricManifold{SymmetricPositiveDefinite,AffineInvariantMetric}, p, X, y)\n\nCompute the parallel transport of X from the tangent space at p to the tangent space at q on the SymmetricPositiveDefinite as a MetricManifold with the AffineInvariantMetric. The formula reads\n\nmathcal P_qpX = p^frac12\noperatornameExpbigl(\nfrac12p^-frac12log_p(q)p^-frac12\nbigr)\np^-frac12X p^-frac12\noperatornameExpbigl(\nfrac12p^-frac12log_p(q)p^-frac12\nbigr)\np^frac12\n\nwhere operatornameExp denotes the matrix exponential and log the logarithmic map on SymmetricPositiveDefinite (again with respect to the AffineInvariantMetric).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.riemann_tensor-Tuple{SymmetricPositiveDefinite, Vararg{Any, 4}}","page":"Symmetric positive definite","title":"ManifoldsBase.riemann_tensor","text":"riemann_tensor(::SymmetricPositiveDefinite, p, X, Y, Z)\n\nCompute the value of Riemann tensor on the SymmetricPositiveDefinite manifold. The formula reads[Rentmeesters2011] R(XY)Z=p^12R(X_I Y_I)Z_Ip^12, where R_I(X_I Y_I)Z_I=frac14Z_I X_I Y_I, X_I=p^-12Xp^-12, Y_I=p^-12Yp^-12 and Z_I=p^-12Zp^-12.\n\n[Rentmeesters2011]: Q. Rentmeesters, “A gradient method for geodesic data fitting on some symmetric Riemannian manifolds,” in 2011 50th IEEE Conference on Decision and Control and European Control Conference, Dec. 2011, pp. 7141–7146. doi: 10.1109/CDC.2011.6161280.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#BuresWassersteinMetricSection","page":"Symmetric positive definite","title":"Bures-Wasserstein metric","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"Modules = [Manifolds]\nPages = [\"manifolds/SymmetricPositiveDefiniteBuresWasserstein.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.BuresWassersteinMetric","page":"Symmetric positive definite","title":"Manifolds.BuresWassersteinMetric","text":"BurresWassertseinMetric <: AbstractMetric\n\nThe Bures Wasserstein metric for symmetric positive definite matrices[MalagoMontruccioPistone2018].\n\n[MalagoMontruccioPistone2018]: Malagò, L., Montrucchio, L., Pistone, G.: Wasserstein Riemannian geometry of Gaussian densities. Information Geometry, 1, pp. 137–179, 2018. doi: 10.1007/s41884-018-0014-4\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symmetricpositivedefinite.html#Base.exp-Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite, BuresWassersteinMetric}, Any, Any}","page":"Symmetric positive definite","title":"Base.exp","text":"exp(::MatricManifold{ℝ,SymmetricPositiveDefinite,BuresWassersteinMetric}, p, X)\n\nCompute the exponential map on SymmetricPositiveDefinite with respect to the BuresWassersteinMetric given by\n\n exp_p(X) = p+X+L_p(X)pL_p(X)\n\nwhere q=L_p(X) denotes the Lyapunov operator, i.e. it solves pq + qp = X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Base.log-Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite, BuresWassersteinMetric}, Any, Any}","page":"Symmetric positive definite","title":"Base.log","text":"log(::MatricManifold{SymmetricPositiveDefinite,BuresWassersteinMetric}, p, q)\n\nCompute the logarithmic map on SymmetricPositiveDefinite with respect to the BuresWassersteinMetric given by\n\n log_p(q) = (pq)^frac12 + (qp)^frac12 - 2 p\n\nwhere q=L_p(X) denotes the Lyapunov operator, i.e. it solves pq + qp = X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.change_representer-Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite, BuresWassersteinMetric}, EuclideanMetric, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.change_representer","text":"change_representer(M::MetricManifold{ℝ,SymmetricPositiveDefinite,BuresWassersteinMetric}, E::EuclideanMetric, p, X)\n\nGiven a tangent vector X T_pmathcal M representing a linear function on the tangent space at p with respect to the EuclideanMetric g_E, this is turned into the representer with respect to the (default) metric, the BuresWassersteinMetric on the SymmetricPositiveDefinite M.\n\nTo be precise we are looking for ZT_pmathcal P(n) such that for all YT_pmathcal P(n)` it holds\n\nXY = operatornametr(XY) = ZY_mathrmBW\n\nfor all Y and hence we get Z= 2(A+A^{\\mathrm{T}})withA=Xp``.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.distance-Tuple{MetricManifold{ℝ, <:SymmetricPositiveDefinite, BuresWassersteinMetric}, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.distance","text":"distance(::MatricManifold{SymmetricPositiveDefinite,BuresWassersteinMetric}, p, q)\n\nCompute the distance with respect to the BuresWassersteinMetric on SymmetricPositiveDefinite matrices, i.e.\n\nd(pq) =\n operatornametr(p) + operatornametr(q) - 2operatornametrBigl( (p^frac12qp^frac12 bigr)^frac12 Bigr)\n\nwhere the last trace can be simplified (by rotating the matrix products in the trace) to operatornametr(pq).\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.inner-Tuple{MetricManifold{ℝ, <:SymmetricPositiveDefinite, BuresWassersteinMetric}, Any, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.inner","text":"inner(::MetricManifold{ℝ,SymmetricPositiveDefinite,BuresWassersteinMetric}, p, X, Y)\n\nCompute the inner product SymmetricPositiveDefinite with respect to the BuresWassersteinMetric given by\n\n XY = frac12operatornametr(L_p(X)Y)\n\nwhere q=L_p(X) denotes the Lyapunov operator, i.e. it solves pq + qp = X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.is_flat-Tuple{MetricManifold{ℝ, <:SymmetricPositiveDefinite, BuresWassersteinMetric}}","page":"Symmetric positive definite","title":"ManifoldsBase.is_flat","text":"is_flat(::MetricManifold{ℝ,<:SymmetricPositiveDefinite,BuresWassersteinMetric})\n\nReturn false. SymmetricPositiveDefinite with BuresWassersteinMetric is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Generalized-Bures-Wasserstein-metric","page":"Symmetric positive definite","title":"Generalized Bures-Wasserstein metric","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"Modules = [Manifolds]\nPages = [\"manifolds/SymmetricPositiveDefiniteGeneralizedBuresWasserstein.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.GeneralizedBuresWassersteinMetric","page":"Symmetric positive definite","title":"Manifolds.GeneralizedBuresWassersteinMetric","text":"GeneralizedBurresWassertseinMetric{T<:AbstractMatrix} <: AbstractMetric\n\nThe generalized Bures Wasserstein metric for symmetric positive definite matrices, see[HanMishraJawanpuriaGao2021].\n\nThis metric internally stores the symmetric positive definite matrix M to generalise the metric, where the name also follows the mentioned preprint.\n\n[HanMishraJawanpuriaGao2021]: Han, A., Mishra, B., Jawanpuria, P., Gao, J.: Generalized Bures-Wasserstein geometry for positive definite matrices. arXiv: 2110.10464.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symmetricpositivedefinite.html#Base.exp-Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite, GeneralizedBuresWassersteinMetric}, Any, Any}","page":"Symmetric positive definite","title":"Base.exp","text":"exp(::MatricManifold{ℝ,SymmetricPositiveDefinite,GeneralizedBuresWassersteinMetric}, p, X)\n\nCompute the exponential map on SymmetricPositiveDefinite with respect to the GeneralizedBuresWassersteinMetric given by\n\n exp_p(X) = p+X+mathcal ML_pM(X)pML_pM(X)\n\nwhere q=L_Mp(X) denotes the generalized Lyapunov operator, i.e. it solves pqM + Mqp = X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Base.log-Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite, GeneralizedBuresWassersteinMetric}, Any, Any}","page":"Symmetric positive definite","title":"Base.log","text":"log(::MatricManifold{SymmetricPositiveDefinite,GeneralizedBuresWassersteinMetric}, p, q)\n\nCompute the logarithmic map on SymmetricPositiveDefinite with respect to the BuresWassersteinMetric given by\n\n log_p(q) = M(M^-1pM^-1q)^frac12 + (qM^-1pM^-1)^frac12M - 2 p\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.change_representer-Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite, GeneralizedBuresWassersteinMetric}, EuclideanMetric, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.change_representer","text":"change_representer(M::MetricManifold{ℝ,SymmetricPositiveDefinite,GeneralizedBuresWassersteinMetric}, E::EuclideanMetric, p, X)\n\nGiven a tangent vector X T_pmathcal M representing a linear function on the tangent space at p with respect to the EuclideanMetric g_E, this is turned into the representer with respect to the (default) metric, the GeneralizedBuresWassersteinMetric on the SymmetricPositiveDefinite M.\n\nTo be precise we are looking for ZT_pmathcal P(n) such that for all YT_pmathcal P(n) it holds\n\nXY = operatornametr(XY) = ZY_mathrmBW\n\nfor all Y and hence we get Z = 2pXM + 2MXp.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.distance-Tuple{MetricManifold{ℝ, <:SymmetricPositiveDefinite, <:GeneralizedBuresWassersteinMetric}, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.distance","text":"distance(::MatricManifold{SymmetricPositiveDefinite,GeneralizedBuresWassersteinMetric}, p, q)\n\nCompute the distance with respect to the BuresWassersteinMetric on SymmetricPositiveDefinite matrices, i.e.\n\nd(pq) = operatornametr(M^-1p) + operatornametr(M^-1q)\n - 2operatornametrbigl( (p^frac12M^-1qM^-1p^frac12 bigr)^frac12\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.inner-Tuple{MetricManifold{ℝ, <:SymmetricPositiveDefinite, <:GeneralizedBuresWassersteinMetric}, Any, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.inner","text":"inner(::MetricManifold{ℝ,SymmetricPositiveDefinite,GeneralizedBuresWassersteinMetric}, p, X, Y)\n\nCompute the inner product SymmetricPositiveDefinite with respect to the GeneralizedBuresWassersteinMetric given by\n\n XY = frac12operatornametr(L_pM(X)Y)\n\nwhere q=L_Mp(X) denotes the generalized Lyapunov operator, i.e. it solves pqM + Mqp = X.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.is_flat-Tuple{MetricManifold{ℝ, <:SymmetricPositiveDefinite, <:GeneralizedBuresWassersteinMetric}}","page":"Symmetric positive definite","title":"ManifoldsBase.is_flat","text":"is_flat(::MetricManifold{ℝ,<:SymmetricPositiveDefinite,<:GeneralizedBuresWassersteinMetric})\n\nReturn false. SymmetricPositiveDefinite with GeneralizedBuresWassersteinMetric is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Log-Euclidean-metric","page":"Symmetric positive definite","title":"Log-Euclidean metric","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"Modules = [Manifolds]\nPages = [\"manifolds/SymmetricPositiveDefiniteLogEuclidean.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.LogEuclideanMetric","page":"Symmetric positive definite","title":"Manifolds.LogEuclideanMetric","text":"LogEuclideanMetric <: RiemannianMetric\n\nThe LogEuclidean Metric consists of the Euclidean metric applied to all elements after mapping them into the Lie Algebra, i.e. performing a matrix logarithm beforehand.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.distance-Union{Tuple{N}, Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite{N}, LogEuclideanMetric}, Any, Any}} where N","page":"Symmetric positive definite","title":"ManifoldsBase.distance","text":"distance(M::MetricManifold{SymmetricPositiveDefinite{N},LogEuclideanMetric}, p, q)\n\nCompute the distance on the SymmetricPositiveDefinite manifold between p and q as a MetricManifold with LogEuclideanMetric. The formula reads\n\n d_mathcal P(n)(pq) = lVert operatornameLog p - operatornameLog q rVert_mathrmF\n\nwhere operatornameLog denotes the matrix logarithm and lVertcdotrVert_mathrmF denotes the matrix Frobenius norm.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.is_flat-Tuple{MetricManifold{ℝ, <:SymmetricPositiveDefinite, LogEuclideanMetric}}","page":"Symmetric positive definite","title":"ManifoldsBase.is_flat","text":"is_flat(::MetricManifold{ℝ,<:SymmetricPositiveDefinite,LogEuclideanMetric})\n\nReturn false. SymmetricPositiveDefinite with LogEuclideanMetric is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Log-Cholesky-metric","page":"Symmetric positive definite","title":"Log-Cholesky metric","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"Modules = [Manifolds]\nPages = [\"manifolds/SymmetricPositiveDefiniteLogCholesky.jl\"]\nOrder = [:type, :function]","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.LogCholeskyMetric","page":"Symmetric positive definite","title":"Manifolds.LogCholeskyMetric","text":"LogCholeskyMetric <: RiemannianMetric\n\nThe Log-Cholesky metric imposes a metric based on the Cholesky decomposition as introduced by [Lin2019].\n\n[Lin2019]: Lin, Zenhua: \"Riemannian Geometry of Symmetric Positive Definite Matrices via Cholesky Decomposition\", arXiv: 1908.09326.\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symmetricpositivedefinite.html#Base.exp-Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite, LogCholeskyMetric}, Vararg{Any}}","page":"Symmetric positive definite","title":"Base.exp","text":"exp(M::MetricManifold{SymmetricPositiveDefinite,LogCholeskyMetric}, p, X)\n\nCompute the exponential map on the SymmetricPositiveDefinite M with LogCholeskyMetric from p into direction X. The formula reads\n\nexp_p X = (exp_y W)(exp_y W)^mathrmT\n\nwhere exp_xW is the exponential map on CholeskySpace, y is the cholesky decomposition of p, W = y(y^-1Xy^-mathrmT)_frac12, and (cdot)_frac12 denotes the lower triangular matrix with the diagonal multiplied by frac12.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Base.log-Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite, LogCholeskyMetric}, Vararg{Any}}","page":"Symmetric positive definite","title":"Base.log","text":"log(M::MetricManifold{SymmetricPositiveDefinite,LogCholeskyMetric}, p, q)\n\nCompute the logarithmic map on SymmetricPositiveDefinite M with respect to the LogCholeskyMetric emanating from p to q. The formula can be adapted from the CholeskySpace as\n\nlog_p q = xW^mathrmT + Wx^mathrmT\n\nwhere x is the cholesky factor of p and W=log_x y for y the cholesky factor of q and the just mentioned logarithmic map is the one on CholeskySpace.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.distance-Union{Tuple{N}, Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite{N}, LogCholeskyMetric}, Any, Any}} where N","page":"Symmetric positive definite","title":"ManifoldsBase.distance","text":"distance(M::MetricManifold{SymmetricPositiveDefinite,LogCholeskyMetric}, p, q)\n\nCompute the distance on the manifold of SymmetricPositiveDefinite nmatrices, i.e. between two symmetric positive definite matrices p and q with respect to the LogCholeskyMetric. The formula reads\n\nd_mathcal P(n)(pq) = sqrt\n lVert x - y rVert_mathrmF^2\n + lVert log(operatornamediag(x)) - log(operatornamediag(y))rVert_mathrmF^2 \n\nwhere x and y are the cholesky factors of p and q, respectively, cdot denbotes the strictly lower triangular matrix of its argument, and lVertcdotrVert_mathrmF the Frobenius norm.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.inner-Union{Tuple{N}, Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite{N}, LogCholeskyMetric}, Any, Any, Any}} where N","page":"Symmetric positive definite","title":"ManifoldsBase.inner","text":"inner(M::MetricManifold{LogCholeskyMetric,ℝ,SymmetricPositiveDefinite}, p, X, Y)\n\nCompute the inner product of two matrices X, Y in the tangent space of p on the SymmetricPositiveDefinite manifold M, as a MetricManifold with LogCholeskyMetric. The formula reads\n\n g_p(XY) = a_z(X)a_z(Y)_z\n\nwhere cdotcdot_x denotes inner product on the CholeskySpace, z is the cholesky factor of p, a_z(W) = z (z^-1Wz^-mathrmT)_frac12, and (cdot)_frac12 denotes the lower triangular matrix with the diagonal multiplied by frac12\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.is_flat-Tuple{MetricManifold{ℝ, <:SymmetricPositiveDefinite, LogCholeskyMetric}}","page":"Symmetric positive definite","title":"ManifoldsBase.is_flat","text":"is_flat(::MetricManifold{ℝ,<:SymmetricPositiveDefinite,LogCholeskyMetric})\n\nReturn false. SymmetricPositiveDefinite with LogCholeskyMetric is not a flat manifold.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#ManifoldsBase.parallel_transport_to-Tuple{MetricManifold{ℝ, SymmetricPositiveDefinite, LogCholeskyMetric}, Any, Any, Any}","page":"Symmetric positive definite","title":"ManifoldsBase.parallel_transport_to","text":"vector_transport_to(\n M::MetricManifold{SymmetricPositiveDefinite,LogCholeskyMetric},\n p,\n X,\n q,\n ::ParallelTransport,\n)\n\nParallel transport the tangent vector X at p along the geodesic to q with respect to the SymmetricPositiveDefinite manifold M and LogCholeskyMetric. The parallel transport is based on the parallel transport on CholeskySpace: Let x and y denote the cholesky factors of p and q, respectively and W = x(x^-1Xx^-mathrmT)_frac12, where (cdot)_frac12 denotes the lower triangular matrix with the diagonal multiplied by frac12. With V the parallel transport on CholeskySpace from x to y. The formula hear reads\n\nmathcal P_qpX = yV^mathrmT + Vy^mathrmT\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Statistics","page":"Symmetric positive definite","title":"Statistics","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"Modules = [Manifolds]\nPages = [\"SymmetricPositiveDefinite.jl\"]\nOrder = [:function]\nFilter = t -> t === mean","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Statistics.mean-Tuple{SymmetricPositiveDefinite, Any}","page":"Symmetric positive definite","title":"Statistics.mean","text":"mean(\n M::SymmetricPositiveDefinite,\n x::AbstractVector,\n [w::AbstractWeights,]\n method = GeodesicInterpolation();\n kwargs...,\n)\n\nCompute the Riemannian mean of x using GeodesicInterpolation.\n\n\n\n\n\n","category":"method"},{"location":"manifolds/symmetricpositivedefinite.html#Efficient-representation","page":"Symmetric positive definite","title":"Efficient representation","text":"","category":"section"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"When a point p is used in several occasions, it might be beneficial to store the eigenvalues and vectors of p and optionally its square root and the inverse of the square root. The SPDPoint can be used for exactly that.","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"SPDPoint","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.SPDPoint","page":"Symmetric positive definite","title":"Manifolds.SPDPoint","text":"SPDPoint <: AbstractManifoldsPoint\n\nStore the result of eigen(p) of an SPD matrix and (optionally) p^12 and p^-12 to avoid their repeated computations.\n\nThis result only has the result of eigen as a mandatory storage, the other three can be stored. If they are not stored they are computed and returned (but then still not stored) when required.\n\nConstructor\n\nSPDPoint(p::AbstractMatrix; store_p=true, store_sqrt=true, store_sqrt_inv=true)\n\nCreate an SPD point using an symmetric positive defincite matrix p, where you can optionally store p, sqrt and sqrt_inv\n\n\n\n\n\n","category":"type"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"and there are three internal functions to be able to use SPDPoint interchangeably with the default representation as a matrix.","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html","page":"Symmetric positive definite","title":"Symmetric positive definite","text":"Manifolds.spd_sqrt\nManifolds.spd_sqrt_inv\nManifolds.spd_sqrt_and_sqrt_inv","category":"page"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.spd_sqrt","page":"Symmetric positive definite","title":"Manifolds.spd_sqrt","text":"spd_sqrt(p::AbstractMatrix)\nspd_sqrt(p::SPDPoint)\n\nreturn p^frac12 by either computing it (if it is missing or for the AbstractMatrix) or returning the stored value from within the SPDPoint.\n\nThis method assumes that p represents an spd matrix.\n\n\n\n\n\n","category":"function"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.spd_sqrt_inv","page":"Symmetric positive definite","title":"Manifolds.spd_sqrt_inv","text":"spd_sqrt_inv(p::SPDPoint)\n\nreturn p^-frac12 by either computing it (if it is missing or for the AbstractMatrix) or returning the stored value from within the SPDPoint.\n\nThis method assumes that p represents an spd matrix.\n\n\n\n\n\n","category":"function"},{"location":"manifolds/symmetricpositivedefinite.html#Manifolds.spd_sqrt_and_sqrt_inv","page":"Symmetric positive definite","title":"Manifolds.spd_sqrt_and_sqrt_inv","text":"spd_sqrt_and_sqrt_inv(p::AbstractMatrix)\nspd_sqrt_and_sqrt_inv(p::SPDPoint)\n\nreturn p^frac12 and p^-frac12 by either computing them (if they are missing or for the AbstractMatrix) or returning their stored value from within the SPDPoint.\n\nCompared to calling single methods spd_sqrt and spd_sqrt_inv this method only computes the eigenvectors once for the case of the AbstractMatrix or if both are missing.\n\nThis method assumes that p represents an spd matrix.\n\n\n\n\n\n","category":"function"},{"location":"manifolds/symmetricpositivedefinite.html#Literature","page":"Symmetric positive definite","title":"Literature","text":"","category":"section"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"EditURL = \"https://github.com/JuliaManifolds/Manifolds.jl/blob/master/CONTRIBUTING.md\"","category":"page"},{"location":"misc/contributing.html#Contributing-to-Manifolds.jl","page":"Contributing","title":"Contributing to Manifolds.jl","text":"","category":"section"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"First, thanks for taking the time to contribute. Any contribution is appreciated and welcome.","category":"page"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"The following is a set of guidelines to Manifolds.jl.","category":"page"},{"location":"misc/contributing.html#Table-of-Contents","page":"Contributing","title":"Table of Contents","text":"","category":"section"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"Contributing to Manifolds.jl - Table of Contents\nI just have a question\nHow can I file an issue?\nHow can I contribute?\nAdd a missing method\nProvide a new manifold\nCode style","category":"page"},{"location":"misc/contributing.html#I-just-have-a-question","page":"Contributing","title":"I just have a question","text":"","category":"section"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"The developers can most easily be reached in the Julia Slack channel #manifolds. You can apply for the Julia Slack workspace here if you haven't joined yet. You can also ask your question on discourse.julialang.org.","category":"page"},{"location":"misc/contributing.html#How-can-I-file-an-issue?","page":"Contributing","title":"How can I file an issue?","text":"","category":"section"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"If you found a bug or want to propose a feature, we track our issues within the GitHub repository.","category":"page"},{"location":"misc/contributing.html#How-can-I-contribute?","page":"Contributing","title":"How can I contribute?","text":"","category":"section"},{"location":"misc/contributing.html#Add-a-missing-method","page":"Contributing","title":"Add a missing method","text":"","category":"section"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"Not all methods from our interface ManifoldsBase.jl have been implemented for every manifold. If you notice a method missing and can contribute an implementation, please do so! Even providing a single new method is a good contribution.","category":"page"},{"location":"misc/contributing.html#Provide-a-new-manifold","page":"Contributing","title":"Provide a new manifold","text":"","category":"section"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"A main contribution you can provide is another manifold that is not yet included in the package. A manifold is a concrete type of AbstractManifold from ManifoldsBase.jl. This package also provides the main set of functions a manifold can/should implement. Don't worry if you can only implement some of the functions. If the application you have in mind only requires a subset of these functions, implement those. The ManifoldsBase.jl interface provides concrete error messages for the remaining unimplemented functions.","category":"page"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"One important detail is that the interface usually provides an in-place as well as a non-mutating variant See for example exp! and exp. The non-mutating one (e.g. exp) always falls back to use the in-place one, so in most cases it should suffice to implement the in-place one (e.g. exp!).","category":"page"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"Note that since the first argument is always the AbstractManifold, the mutated argument is always the second one in the signature. In the example we have exp(M, p, X, t) for the exponential map and exp!(M, q, p, X, t) for the in-place one, which stores the result in q.","category":"page"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"On the other hand, the user will most likely look for the documentation of the non-mutating version, so we recommend adding the docstring for the non-mutating one, where all different signatures should be collected in one string when reasonable. This can best be achieved by adding a docstring to the method with a general signature with the first argument being your manifold:","category":"page"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"struct MyManifold <: AbstractManifold end\n\n@doc raw\"\"\"\n exp(M::MyManifold, p, X)\n\nDescribe the function.\n\"\"\"\nexp(::MyManifold, ::Any...)","category":"page"},{"location":"misc/contributing.html#Code-style","page":"Contributing","title":"Code style","text":"","category":"section"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"We try to follow the documentation guidelines from the Julia documentation as well as Blue Style. We run JuliaFormatter.jl on the repo in the way set in the .JuliaFormatter.toml file, which enforces a number of conventions consistent with the Blue Style.","category":"page"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"We also follow a few internal conventions:","category":"page"},{"location":"misc/contributing.html","page":"Contributing","title":"Contributing","text":"It is preferred that the AbstractManifold's struct contain a reference to the general theory.\nAny implemented function should be accompanied by its mathematical formulae if a closed form exists.\nWithin the source code of one manifold, the type of the manifold should be the first element of the file, and an alphabetical order of the functions is preferable.\nThe above implies that the in-place variant of a function follows the non-mutating variant.\nThere should be no dangling = signs.\nAlways add a newline between things of different types (struct/method/const).\nAlways add a newline between methods for different functions (including in-place/nonmutating variants).\nPrefer to have no newline between methods for the same function; when reasonable, merge the docstrings.\nAll import/using/include should be in the main module file.","category":"page"}] +} diff --git a/previews/PR644/siteinfo.js b/previews/PR644/siteinfo.js new file mode 100644 index 0000000000..577afa65df --- /dev/null +++ b/previews/PR644/siteinfo.js @@ -0,0 +1 @@ +var DOCUMENTER_CURRENT_VERSION = "previews/PR644"; diff --git a/previews/PR644/tutorials/getstarted.html b/previews/PR644/tutorials/getstarted.html new file mode 100644 index 0000000000..486c7591fc --- /dev/null +++ b/previews/PR644/tutorials/getstarted.html @@ -0,0 +1,56 @@ + +🚀 Get Started with Manifolds.jl · Manifolds.jl

    🚀 Get Started with Manifolds.jl

    This is a short overview of Manifolds.jl and how to get started working with your first Manifold. we first need to install the package, using for example

    using Pkg; Pkg.add("Manifolds")

    Then you can load the package with

    using Manifolds
    [ Info: Precompiling ManifoldsRecipesBaseExt [37da849e-34ab-54fd-a5a4-b22599bd6cb0]

    Using the Library of Manifolds

    Manifolds.jl is first of all a library of manifolds, see the list in the menu here under “basic manifolds”.

    Let’s look at three examples together with the first few functions on manifolds.

    1. The Euclidean space

    The Euclidean Space Euclidean brings us (back) into linear case of vectors, so in terms of manifolds, this is a very simple one. It is often useful to compare to classical algorithms, or implementations.

    M₁ = Euclidean(3)
    Euclidean(3; field = ℝ)

    Since a manifold is a type in Julia, we write it in CamelCase. Its parameters are first a dimension or size parameter of the manifold, sometimes optional is a field the manifold is defined over.

    For example the above definition is the same as the real-valued case

    M₁ === Euclidean(3, field=ℝ)
    true

    But we even introduced a short hand notation, since ℝ is also just a symbol/variable to use”

    M₁ === ℝ^3
    true

    And similarly here are two ways to create the manifold of vectors of length two with complex entries – or mathematically the space $\mathbb C^2$

    Euclidean(2, field=ℂ) === ℂ^2
    true

    The easiest to check is the dimension of a manifold. Here we have three “directions to walk into” at every point $p\in \mathbb R ^3$ so 🔗 manifold_dimension) is

    manifold_dimension(M₁)
    3

    2. The hyperpolic space

    The $d$-dimensional hyperbolic space is usually represented in $\mathbb R^{d+1}$ as the set of points $p\in\mathbb R^3$ fulfilling

    \[p_1^2+p_2^2+\cdots+p_d^2-p_{d+1}^2 = -1.\]

    We define the manifold using

    M₂ = Hyperbolic(2)
    Hyperbolic(2)

    And we can again just start with looking at the manifold dimension of M₂

    manifold_dimension(M₂)
    2

    A next useful function is to check, whether some $p∈\mathbb R^3$ is a point on the manifold M₂. We can check

    is_point(M₂, [0, 0, 1])
    true

    or

    is_point(M₂, [1, 0, 1])
    false

    Keyword arguments are passed on to any numerical checks, for example an absolute tolerance when checking the above equiality.

    But in an interactive session an error message might be helpful. A positional (third) argument is present to activate this. Setting this parameter to true, we obtain an error message that gives insight into why the point is not a point on M₂. Note that the LoadError: is due to quarto, on REPL you would just get the DomainError.

    is_point(M₂, [0, 0, 1.001], true)
    LoadError: DomainError with -1.0020009999999997:
    +The point [0.0, 0.0, 1.001] does not lie on Hyperbolic(2) since its Minkowski inner product is not -1.

    3. The sphere

    The sphere $\mathbb S^d$ is the $d$-dimensional sphere represented in its embedded form, that is unit vectors $p \in \mathbb R^{d+1}$ with unit norm $\lVert p \rVert_2 = 1$.

    M₃ = Sphere(2)
    Sphere(2, ℝ)

    If we only have a point that is approximately on the manifold, we can allow for a tolerance. Usually these are the same values of atol and rtol alowed in isapprox, i.e. we get

    is_point(M₃, [0, 0, 1.001]; atol=1e-3)
    true

    Here we can show a last nice check: 🔗 is_vector to check whether a tangent vector X is a representation of a tangent vector $X∈T_p\mathcal M$ to a point p on the manifold.

    This function has two positional asrguments, the first to again indicate whether to throw an error, the second to disable the check that p is a valid point on the manifold. Usually this validity is essential for the tangent check, but if it was for example performed before, it can be turned off to spare time.

    For example in our first example the point is not of unit norm

    is_vector(M₃, [2, 0, 0], [0, 1, 1])
    false

    But the orthogonality of p and X is still valid, we can disable the point check, but even setting the error to true we get here

    is_vector(M₃, [2, 0, 0], [0, 1, 1], true, false)
    true

    But of course it is better to use a valid point in the first place

    is_vector(M₃, [1, 0, 0], [0, 1, 1])
    true

    and for these we again get informative error messages

    @expect_error is_vector(M₃, [1, 0, 0], [0.1, 1, 1], true) DomainError
    LoadError: LoadError: UndefVarError: `@expect_error` not defined
    +in expression starting at In[19]:1

    To learn about how to define a manifold youself check out the 🔗 How to define your own manifold tutorial of 🔗 ManifoldsBase.jl.”

    Building more advanced manifolds

    Based on these basic manifolds we can directly build more advanced manifolds.

    The first one concerns vectors or matrices of data on a manifold, the PowerManifold.

    M₄ = M₂^2
    PowerManifold(Hyperbolic(2), 2)

    Then points are represented by arrays, where the power manifold dimension is added in the end. In other words – for the hyperbolic manifold here, we have a matrix with 2 columns, where each column is a valid point on hyperbolic space.

    p = [0 0; 0 1; 1 sqrt(2)]
    3×2 Matrix{Float64}:
    + 0.0  0.0
    + 0.0  1.0
    + 1.0  1.41421
    [is_point(M₂, p[:, 1]), is_point(M₂, p[:, 2])]
    2-element Vector{Bool}:
    + 1
    + 1

    But of course the method we used previously also works for power manifolds:

    is_point(M₄, p)
    true

    Note that nested power manifolds are combined into one as in

    M₄₂ = M₄^4
    PowerManifold(Hyperbolic(2), 2, 4)

    which represents $2\times 4$ – matrices of hyperbolic points represented in $3\times 2\times 4$ arrays.

    We can – alternatively – use a power manifold with nested arrays

    M₅ = PowerManifold(M₃, NestedPowerRepresentation(), 2)
    PowerManifold(Sphere(2, ℝ), NestedPowerRepresentation(), 2)

    which emphasizes that we have vectors of length 2 that contain points, so we store them that way.

    p₂ = [[0.0, 0.0, 1.0], [0.0, 1.0, 0.0]]
    2-element Vector{Vector{Float64}}:
    + [0.0, 0.0, 1.0]
    + [0.0, 1.0, 0.0]

    To unify both representations, elements of the power manifold can also be accessed in the classical indexing fashion, if we start with the corresponding manifold first. This way one can implement algorithms also independent of which representation is used.”

    p[M₄, 1]
    3-element Vector{Float64}:
    + 0.0
    + 0.0
    + 1.0
    p₂[M₅, 2]
    3-element Vector{Float64}:
    + 0.0
    + 1.0
    + 0.0

    Another construtor is the ProductManifold to combine different manifolds. Here of course the order matters. First we construct these using $×$

    M₆ = M₂ × M₃
    ProductManifold with 2 submanifolds:
    + Hyperbolic(2)
    + Sphere(2, ℝ)

    Since now the representations might differ from element to element, we have to encapsulate these in their own type.

    p₃ = Manifolds.ArrayPartition([0, 0, 1], [0, 1, 0])
    ([0, 0, 1], [0, 1, 0])

    Here ArrayPartition taken from 🔗 RecursiveArrayTools.jl to store the point on the product manifold efficiently in one array, still allowing efficient access to the product elements.

    is_point(M₆, p₃, true)
    true

    But accessing single components still works the same.”

    p₃[M₆, 1]
    3-element Vector{Int64}:
    + 0
    + 0
    + 1

    Finally, also the TangentBundle, the manifold collecting all tangent spaces on a manifold is available as”

    M₇ = TangentBundle(M₃)
    TangentBundle(Sphere(2, ℝ))

    Implementing generic Functions

    In this section we take a look how to implement generic functions on manifolds.

    For our example here, we want to implement the so-called 📖 Bézier curve using the so-called 📖 de-Casteljau algorithm. The linked algorithm can easily be generalised to manifolds by replacing lines with geodesics. This was for example used in [1] and the following example is an extended version of an example from [2].

    The algorithm works recursively. For the case that we have a Bézier curve with just two points, the algorithm just evaluates the geodesic connecting both at some time point $t∈[0,1]$. The function to evaluate a shortest geodesic (it might not be unique, but then a deterministic choice is taken) between two points p and q on a manifold M 🔗 shortest_geodesic(M, p, q, t).

    function de_Casteljau(M::AbstractManifold, t, pts::NTuple{2})
    +    return shortest_geodesic(M, pts[1], pts[2], t)
    +end
    de_Casteljau (generic function with 1 method)
    function de_Casteljau(M::AbstractManifold, t, pts::NTuple)
    +    p = de_Casteljau(M, t, pts[1:(end - 1)])
    +    q = de_Casteljau(M, t, pts[2:end])
    +    return shortest_geodesic(M, p, q, t)
    +end
    de_Casteljau (generic function with 2 methods)

    Which can now be used on any manifold where the shortest geodesic is implemented

    Now on several manifolds the 📖 exponential map and its (locally defined) inverse, the logarithmic map might not be available in an implementation. So one way to generalise this, is the use of a retraction (see [3], Def. 4.1.1 for details) and its (local) inverse.

    The function itself is quite similar to the expponential map, just that 🔗 retract(M, p, X, m) has one further parameter, the type of retraction to take, so m is a subtype of AbstractRetractionMethod m, the same for the 🔗 inverse_retract(M, p, q, n) with an AbstractInverseRetractionMethod n.

    Thinking of a generic implementation, we would like to have a way to specify one, that is available. This can be done by using 🔗 default_retraction_method and 🔗 default_inverse_retraction_method, respectively. We implement

    function generic_de_Casteljau(
    +    M::AbstractManifold,
    +    t,
    +    pts::NTuple{2};
    +    m::AbstractRetractionMethod=default_retraction_method(M),
    +    n::AbstractInverseRetractionMethod=default_inverse_retraction_method(M),
    +)
    +    X = inverse_retract(M, pts[1], pts[2], n)
    +    return retract(M, pts[1], X, t, m)
    +end
    generic_de_Casteljau (generic function with 1 method)

    and for the recursion

    function generic_de_Casteljau(
    +    M::AbstractManifold,
    +    t,
    +    pts::NTuple;
    +    m::AbstractRetractionMethod=default_retraction_method(M),
    +    n::AbstractInverseRetractionMethod=default_inverse_retraction_method(M),
    +)
    +    p = generic_de_Casteljau(M, t, pts[1:(end - 1)]; m=m, n=n)
    +    q = generic_de_Casteljau(M, t, pts[2:end]; m=m, n=n)
    +    X = inverse_retract(M, p, q, n)
    +    return retract(M, p, X, t, m)
    +end
    generic_de_Casteljau (generic function with 2 methods)

    Note that on a manifold M where the exponential map is implemented, the default_retraction_method(M) returns 🔗 ExponentialRetraction, which yields that the retract function falls back to calling exp.

    The same mechanism exists for 🔗 parallel_transport_to(M, p, X, q) and the more general 🔗 vector_transport_to(M, p, X, q, m) whose 🔗 AbstractVectorTransportMethod m has a default defined by 🔗 default_vector_transport_method(M).

    Allocating and in-place computations

    Memory allocation is a 🔗 critical performace issue when programming in Julia. To take this into account, Manifolds.jl provides special functions to reduce the amount of allocations.

    We again look at the 📖 exponential map. On a manifold M the exponential map needs a point p (to start from) and a tangent vector X, which can be seen as direction to “walk into” as well as the length to walk into this direction. In Manifolds.jl the function can then be called with q = exp(M, p, X) (see 🔗 exp(M, p, X)). This function returns the resulting point q, which requires to allocate new memory.

    To avoid this allocation, the function 🔗 exp!(M, q, p, X) can be called. Here q is allocated beforehand and is passed as the memory, where the result is returned in. It might be used even for interims computations, as long as it does not introduce side effects. Thas means that even with exp!(M, p, p, X) the result is correct.

    Let’s look at an example.

    We take another look at the Sphere, but now a high-dimensional one. We can also illustrate how to generate radnom points and tangent vectors.

    M = Sphere(10000)
    +p₄ = rand(M)
    +X = rand(M; vector_at=p₄)

    Looking at the allocations required we get

    @allocated exp(M, p₄, X)
    9921279

    While if we have already allocated memory for the resulting point on the manifold, for example

    q₂ = zero(p₄);

    There are no new memory allocations necessary if we use the in-place function.”

    @allocated exp!(M, q₂, p₄, X)
    0

    This methodology is used for all functions that compute a new point or tangent vector. By default all allocating functions allocate memory and call the in-place function. This also means that if you implement a new manifold, you just have to implement the in-place version.

    Decorating a manifold

    As you saw until now, an 🔗 AbstractManifold describes a Riemannian manifold. For completeness, this also includes the chosen 📖 Riemannian metric tensor or inner product on the tangent spaces.

    In Manifolds.jl these are assumed to be a “reasonable default”. For example on the Sphere(n) we used above, the default metric is the one inherited from restricting the inner product from the embedding space onto each tangent space.

    Consider a manifold like

    M₈ = SymmetricPositiveDefinite(3)
    SymmetricPositiveDefinite(3)

    which is the manifold of $3×3$ matrices that are symmetric and positive definite. which has a default as well, the affine invariant AffineInvariantMetric, but also has several different metrics.

    To switch the metric, we use the idea of a 📖 decorator pattern approach. Defining

    M₈₂ = MetricManifold(M₈, BuresWassersteinMetric())
    MetricManifold(SymmetricPositiveDefinite(3), BuresWassersteinMetric())

    changes the manifold to use the BuresWassersteinMetric.

    This changes all functions that depend on the metric, most prominently the Riemannian matric, but also the exponential and logarithmic map and hence also geodesics.

    All functions that are not dependent on a metric – for example the manifold dimension, the tests of points and vectors we already looked at, but also all retractions – stay unchanged. This means that for example

    [manifold_dimension(M₈₂), manifold_dimension(M₈)]
    2-element Vector{Int64}:
    + 6
    + 6

    both calls the same underlying function. On the other hand with

    p₅, X₅ = one(zeros(3, 3)), [1.0 0.0 1.0; 0.0 1.0 0.0; 1.0 0.0 1.0]
    ([1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0], [1.0 0.0 1.0; 0.0 1.0 0.0; 1.0 0.0 1.0])

    but for example the exponential map and the norm yield different results

    [exp(M₈, p₅, X₅), exp(M₈₂, p₅, X₅)]
    2-element Vector{Matrix{Float64}}:
    + [4.194528049465325 0.0 3.194528049465325; 0.0 2.718281828459045 0.0; 3.194528049465325 0.0 4.194528049465328]
    + [2.5 0.0 1.5; 0.0 2.25 0.0; 1.5 0.0 2.5]
    [norm(M₈, p₅, X₅), norm(M₈₂, p₅, X₅)]
    2-element Vector{Float64}:
    + 2.23606797749979
    + 1.118033988749895

    Technically this done using Traits – the trait here is the IsMetricManifold trait. Our trait system allows to combine traits but also to inherit properties in a hierarchical way, see 🔗 here for the technical details.

    The same approach is used for

    Again, for all of these, the concrete types only have to be used if you want to do a second, different from the details, property, for example a second way to embed a manfiold. If a manifold is (in its usual representation) an embedded manifold, this works with the default manifold type already, since then it is again set as the reasonable default.

    References

    [1]

    Bergmann, R. and Gousenbourger, P.-Y.: A variational model for data fitting on manifolds by minimizing the acceleration of a Bézier curve. Frontiers in Applied Mathematics and Statistics, 2018. doi: 10.3389/fams.2018.00059, arXiv: 1807.10090

    [2]

    Axen, S. D., Baran, M., Bergmann, R. and Rzecki, K: Manifolds.jl: An Extensible Julia Framework for Data Analysis on Manifolds, arXiv preprint, 2022, 2106.08777

    [3]

    Absil, P.-A., Mahony, R. and Sepulchre R., Optimization Algorithms on Matrix Manifolds Princeton University Press, 2008, doi: 10.1515/9781400830244 open access

    diff --git a/previews/PR644/tutorials/hand-gestures.html b/previews/PR644/tutorials/hand-gestures.html new file mode 100644 index 0000000000..c8734c9ee0 --- /dev/null +++ b/previews/PR644/tutorials/hand-gestures.html @@ -0,0 +1,103 @@ + +perform Hand gesture analysis · Manifolds.jl

    Hand gesture analysis

    In this tutorial we will learn how to use Kendall’s shape space to analyze hand gesture data.

    Let’s start by loading libraries required for our work.

    using Manifolds, CSV, DataFrames, Plots, MultivariateStats

    Our first function loads dataset of hand gestures, described here.

    function load_hands()
    +    hands_url = "https://raw.githubusercontent.com/geomstats/geomstats/master/geomstats/datasets/data/hands/hands.txt"
    +    hand_labels_url = "https://raw.githubusercontent.com/geomstats/geomstats/master/geomstats/datasets/data/hands/labels.txt"
    +
    +    hands = Matrix(CSV.read(download(hands_url), DataFrame, header=false))
    +    hands = reshape(hands, size(hands, 1), 3, 22)
    +    hand_labels = CSV.read(download(hand_labels_url), DataFrame, header=false).Column1
    +    return hands, hand_labels
    +end
    load_hands (generic function with 1 method)

    The following code plots a sample gesture as a 3D scatter plot of points.

    hands, hand_labels = load_hands()
    +scatter3d(hands[1, 1, :], hands[1, 2, :], hands[1, 3, :])

    Each gesture is represented by 22 landmarks in $ℝ³$, so we use the appropriate Kendall’s shape space

    Mshape = KendallsShapeSpace(3, 22)
    KendallsShapeSpace{3, 22}()

    Hands read from the dataset are projected to the shape space to remove translation and scaling variability. Rotational variability is then handled using the quotient structure of KendallsShapeSpace

    hands_projected = [project(Mshape, hands[i, :, :]) for i in axes(hands, 1)]

    In the next part let’s do tangent space PCA. This starts with computing a mean point and computing logithmic maps at mean to each point in the dataset.

    mean_hand = mean(Mshape, hands_projected)
    +hand_logs = [log(Mshape, mean_hand, p) for p in hands_projected]

    For a tangent PCA, we need coordinates in a basis. Some libraries skip this step because the representation of tangent vectors forms a linear subspace of an Euclidean space so PCA automatically detects which directions have no variance but this is a more generic way to solve this issue.

    B = get_basis(Mshape, mean_hand, ProjectedOrthonormalBasis(:svd))
    +hand_log_coordinates = [get_coordinates(Mshape, mean_hand, X, B) for X in hand_logs]

    This code prepares data for MultivariateStats – mean=0 is set because we’ve centered the data geometrically to mean_hand in the code above.

    red_coords = reduce(hcat, hand_log_coordinates)
    +fp = fit(PCA, red_coords; mean=0)
    PCA(indim = 59, outdim = 18, principalratio = 0.9900213563800988)
    +
    +Pattern matrix (unstandardized loadings):
    +─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    +            PC1           PC2           PC3           PC4           PC5           PC6           PC7           PC8           PC9          PC10          PC11          PC12          PC13          PC14          PC15          PC16          PC17          PC18
    +─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    +1   -0.0290105    0.0208927    -0.01643       0.00190549    0.00901145    0.000643771  -0.00363047   -0.00217327    0.00312554   -0.00356053    0.00478045    0.00165704    0.00218866    0.0037857     0.000320345  -0.00145212    0.000948335  -0.00184176
    +2    0.0172527    0.0165863    -0.0168821    -0.0183233     0.0121555     0.00833736    0.00187667   -0.000648234   0.00706323    0.00583622   -0.0044018     0.0012355     0.00118376   -0.00246016    0.00446684   -0.00498993   -0.0028049    -0.00259758
    +3    0.0447499   -0.00487667   -0.00247071   -0.00148697   -0.00200127   -0.00795338    0.00905314    0.00687454    0.0114088    -0.000998774   0.00459101    0.00645948    0.00073043    0.00591995   -0.00520394    0.00129428   -0.000463386  -0.00207384
    +4   -0.00881422  -0.0341713     0.00749624    0.00795209   -0.00260601    0.00356386    0.00204456   -0.00905276    0.00826807    0.00012095    0.000768538  -0.000460691   0.00411022   -0.00216294   -0.000650028   0.00251224    0.00149784   -0.00181133
    +5    0.0325794   -0.023796      0.000642765   0.00509869    0.00759807    0.00483368   -0.00252952    0.00656179    0.00322274   -0.000313146   0.00143493   -0.000676479   0.000146354  -0.00266203    0.00353957    0.0021415    -0.00457168    0.00282965
    +6   -0.00617763   6.91201e-5    0.00765638    0.00183758    0.00157382    0.00184956   -0.00797935    0.000700457   0.0087012     0.00992564    0.00263642    0.00294279   -0.0092        0.00133877    0.00145735   -0.0014816     0.00235123   -0.00039541
    +7   -0.0183122    0.0131045     0.0125222    -0.00638021   -0.006709     -0.00013628    0.00858169   -0.00159031   -0.00585433   -0.0032447     0.00880912   -0.00149308    0.000724205   0.00469925    0.00432005    0.0012382    -0.00251638    6.89878e-5
    +8    0.0392874   -0.0152552    -0.00404674   -0.0183856    -0.0054739     0.000203488   0.00687526    0.00989129   -0.00570517    0.00234255   -0.00221344   -0.00514796    0.000658069   0.00220789    7.02581e-5    0.000380265   0.0007751     0.00234631
    +9   -0.00525049  -0.0181427    -0.00473895   -0.0128126     0.000405834  -0.00936332   -0.000781745   0.011196     -0.00498502    0.00199077    0.00355555   -0.00334398    0.00763648    0.000311697  -0.000844841  -0.00526438   -0.00201977    0.00188678
    +10   0.0771681    0.0248294    -0.00375548   -0.0138712    -0.0126479    -0.00543573   -0.0136609    -0.00408721   -0.00445726   -0.00407287    0.00696664   -0.00158737   -0.00201909   -0.00211184    0.000907502   0.00235338   -0.00259266    0.00114594
    +11  -0.0013693    0.0125762    -0.00145726    0.0119688    -0.00362363    0.00954477    0.000894749   0.00311196    0.000186917   0.00923739    0.0036434     0.00484736    0.000288834  -0.00269382   -0.00194147   -0.000702207  -0.00245996   -0.000458531
    +12   0.00497523   0.0154863     0.0409999    -0.00832204   -0.00216091    0.0149159     0.011796      0.0121391    -0.00292353   -0.00532504   -0.00427894    0.000550893  -0.00408841    0.000520159  -0.00344571    0.000625647   0.000271049  -0.00165807
    +13  -0.0541357   -0.0291498     0.0140122     0.00292223    0.00128359    0.00301256   -0.00581861   -0.00397323    0.000588485   0.0025976    -0.00442985   -0.00603182    0.00326815    0.00326603    0.000384467  -0.00134404   -0.00160027   -0.00261985
    +14  -0.0493144    0.0120223    -0.0163111     0.0103746    -0.0126512    -0.011453      0.00488614   -0.00586095    0.0027455    -0.00434342    0.00203457   -0.000941868  -0.00426973   -0.00447805   -0.00239537   -0.00320013    0.000877498   0.000673572
    +15  -0.00654048   0.00225524   -0.028207      0.00306531    0.00321072   -0.000599231   0.00320363   -0.0059508    -0.00586048    0.0031903    -0.00613799    0.00471076   -0.00101853    0.00294667   -0.000548534   0.00402922    0.000405583   2.6607e-5
    +16   0.0300802    0.0075843     0.00364836   -0.00205771   -0.0148831     0.0211394    -0.000508637   0.0036868     0.0109845    -0.00574404   -0.00920237    0.0007153     0.000544823  -0.00209521    0.000474541  -0.00052208    0.00180017    0.00202094
    +17  -0.0110775    0.0373997    -0.00242133    0.00827109   -0.000567586  -0.0141686    -0.000939656   0.00843637   -0.00590348    0.00649057    0.00259619   -0.000897277   0.00443368   -0.0047585    -0.00160148    0.000335684   0.00152076   -0.00300398
    +18   0.0391783    0.0248007     0.0308429     0.00118303    0.00981074    0.00261316   -0.00100239   -0.0062546    -0.00491006   -0.00506867    0.00441608   -0.00367774   -0.00481009   -0.000493728  -0.00329753    0.000419403   0.000711267   0.000406243
    +19   0.0138738   -0.0443171    -0.00598066    0.00585226    0.00596223    0.00680714   -0.0079294    -0.00269779   -0.00426069   -0.00718608    0.00761514    0.00336824   -0.00295577   -0.00264683    0.00316699   -0.000418376  -0.00240164   -0.00413196
    +20   0.0173164   -0.0215417     0.000863689  -0.0205664     0.00121695    0.00307745    0.00191828   -0.00849558   -0.00147893    0.00180504    0.00814434    0.00372913    0.00188294   -0.00170647   -0.00451407   -0.00100769   -0.000238128  -0.000257117
    +21   0.00338984   0.00237562    0.0237069    -0.0129184     0.00148197   -0.000855367   0.00148785    0.00142366    0.00320966    0.00781237    0.000800995  -0.000516126   0.00440079   -0.0079143     0.00215576    0.00201592   -0.000335618   0.00337192
    +22  -0.00746071  -0.0116344     0.0021644     0.0152239     0.00723169    0.0120803    -0.000485058   0.00653526    0.0026666     0.00152026    0.0135607    -0.00247612    0.00348543    3.45051e-6    0.0017885     0.000179426  -0.000524643  -0.000805656
    +23   0.0478442   -0.0227649    -0.0113793    -0.00367693    0.0106966     0.00169994    0.0135303    -0.00344929    0.000128235   0.00063693   -0.00225447    0.000880574  -0.00665083   -0.0050547    -0.00295617   -0.00422433    0.00166798   -0.00189465
    +24  -0.0142467    0.0166931     0.00516018    0.00593988   -0.0210703     0.00438546    0.00643305    0.00174866    0.00505729    0.000463517   0.00763753   -0.00417294   -0.00156206    0.00540319   -0.00301265   -0.00408336   -0.00144362   -0.000137294
    +25   0.00108012   0.0195339     0.011519      0.0110158     0.00193433    0.0107534    -0.00146174    0.000236797   0.00226925   -0.00744152    0.00199678   -0.00445237    0.00273993   -0.000207735  -0.00191042    0.00121896    0.00195283   -0.00274164
    +26   0.0123466    0.0083253     0.00519553   -0.00196478    0.0137825    -0.00233978   -0.00771765   -0.00232805   -0.00279333    0.00340724    0.0012353    -0.00362154   -0.0013554     0.000632953  -2.37112e-5    0.00141247   -0.000568908  -0.000973567
    +27  -0.00893091   0.00641791    0.0087648     0.00424429   -0.000824081  -0.00761539   -0.0152518     0.00995065    0.00317758    8.84094e-5   -0.00419563   -0.00124495   -0.00589762   -0.000929293   0.00477719    0.00377025    0.00267074    0.000761405
    +28   0.0378644   -0.0125169     0.012799      0.0178141     0.00260966   -0.00752201    0.00299546   -0.00777486    0.00426756    0.00566038    0.00107451   -0.000215202  -0.00470252    0.00209217   -0.000578698   0.00150591   -0.00148331    0.00229085
    +29   0.00205475   0.0304241    -0.0354979     0.00394855   -0.00350914    0.00725592   -0.00678139    0.000307436  -0.00315394   -0.00689183    0.000456785   0.00368637    0.00277269   -0.00277076   -0.00422942    0.00223455    0.0015448    -0.00234455
    +30   0.0749975   -0.00999942    0.00367276    0.0100629    -0.00671752   -0.011357      0.00301586    0.000408736   0.00259563    0.000303288  -0.000111357  -0.00159763    0.00161827   -0.000545339   0.00377406    0.00268094    0.00406555   -0.00203144
    +31   0.0209729    0.00213421    0.00669869    0.016557      0.00403684   -0.0178951     0.0107244     0.0111298     0.00610797   -0.00390215   -0.00353771   -0.00178467    0.00235713    0.000973802   0.000274041   0.00218045   -0.00215689   -0.00158819
    +32  -0.0244084   -0.0371206     0.0192767    -0.000685794   0.0158289    -0.001451     -0.00509477    0.00577056   -0.00513049   -0.00950968   -0.00158958    0.000989458  -0.000699212   0.00122133   -0.000191417   0.000911926   0.00209233   -6.04374e-5
    +33   0.00565764  -0.0172793     0.00401092   -0.00793658    0.00504771   -0.00220381    0.00224319    0.0071918    -0.0124133     0.00175162    0.00348751    0.00633021   -0.00260535    0.00565187   -0.00186287   -0.000238933   0.000666333   0.00250607
    +34   0.00185581  -0.0166196    -0.0197269     0.00699341    0.00647246   -0.00303065   -0.000117067   0.00490106    0.00667588   -0.00855122    0.00302462    0.00173228    0.00553969   -0.00468124    0.00121978    0.0005079     0.000420239   0.00253235
    +35   0.0199811    0.0267965     0.0129649     0.00264194    0.000195136  -0.00349662    0.00294599   -0.00187851    0.00177767   -0.0053757    -0.00330811   -0.00295473    0.00208629   -6.97773e-5   -0.00153972   -0.000773065  -0.00157575   -0.000197057
    +36   0.0175704    0.0191343    -0.0116551     0.00882917   -0.0104714     0.0103777     0.00118041   -0.000696881   0.00192364    0.00744034    0.00497109   -0.00164206    0.00162482   -0.00139405    0.00167977    0.000693101  -0.00132024    0.00297973
    +37  -0.00462744  -0.013417      0.00735863    0.0138801    -0.0058212    -0.00238145   -0.00576575    0.00188503    0.00101854    0.0035232     0.0016009     0.00106877   -0.00593854   -0.0015165    -0.00563642   -0.000339869   0.00216456    0.002153
    +38  -0.0218719    0.00531191    0.00305154    0.0241393     0.0234907     0.00316473    0.0020773    -0.00469298   -0.00845531    0.00456344   -0.000534739   0.00131404   -0.00166945   -0.000113877  -0.00168502    0.00333815   -0.00307554    0.00114466
    +39  -0.00848638   0.0208304     0.00949937    0.0226454     0.0052942    -0.000851704   0.00632965    2.91971e-5    0.00329463    6.28469e-5    0.00660731    0.00235582   -0.00130279   -0.00141865    0.00530658   -0.00248136    0.000456183   0.00125713
    +40  -0.0887529   -0.0108083    -0.00348235   -0.0197061    -0.00851786   -0.00490488    0.00159713    0.00351037    0.0148414    -0.00401737    0.00779929    0.00245023   -0.00253298   -0.000226246  -0.000206421   0.00510786    0.00148421    0.00186788
    +41   0.00130006   0.00193007   -0.00297337    0.0070658     0.00888416    0.00665004   -0.013746      0.000961125   0.00363303    0.00316905    0.000576911  -0.00659932    0.00136165    0.0013939    -0.00380487   -0.00444913    0.00366095    0.00144111
    +42  -0.0207553    0.0174796    -0.00445662   -0.0117613     0.0273261    -0.00065484    0.00296882    0.00593266    0.00162045   -0.00318673    0.0066341    -0.0053347     0.000440878  -0.000644585  -0.00244859    0.00184264    0.00345959   -0.000426283
    +43   0.0413948    0.00307635   -0.00665062   -0.00226029    0.017443     -0.00424136    0.00950125   -0.00429922    0.00148225   -0.000166312   0.00294757   -0.00069645    0.000696539   0.000366659   0.00282844   -0.00230084    0.0053369     0.00238474
    +44   0.00449575   0.0201137     0.03094      -0.0058886    -0.00146264    0.0101428    -0.00516029    0.00543426   -0.00941967    0.000969442  -0.000431407   0.0064443     0.00115545   -0.00181689    0.00364823   -0.000426309   0.000849352  -0.00167685
    +45  -0.0205292   -0.00157548    0.013357     -0.00792343    0.00744915    0.00216668   -0.00243796    0.00180573    0.01512       0.00713893   -0.00283512    0.00430074    0.000788886   0.0049491     0.0029426    -0.00139686    0.00105337   -0.00239361
    +46  -0.0215505   -0.0112917     0.013841      0.0111599    -0.0105729     0.00953035    0.0113897    -0.00673481   -0.0100248     0.00344613    0.00262901    0.0047878     0.00566946   -6.60172e-5    0.00414744    0.00111141    0.00450865   -0.00145945
    +47  -0.0171993    0.0180146     0.00810394   -0.00791244    0.0061704     0.00923438    0.000727892  -0.0152243     0.00748635   -0.00599911   -0.00175649    0.00265434   -8.49398e-5    0.00305952   -0.00198115    0.00274446   -0.0028668     0.00323797
    +48   0.0587549    0.0116068    -0.00915491    0.00448539    0.0104133     0.00457871    0.00126112    0.00499596    0.00964989   -0.00404286    0.000207311   0.003728     -0.000433589  -0.000303131   0.00412588    0.000467283  -0.000916261  -0.00103631
    +49  -0.00166257   0.0250389     0.00797097    0.000683472  -0.000895449  -0.0133557    -0.00573426    0.000680622   0.00069621    0.00638431   -0.00245348    0.00498899    0.00507946    0.0057863    -0.00069408    0.0014596     0.000877213  -0.000692365
    +50  -0.0355097    0.0143079    -0.00981991    0.00946907   -0.00422843   -0.00254884    0.00491884    0.00651818   -0.00548423   -0.0071809     9.81603e-5    0.00390103   -0.00712449    0.0013088     0.00694234   -0.00320143    0.000147409   0.00234526
    +51   0.0456319   -0.0188437     0.00614929    0.01619      -0.0156405     0.00353768   -0.00911906    0.000874972  -0.00121217   -0.00403428   -0.000414905   0.00681573    0.00859836    0.00350106   -0.00263157   -0.00122084    0.00183226    0.00257702
    +52   0.00746721   0.0133773    -0.0340613    -0.0139034     0.00655522    0.00929538    0.000770716  -0.000483502  -0.00600155    0.00201797    0.0011251     0.00179484   -2.38878e-5    0.00486216    0.00282832    0.00255029    0.00367921    0.00129338
    +53   0.00823236  -0.00600734   -0.0200329     0.00202998   -0.0011313     0.0105144     0.00321895    0.00687414    0.000987698   0.00431901    0.000760463  -0.00635147   -0.00119575    0.00474285    4.40898e-5    0.00580837   -0.00332298   -0.00201341
    +54  -0.043754    -0.00171994   -0.00111157    0.00123094   -0.00428039    0.0027972     0.00934907   -0.00596239   -0.00226019    0.001642     -0.00513074   -0.00589632    0.00344517   -0.0042949     0.0025378     0.00306413    0.00186166    0.00125999
    +55   0.0430398   -0.000525733   0.0081576    -0.00839141   -0.00347855   -0.00933299    0.00251806   -0.0126012     0.002086      0.00272973    0.00204035   -0.000224255  -0.000607192  -0.000454776  -0.000157181   0.00250081    0.00145433   -0.00163108
    +56   0.0305092   -0.00319322   -0.010629      0.0139009     0.00442941    0.00855659    0.00087527   -0.00330425    0.000399393  -0.000737765  -0.00150343   -0.00754475    0.000704529   0.00851631    0.00185909   -0.00126123    0.00232031    0.00223781
    +57   0.00321453  -0.0190408    -0.0279848     0.00741802   -0.0157076     0.00592558    0.0020086     0.00843992   -0.00442316    0.00325392   -0.002545     -0.00268433   -0.00623548   -0.00142257   -0.00199612    0.0016597     0.000405685  -0.00229266
    +58   0.0156328   -0.0074322     0.0066988    -0.0114629    -0.0168092     0.00328227   -0.00226964   -0.00110748    0.000440872   0.00227572    0.00827165   -0.00488151   -0.00316671   -2.58046e-5    0.00360288    0.00115025    0.00316887   -0.00204823
    +59  -0.00151264   0.00426245    0.00115303    0.00338067    0.00957651    0.0116283     0.00361068    0.0102905     0.00246382    0.00700902    0.00252521    0.00257786    0.000578243  -0.00384276   -0.00597088    0.00283491    0.00171675    0.00226962
    +─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    +
    +Importance of components:
    +──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    +                                 PC1        PC2        PC3         PC4        PC5         PC6         PC7         PC8         PC9        PC10       PC11         PC12         PC13         PC14        PC15         PC16         PC17         PC18
    +──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    +SS Loadings (Eigenvalues)  0.0559745  0.0192925  0.0128414  0.00672244  0.0055061  0.00364815  0.00229962  0.00223028  0.00206984  0.00135745  0.00119    0.000805397  0.000775895  0.000619591  0.00052072  0.000351929  0.000282879  0.000224033
    +Variance explained         0.474806   0.16365    0.108928   0.0570235   0.0467058  0.0309456   0.0195066   0.0189185   0.0175575   0.0115146   0.0100942  0.00683182   0.00658157   0.00525572   0.00441704  0.00298526   0.00239954   0.00190038
    +Cumulative variance        0.474806   0.638456   0.747384   0.804407    0.851113   0.882059    0.901565    0.920484    0.938041    0.949556    0.95965    0.966482     0.973063     0.978319     0.982736    0.985721     0.988121     0.990021
    +Proportion explained       0.479592   0.165299   0.110026   0.0575982   0.0471765  0.0312575   0.0197032   0.0191092   0.0177345   0.0116307   0.010196   0.00690068   0.00664791   0.00530869   0.00446156  0.00301535   0.00242373   0.00191953
    +Cumulative proportion      0.479592   0.644891   0.754917   0.812515    0.859692   0.890949    0.910652    0.929761    0.947496    0.959127    0.969323   0.976223     0.982871     0.98818      0.992641    0.995657     0.99808      1.0
    +──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

    Now let’s show explained variance of each principal component.

    plot(principalvars(fp), title="explained variance", label="Tangent PCA")

    The next plot shows how projections on the first two pricipal components look like.

    fig = plot(; title="coordinates per gesture of the first two principal components")
    +for label_num in [0, 1]
    +    mask = hand_labels .== label_num
    +    cur_hand_logs = red_coords[:, mask]
    +    cur_t = MultivariateStats.transform(fp, cur_hand_logs)
    +    scatter!(fig, cur_t[1, :], cur_t[2, :], label="gesture " * string(label_num))
    +end
    +xlabel!(fig, "principal component 1")
    +ylabel!(fig, "principal component 2")
    +fig

    The following heatmap displays pairwise distances between gestures. We can use them for clustering, classification, etc.

    hand_distances = [
    +    distance(Mshape, hands_projected[i], hands_projected[j]) for
    +    i in eachindex(hands_projected), j in eachindex(hands_projected)
    +]
    +heatmap(hand_distances, aspect_ratio=:equal)

    diff --git a/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-11-output-1.svg b/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-11-output-1.svg new file mode 100644 index 0000000000..d5a9bd8363 --- /dev/null +++ b/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-11-output-1.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-12-output-1.svg b/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-12-output-1.svg new file mode 100644 index 0000000000..73b6efa70c --- /dev/null +++ b/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-12-output-1.svg @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-13-output-1.svg b/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-13-output-1.svg new file mode 100644 index 0000000000..b7e8ca9ea2 --- /dev/null +++ b/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-13-output-1.svg @@ -0,0 +1,643 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-5-output-1.svg b/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-5-output-1.svg new file mode 100644 index 0000000000..bd8d161017 --- /dev/null +++ b/previews/PR644/tutorials/hand-gestures_files/figure-commonmark/cell-5-output-1.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR644/tutorials/working-in-charts.html b/previews/PR644/tutorials/working-in-charts.html new file mode 100644 index 0000000000..62e1290e89 --- /dev/null +++ b/previews/PR644/tutorials/working-in-charts.html @@ -0,0 +1,79 @@ + +work in charts · Manifolds.jl

    Working in charts

    In this tutorial we will learn how to use charts for basic geometric operations like exponential map, logarithmic map and parallel transport.

    There are two conceptually different approaches to working on a manifold: working in charts and chart-free representations.

    The first one, widespread in differential geometry textbooks, is based on defining an atlas on the manifold and performing computations in selected charts. This approach, while generic, is not ideally suitable in all circumstances. For example, working in charts that do not cover the entire manifold causes issues with having to switch charts when operating on a manifold.

    The second one is beneficital, if there exist a representation of points and tangent vectors for a manifold, which allow for efficient closed-form formulas for standard functions like the exponential map or Riemannian distance in this representation. These computations are then chart-free. Manifolds.jl supports both approaches, although the chart-free approach is the main focus of the library.

    In this tutorial we focus on chart-based computation.

    using Manifolds, RecursiveArrayTools, OrdinaryDiffEq, DiffEqCallbacks, BoundaryValueDiffEq

    The manifold we consider is the M is the torus in form of the EmbeddedTorus, that is the representation defined as a surface of revolution of a circle of radius 2 around a circle of radius 3. The atlas we will perform computations in is its DefaultTorusAtlas A, consistting of a family of charts indexed by two angles, that specify the base point of the chart.

    We will draw geodesics time between 0 and t_end, and then sample the solution at multiples of dt and draw a line connecting sampled points.

    M = Manifolds.EmbeddedTorus(3, 2)
    +A = Manifolds.DefaultTorusAtlas()
    Manifolds.DefaultTorusAtlas()

    Setup

    We will first set up our plot with an empty torus. param_points are points on the surface of the torus that will be used for basic surface shape in Makie.jl. The torus will be colored according to its Gaussian curvature stored in gcs. We later want to have a color scale that has negative curvature blue, zero curvature white and positive curvature red so gcs_mm is the largest absolute value of the curvature that will be needed to properly set range of curvature values.

    In the documentation this tutorial represents a static situation (without interactivity). Makie.jl rendering is turned off.

    # using GLMakie, Makie
    +# GLMakie.activate!()
    +
    +"""
    +    torus_figure()
    +
    +This function generates a simple plot of a torus and returns the new figure containing the plot.
    +"""
    +function torus_figure()
    +    fig = Figure(resolution=(1400, 1000), fontsize=16)
    +    ax = LScene(fig[1, 1], show_axis=true)
    +    ϴs, φs = LinRange(-π, π, 50), LinRange(-π, π, 50)
    +    param_points = [Manifolds._torus_param(M, θ, φ) for θ in ϴs, φ in φs]
    +    X1, Y1, Z1 = [[p[i] for p in param_points] for i in 1:3]
    +    gcs = [gaussian_curvature(M, p) for p in param_points]
    +    gcs_mm = max(abs(minimum(gcs)), abs(maximum(gcs)))
    +    pltobj = surface!(
    +        ax,
    +        X1,
    +        Y1,
    +        Z1;
    +        shading=true,
    +        ambient=Vec3f(0.65, 0.65, 0.65),
    +        backlight=1.0f0,
    +        color=gcs,
    +        colormap=Reverse(:RdBu),
    +        colorrange=(-gcs_mm, gcs_mm),
    +        transparency=true,
    +    )
    +    wireframe!(ax, X1, Y1, Z1; transparency=true, color=:gray, linewidth=0.5)
    +    zoom!(ax.scene, cameracontrols(ax.scene), 0.98)
    +    Colorbar(fig[1, 2], pltobj, height=Relative(0.5), label="Gaussian curvature")
    +    return ax, fig
    +end
    torus_figure

    Values for the geodesic

    solve_for is a helper function that solves a parallel transport along geodesic problem on the torus M. p0x is the $(\theta, \varphi)$ parametrization of the point from which we will transport the vector. We first calculate the coordinates in the embedding of p0x and store it as p, and then get the initial chart from atlas A appropriate for starting working at point p. The vector we transport has coordinates Y_transp in the induced tangent space basis of chart i_p0x. The function returns the full solution to the parallel transport problem, containing the sequence of charts that was used and solutions of differential equations computed using OrdinaryDiffEq.

    bvp_i is needed later for a different purpose, it is the chart index we will use for solving the logarithmic map boundary value problem in.

    Next we solve the vector transport problem solve_for([θₚ, φₚ], [θₓ, φₓ], [θy, φy]), sample the result at the selected time steps and store the result in geo. The solution includes the geodesic which we extract and convert to a sequence of points digestible by Makie.jl, geo_ps. [θₚ, φₚ] is the parametrization in chart (0, 0) of the starting point of the geodesic. The direction of the geodesic is determined by [θₓ, φₓ], coordinates of the tangent vector at the starting point expressed in the induced basis of chart i_p0x (which depends on the initial point). Finally, [θy, φy] are the coordinates of the tangent vector that will be transported along the geodesic, which are also expressed in same basis as [θₓ, φₓ].

    We won’t draw the transported vector at every point as there would be too many arrows, which is why we select every 100th point only for that purpose with pt_indices. Then, geo_ps_pt contains points at which the transported vector is tangent to and geo_Ys the transported vector at that point, represented in the embedding.

    The logarithmic map will be solved between points with parametrization bvp_a1 and bvp_a2 in chart bvp_i. The result is assigned to variable bvp_sol and then sampled with time step 0.05. The result of this sampling is converted from parameters in chart bvp_i to point in the embedding and stored in geo_r.

    function solve_for(p0x, X_p0x, Y_transp, T)
    +    p = [Manifolds._torus_param(M, p0x...)...]
    +    i_p0x = Manifolds.get_chart_index(M, A, p)
    +    p_exp = Manifolds.solve_chart_parallel_transport_ode(
    +        M,
    +        [0.0, 0.0],
    +        X_p0x,
    +        A,
    +        i_p0x,
    +        Y_transp;
    +        final_time=T,
    +    )
    +    return p_exp
    +end;

    Solving parallel Transport ODE

    We set the end time t_end and time step dt.

    t_end = 2.0
    +dt = 1e-1
    0.1

    We also parametrise the start point and direction.

    θₚ = π/10
    +φₚ = -π/4
    +θₓ = π/2
    +φₓ = 0.7
    +θy = 0.2
    +φy = -0.1
    +
    +geo = solve_for([θₚ, φₚ], [θₓ, φₓ], [θy, φy], t_end)(0.0:dt:t_end);
    +# geo_ps = [Point3f(s[1]) for s in geo]
    +# pt_indices = 1:div(length(geo), 10):length(geo)
    +# geo_ps_pt = [Point3f(s[1]) for s in geo[pt_indices]]
    +# geo_Ys = [Point3f(s[3]) for s in geo[pt_indices]]
    +
    +# ax1, fig1 = torus_figure()
    +# arrows!(ax1, geo_ps_pt, geo_Ys, linewidth=0.05, color=:blue)
    +# lines!(geo_ps; linewidth=4.0, color=:green)
    +# fig1

    fig-pt

    Solving the logairthmic map ODE

    θ₁=π/2
    +φ₁=-1.0
    +θ₂=-π/8
    +φ₂=π/2
    +
    +bvp_i = (0, 0)
    +bvp_a1 = [θ₁, φ₁]
    +bvp_a2 = [θ₂, φ₂]
    +bvp_sol = Manifolds.solve_chart_log_bvp(M, bvp_a1, bvp_a2, A, bvp_i);
    +# geo_r = [Point3f(get_point(M, A, bvp_i, p[1:2])) for p in bvp_sol(0.0:0.05:1.0)]
    +
    +# ax2, fig2 = torus_figure()
    +# lines!(geo_r; linewidth=4.0, color=:green)
    +# fig2

    fig-geodesic

    An interactive Pluto version of this tutorial is available in file tutorials/working-in-charts.jl.

    diff --git a/previews/PR644/tutorials/working-in-charts/working-in-charts-geodesic.png b/previews/PR644/tutorials/working-in-charts/working-in-charts-geodesic.png new file mode 100644 index 0000000000..9a73057ffc Binary files /dev/null and b/previews/PR644/tutorials/working-in-charts/working-in-charts-geodesic.png differ diff --git a/previews/PR644/tutorials/working-in-charts/working-in-charts-transport.png b/previews/PR644/tutorials/working-in-charts/working-in-charts-transport.png new file mode 100644 index 0000000000..e1c54d4fb2 Binary files /dev/null and b/previews/PR644/tutorials/working-in-charts/working-in-charts-transport.png differ