diff --git a/stable b/stable index 0aaa265c9c..fdb7935d98 120000 --- a/stable +++ b/stable @@ -1 +1 @@ -v0.37.5 \ No newline at end of file +v0.37.6 \ No newline at end of file diff --git a/v0.37 b/v0.37 index 0aaa265c9c..fdb7935d98 120000 --- a/v0.37 +++ b/v0.37 @@ -1 +1 @@ -v0.37.5 \ No newline at end of file +v0.37.6 \ No newline at end of file diff --git a/v0.37.6/.documenter-siteinfo.json b/v0.37.6/.documenter-siteinfo.json new file mode 100644 index 0000000000..869b51c5e5 --- /dev/null +++ b/v0.37.6/.documenter-siteinfo.json @@ -0,0 +1 @@ +{"documenter":{"julia_version":"1.10.0","generation_timestamp":"2024-02-09T20:58:25","documenter_version":"1.2.1"}} \ No newline at end of file diff --git a/v0.37.6/assets/documenter.js b/v0.37.6/assets/documenter.js new file mode 100644 index 0000000000..f5311607bf --- /dev/null +++ b/v0.37.6/assets/documenter.js @@ -0,0 +1,889 @@ +// Generated by Documenter.jl +requirejs.config({ + paths: { + 'highlight-julia': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/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.13.2/jquery-ui.min', + 'minisearch': 'https://cdn.jsdelivr.net/npm/minisearch@6.1.0/dist/umd/index.min', + 'katex-auto-render': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/contrib/auto-render.min', + 'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.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.16.8/katex.min', + 'highlight': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min', + 'highlight-julia-repl': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/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(['jquery'], function($) { + +let timer = 0; +var isExpanded = true; + +$(document).on("click", ".docstring header", function () { + let articleToggleTitle = "Expand docstring"; + + debounce(() => { + if ($(this).siblings("section").is(":visible")) { + $(this) + .find(".docstring-article-toggle-button") + .removeClass("fa-chevron-down") + .addClass("fa-chevron-right"); + } else { + $(this) + .find(".docstring-article-toggle-button") + .removeClass("fa-chevron-right") + .addClass("fa-chevron-down"); + + articleToggleTitle = "Collapse docstring"; + } + + $(this) + .find(".docstring-article-toggle-button") + .prop("title", articleToggleTitle); + $(this).siblings("section").slideToggle(); + }); +}); + +$(document).on("click", ".docs-article-toggle-button", function () { + let articleToggleTitle = "Expand docstring"; + let navArticleToggleTitle = "Expand all docstrings"; + + debounce(() => { + if (isExpanded) { + $(this).removeClass("fa-chevron-up").addClass("fa-chevron-down"); + $(".docstring-article-toggle-button") + .removeClass("fa-chevron-down") + .addClass("fa-chevron-right"); + + isExpanded = false; + + $(".docstring section").slideUp(); + } else { + $(this).removeClass("fa-chevron-down").addClass("fa-chevron-up"); + $(".docstring-article-toggle-button") + .removeClass("fa-chevron-right") + .addClass("fa-chevron-down"); + + isExpanded = true; + articleToggleTitle = "Collapse docstring"; + navArticleToggleTitle = "Collapse all docstrings"; + + $(".docstring section").slideDown(); + } + + $(this).prop("title", navArticleToggleTitle); + $(".docstring-article-toggle-button").prop("title", articleToggleTitle); + }); +}); + +function debounce(callback, timeout = 300) { + if (Date.now() - timer > timeout) { + callback(); + } + + clearTimeout(timer); + + timer = Date.now(); +} + +}) +//////////////////////////////////////////////////////////////////////////////// +require([], function() { +function addCopyButtonCallbacks() { + for (const el of document.getElementsByTagName("pre")) { + const button = document.createElement("button"); + button.classList.add("copy-button", "fa-solid", "fa-copy"); + button.setAttribute("aria-label", "Copy this code block"); + button.setAttribute("title", "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-xmark"); + 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-xmark"); + }, 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', 'minisearch'], function($, minisearch) { + +// In general, most search related things will have "search" as a prefix. +// To get an in-depth about the thought process you can refer: https://hetarth02.hashnode.dev/series/gsoc + +let results = []; +let timer = undefined; + +let data = documenterSearchIndex["docs"].map((x, key) => { + x["id"] = key; // minisearch requires a unique for each object + return x; +}); + +// 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 +const stopWords = new Set([ + "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", +]); + +let index = new minisearch({ + fields: ["title", "text"], // fields to index for full-text search + storeFields: ["location", "title", "text", "category", "page"], // fields to return with search results + processTerm: (term) => { + let word = stopWords.has(term) ? null : term; + if (word) { + // custom trimmer that doesn't strip @ and !, which are used in julia macro and function names + word = word + .replace(/^[^a-zA-Z0-9@!]+/, "") + .replace(/[^a-zA-Z0-9@!]+$/, ""); + } + + return word ?? null; + }, + // add . as a separator, because otherwise "title": "Documenter.Anchors.add!", would not find anything if searching for "add!", only for the entire qualification + tokenize: (string) => string.split(/[\s\-\.]+/), + // options which will be applied during the search + searchOptions: { + boost: { title: 100 }, + fuzzy: 2, + processTerm: (term) => { + let word = stopWords.has(term) ? null : term; + if (word) { + word = word + .replace(/^[^a-zA-Z0-9@!]+/, "") + .replace(/[^a-zA-Z0-9@!]+$/, ""); + } + + return word ?? null; + }, + tokenize: (string) => string.split(/[\s\-\.]+/), + }, +}); + +index.addAll(data); + +let filters = [...new Set(data.map((x) => x.category))]; +var modal_filters = make_modal_body_filters(filters); +var filter_results = []; + +$(document).on("keyup", ".documenter-search-input", function (event) { + // Adding a debounce to prevent disruptions from super-speed typing! + debounce(() => update_search(filter_results), 300); +}); + +$(document).on("click", ".search-filter", function () { + if ($(this).hasClass("search-filter-selected")) { + $(this).removeClass("search-filter-selected"); + } else { + $(this).addClass("search-filter-selected"); + } + + // Adding a debounce to prevent disruptions from crazy clicking! + debounce(() => get_filters(), 300); +}); + +/** + * A debounce function, takes a function and an optional timeout in milliseconds + * + * @function callback + * @param {number} timeout + */ +function debounce(callback, timeout = 300) { + clearTimeout(timer); + timer = setTimeout(callback, timeout); +} + +/** + * Make/Update the search component + * + * @param {string[]} selected_filters + */ +function update_search(selected_filters = []) { + let initial_search_body = ` +
Type something to get started!
+ `; + + let querystring = $(".documenter-search-input").val(); + + if (querystring.trim()) { + results = index.search(querystring, { + filter: (result) => { + // Filtering results + if (selected_filters.length === 0) { + return result.score >= 1; + } else { + return ( + result.score >= 1 && selected_filters.includes(result.category) + ); + } + }, + }); + + let search_result_container = ``; + let search_divider = `
`; + + if (results.length) { + let links = []; + let count = 0; + let search_results = ""; + + results.forEach(function (result) { + if (result.location) { + // Checking for duplication of results for the same page + if (!links.includes(result.location)) { + search_results += make_search_result(result, querystring); + count++; + } + + links.push(result.location); + } + }); + + let result_count = `
${count} result(s)
`; + + search_result_container = ` +
+ ${modal_filters} + ${search_divider} + ${result_count} +
+ ${search_results} +
+
+ `; + } else { + search_result_container = ` +
+ ${modal_filters} + ${search_divider} +
0 result(s)
+
+
No result found!
+ `; + } + + if ($(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").removeClass("is-justify-content-center"); + } + + $(".search-modal-card-body").html(search_result_container); + } else { + filter_results = []; + modal_filters = make_modal_body_filters(filters, filter_results); + + if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").addClass("is-justify-content-center"); + } + + $(".search-modal-card-body").html(initial_search_body); + } +} + +/** + * Make the modal filter html + * + * @param {string[]} filters + * @param {string[]} selected_filters + * @returns string + */ +function make_modal_body_filters(filters, selected_filters = []) { + let str = ``; + + filters.forEach((val) => { + if (selected_filters.includes(val)) { + str += `${val}`; + } else { + str += `${val}`; + } + }); + + let filter_html = ` +
+ Filters: + ${str} +
+ `; + + return filter_html; +} + +/** + * Make the result component given a minisearch result data object and the value of the search input as queryString. + * To view the result object structure, refer: https://lucaong.github.io/minisearch/modules/_minisearch_.html#searchresult + * + * @param {object} result + * @param {string} querystring + * @returns string + */ +function make_search_result(result, querystring) { + let search_divider = `
`; + let display_link = + result.location.slice(Math.max(0), Math.min(50, result.location.length)) + + (result.location.length > 30 ? "..." : ""); // To cut-off the link because it messes with the overflow of the whole div + + if (result.page !== "") { + display_link += ` (${result.page})`; + } + + let textindex = new RegExp(`\\b${querystring}\\b`, "i").exec(result.text); + let text = + textindex !== null + ? result.text.slice( + Math.max(textindex.index - 100, 0), + Math.min( + textindex.index + querystring.length + 100, + result.text.length + ) + ) + : ""; // cut-off text before and after from the match + + let display_result = text.length + ? "..." + + text.replace( + new RegExp(`\\b${querystring}\\b`, "i"), // For first occurrence + '$&' + ) + + "..." + : ""; // highlights the match + + let in_code = false; + if (!["page", "section"].includes(result.category.toLowerCase())) { + in_code = true; + } + + // We encode the full url to escape some special characters which can lead to broken links + let result_div = ` + +
+
${result.title}
+
${result.category}
+
+

+ ${display_result} +

+
+ ${display_link} +
+
+ ${search_divider} + `; + + return result_div; +} + +/** + * Get selected filters, remake the filter html and lastly update the search modal + */ +function get_filters() { + let ele = $(".search-filters .search-filter-selected").get(); + filter_results = ele.map((x) => $(x).text().toLowerCase()); + modal_filters = make_modal_body_filters(filters, filter_results); + update_search(filter_results); +} + +}) +//////////////////////////////////////////////////////////////////////////////// +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($) { + +let search_modal_header = ` + +`; + +let initial_search_body = ` +
Type something to get started!
+`; + +let search_modal_footer = ` + +`; + +$(document.body).append( + ` + + ` +); + +document.querySelector(".docs-search-query").addEventListener("click", () => { + openModal(); +}); + +document.querySelector(".close-search-modal").addEventListener("click", () => { + closeModal(); +}); + +$(document).on("click", ".search-result-link", function () { + closeModal(); +}); + +document.addEventListener("keydown", (event) => { + if ((event.ctrlKey || event.metaKey) && event.key === "/") { + openModal(); + } else if (event.key === "Escape") { + closeModal(); + } + + return false; +}); + +// Functions to open and close a modal +function openModal() { + let searchModal = document.querySelector("#search-modal"); + + searchModal.classList.add("is-active"); + document.querySelector(".documenter-search-input").focus(); +} + +function closeModal() { + let searchModal = document.querySelector("#search-modal"); + let initial_search_body = ` +
Type something to get started!
+ `; + + searchModal.classList.remove("is-active"); + document.querySelector(".documenter-search-input").blur(); + + if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").addClass("is-justify-content-center"); + } + + $(".documenter-search-input").val(""); + $(".search-modal-card-body").html(initial_search_body); +} + +document + .querySelector("#search-modal .modal-background") + .addEventListener("click", () => { + closeModal(); + }); + +}) +//////////////////////////////////////////////////////////////////////////////// +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($) { + +// Theme picker setup +$(document).ready(function () { + // onchange callback + $("#documenter-themepicker").change(function themepick_callback(ev) { + var themename = $("#documenter-themepicker option:selected").attr("value"); + if (themename === "auto") { + // set_theme(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); + window.localStorage.removeItem("documenter-theme"); + } else { + // set_theme(themename); + window.localStorage.setItem("documenter-theme", themename); + } + // We re-use the global function from themeswap.js to actually do the swapping. + set_theme_from_local_storage(); + }); + + // 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; + }); + } + } +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +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/v0.37.6/assets/elements_diagram.svg b/v0.37.6/assets/elements_diagram.svg new file mode 100644 index 0000000000..00f248c364 --- /dev/null +++ b/v0.37.6/assets/elements_diagram.svg @@ -0,0 +1,162 @@ +SetElemIdealElem{T}Map{D, C, S, T}SetMapIdentityMapFunctionalMapFPModuleHomomorphismGroupElemAbstractPermAdditiveGroupElemModuleElem{T}FPModuleElem{T}MatElem{T}NCRingElemMatRingElem{T}NCPolyRingElem{T}RingElemPolyRingElem{T}SeriesElem{T}LaurentPolyRingElem{T}ResElem{T}FieldElemFinFieldElemResFieldElem{T}NumFieldElem{T}SimpleNumFieldElem{T}FracElem{T} \ No newline at end of file diff --git a/v0.37.6/assets/parents_diagram.svg b/v0.37.6/assets/parents_diagram.svg new file mode 100644 index 0000000000..93ac8313aa --- /dev/null +++ b/v0.37.6/assets/parents_diagram.svg @@ -0,0 +1,136 @@ +SetIdeal{T}GroupAbstractPermutationGroupAdditiveGroupModule{T}FPModule{T}MatSpace{T}NCRingMatRing{T}NCPolyRing{T}RingFieldPolyRing{T}LaurentPolyRing{T}SeriesRing{T}ResidueRing{T}ResidueField{T}NumField{T}SimpleNumField{T}FracField{T}FinField \ No newline at end of file diff --git a/v0.37.6/assets/themes/documenter-dark.css b/v0.37.6/assets/themes/documenter-dark.css new file mode 100644 index 0000000000..9f5449f4b9 --- /dev/null +++ b/v0.37.6/assets/themes/documenter-dark.css @@ -0,0 +1,7 @@ +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:1rem;height:2.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(0.5em - 1px);padding-left:calc(0.75em - 1px);padding-right:calc(0.75em - 1px);padding-top:calc(0.5em - 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}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{-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 .pagination:not(:last-child),html.theme--documenter-dark .message:not(:last-child),html.theme--documenter-dark .level:not(:last-child),html.theme--documenter-dark .breadcrumb: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{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,0.2);border:none;border-radius:9999px;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:9999px;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 .navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}/*! minireset.css v0.0.6 | 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,video{height:auto;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:inherit}.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-primary-light{color:#f1f5f9 !important}a.has-text-primary-light:hover,a.has-text-primary-light:focus{color:#cddbe9 !important}.has-background-primary-light{background-color:#f1f5f9 !important}.has-text-primary-dark{color:#4d7eb2 !important}a.has-text-primary-dark:hover,a.has-text-primary-dark:focus{color:#7198c1 !important}.has-background-primary-dark{background-color:#4d7eb2 !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-link-light{color:#edfdf9 !important}a.has-text-link-light:hover,a.has-text-link-light:focus{color:#c0f6ec !important}.has-background-link-light{background-color:#edfdf9 !important}.has-text-link-dark{color:#15987e !important}a.has-text-link-dark:hover,a.has-text-link-dark:focus{color:#1bc5a4 !important}.has-background-link-dark{background-color:#15987e !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-info-light{color:#ebf7ff !important}a.has-text-info-light:hover,a.has-text-info-light:focus{color:#b9e2fe !important}.has-background-info-light{background-color:#ebf7ff !important}.has-text-info-dark{color:#0e9dfb !important}a.has-text-info-dark:hover,a.has-text-info-dark:focus{color:#40b1fc !important}.has-background-info-dark{background-color:#0e9dfb !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-success-light{color:#ebfff3 !important}a.has-text-success-light:hover,a.has-text-success-light:focus{color:#b8ffd6 !important}.has-background-success-light{background-color:#ebfff3 !important}.has-text-success-dark{color:#00eb64 !important}a.has-text-success-dark:hover,a.has-text-success-dark:focus{color:#1fff7e !important}.has-background-success-dark{background-color:#00eb64 !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-warning-light{color:#fffaeb !important}a.has-text-warning-light:hover,a.has-text-warning-light:focus{color:#ffedb8 !important}.has-background-warning-light{background-color:#fffaeb !important}.has-text-warning-dark{color:#d19c00 !important}a.has-text-warning-dark:hover,a.has-text-warning-dark:focus{color:#ffbf05 !important}.has-background-warning-dark{background-color:#d19c00 !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-danger-light{color:#fdeeec !important}a.has-text-danger-light:hover,a.has-text-danger-light:focus{color:#fac3bd !important}.has-background-danger-light{background-color:#fdeeec !important}.has-text-danger-dark{color:#ec311d !important}a.has-text-danger-dark:hover,a.has-text-danger-dark:focus{color:#f05c4c !important}.has-background-danger-dark{background-color:#ec311d !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}.is-flex-direction-row{flex-direction:row !important}.is-flex-direction-row-reverse{flex-direction:row-reverse !important}.is-flex-direction-column{flex-direction:column !important}.is-flex-direction-column-reverse{flex-direction:column-reverse !important}.is-flex-wrap-nowrap{flex-wrap:nowrap !important}.is-flex-wrap-wrap{flex-wrap:wrap !important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse !important}.is-justify-content-flex-start{justify-content:flex-start !important}.is-justify-content-flex-end{justify-content:flex-end !important}.is-justify-content-center{justify-content:center !important}.is-justify-content-space-between{justify-content:space-between !important}.is-justify-content-space-around{justify-content:space-around !important}.is-justify-content-space-evenly{justify-content:space-evenly !important}.is-justify-content-start{justify-content:start !important}.is-justify-content-end{justify-content:end !important}.is-justify-content-left{justify-content:left !important}.is-justify-content-right{justify-content:right !important}.is-align-content-flex-start{align-content:flex-start !important}.is-align-content-flex-end{align-content:flex-end !important}.is-align-content-center{align-content:center !important}.is-align-content-space-between{align-content:space-between !important}.is-align-content-space-around{align-content:space-around !important}.is-align-content-space-evenly{align-content:space-evenly !important}.is-align-content-stretch{align-content:stretch !important}.is-align-content-start{align-content:start !important}.is-align-content-end{align-content:end !important}.is-align-content-baseline{align-content:baseline !important}.is-align-items-stretch{align-items:stretch !important}.is-align-items-flex-start{align-items:flex-start !important}.is-align-items-flex-end{align-items:flex-end !important}.is-align-items-center{align-items:center !important}.is-align-items-baseline{align-items:baseline !important}.is-align-items-start{align-items:start !important}.is-align-items-end{align-items:end !important}.is-align-items-self-start{align-items:self-start !important}.is-align-items-self-end{align-items:self-end !important}.is-align-self-auto{align-self:auto !important}.is-align-self-flex-start{align-self:flex-start !important}.is-align-self-flex-end{align-self:flex-end !important}.is-align-self-center{align-self:center !important}.is-align-self-baseline{align-self:baseline !important}.is-align-self-stretch{align-self:stretch !important}.is-flex-grow-0{flex-grow:0 !important}.is-flex-grow-1{flex-grow:1 !important}.is-flex-grow-2{flex-grow:2 !important}.is-flex-grow-3{flex-grow:3 !important}.is-flex-grow-4{flex-grow:4 !important}.is-flex-grow-5{flex-grow:5 !important}.is-flex-shrink-0{flex-shrink:0 !important}.is-flex-shrink-1{flex-shrink:1 !important}.is-flex-shrink-2{flex-shrink:2 !important}.is-flex-shrink-3{flex-shrink:3 !important}.is-flex-shrink-4{flex-shrink:4 !important}.is-flex-shrink-5{flex-shrink:5 !important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left !important}.is-pulled-right{float:right !important}.is-radiusless{border-radius:0 !important}.is-shadowless{box-shadow:none !important}.is-clickable{cursor:pointer !important;pointer-events:all !important}.is-clipped{overflow:hidden !important}.is-relative{position:relative !important}.is-marginless{margin:0 !important}.is-paddingless{padding:0 !important}.m-0{margin:0 !important}.mt-0{margin-top:0 !important}.mr-0{margin-right:0 !important}.mb-0{margin-bottom:0 !important}.ml-0{margin-left:0 !important}.mx-0{margin-left:0 !important;margin-right:0 !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.m-1{margin:.25rem !important}.mt-1{margin-top:.25rem !important}.mr-1{margin-right:.25rem !important}.mb-1{margin-bottom:.25rem !important}.ml-1{margin-left:.25rem !important}.mx-1{margin-left:.25rem !important;margin-right:.25rem !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.m-2{margin:.5rem !important}.mt-2{margin-top:.5rem !important}.mr-2{margin-right:.5rem !important}.mb-2{margin-bottom:.5rem !important}.ml-2{margin-left:.5rem !important}.mx-2{margin-left:.5rem !important;margin-right:.5rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.m-3{margin:.75rem !important}.mt-3{margin-top:.75rem !important}.mr-3{margin-right:.75rem !important}.mb-3{margin-bottom:.75rem !important}.ml-3{margin-left:.75rem !important}.mx-3{margin-left:.75rem !important;margin-right:.75rem !important}.my-3{margin-top:.75rem !important;margin-bottom:.75rem !important}.m-4{margin:1rem !important}.mt-4{margin-top:1rem !important}.mr-4{margin-right:1rem !important}.mb-4{margin-bottom:1rem !important}.ml-4{margin-left:1rem !important}.mx-4{margin-left:1rem !important;margin-right:1rem !important}.my-4{margin-top:1rem !important;margin-bottom:1rem !important}.m-5{margin:1.5rem !important}.mt-5{margin-top:1.5rem !important}.mr-5{margin-right:1.5rem !important}.mb-5{margin-bottom:1.5rem !important}.ml-5{margin-left:1.5rem !important}.mx-5{margin-left:1.5rem !important;margin-right:1.5rem !important}.my-5{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.m-6{margin:3rem !important}.mt-6{margin-top:3rem !important}.mr-6{margin-right:3rem !important}.mb-6{margin-bottom:3rem !important}.ml-6{margin-left:3rem !important}.mx-6{margin-left:3rem !important;margin-right:3rem !important}.my-6{margin-top:3rem !important;margin-bottom:3rem !important}.m-auto{margin:auto !important}.mt-auto{margin-top:auto !important}.mr-auto{margin-right:auto !important}.mb-auto{margin-bottom:auto !important}.ml-auto{margin-left:auto !important}.mx-auto{margin-left:auto !important;margin-right:auto !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.p-0{padding:0 !important}.pt-0{padding-top:0 !important}.pr-0{padding-right:0 !important}.pb-0{padding-bottom:0 !important}.pl-0{padding-left:0 !important}.px-0{padding-left:0 !important;padding-right:0 !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.p-1{padding:.25rem !important}.pt-1{padding-top:.25rem !important}.pr-1{padding-right:.25rem !important}.pb-1{padding-bottom:.25rem !important}.pl-1{padding-left:.25rem !important}.px-1{padding-left:.25rem !important;padding-right:.25rem !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.p-2{padding:.5rem !important}.pt-2{padding-top:.5rem !important}.pr-2{padding-right:.5rem !important}.pb-2{padding-bottom:.5rem !important}.pl-2{padding-left:.5rem !important}.px-2{padding-left:.5rem !important;padding-right:.5rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.p-3{padding:.75rem !important}.pt-3{padding-top:.75rem !important}.pr-3{padding-right:.75rem !important}.pb-3{padding-bottom:.75rem !important}.pl-3{padding-left:.75rem !important}.px-3{padding-left:.75rem !important;padding-right:.75rem !important}.py-3{padding-top:.75rem !important;padding-bottom:.75rem !important}.p-4{padding:1rem !important}.pt-4{padding-top:1rem !important}.pr-4{padding-right:1rem !important}.pb-4{padding-bottom:1rem !important}.pl-4{padding-left:1rem !important}.px-4{padding-left:1rem !important;padding-right:1rem !important}.py-4{padding-top:1rem !important;padding-bottom:1rem !important}.p-5{padding:1.5rem !important}.pt-5{padding-top:1.5rem !important}.pr-5{padding-right:1.5rem !important}.pb-5{padding-bottom:1.5rem !important}.pl-5{padding-left:1.5rem !important}.px-5{padding-left:1.5rem !important;padding-right:1.5rem !important}.py-5{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.p-6{padding:3rem !important}.pt-6{padding-top:3rem !important}.pr-6{padding-right:3rem !important}.pb-6{padding-bottom:3rem !important}.pl-6{padding-left:3rem !important}.px-6{padding-left:3rem !important;padding-right:3rem !important}.py-6{padding-top:3rem !important;padding-bottom:3rem !important}.p-auto{padding:auto !important}.pt-auto{padding-top:auto !important}.pr-auto{padding-right:auto !important}.pb-auto{padding-bottom:auto !important}.pl-auto{padding-left:auto !important}.px-auto{padding-left:auto !important;padding-right:auto !important}.py-auto{padding-top:auto !important;padding-bottom:auto !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,html.theme--documenter-dark .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}.is-underlined{text-decoration:underline !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}}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 optgroup,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:inherit}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 0.5em 1em -0.125em 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.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(0.5em - 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.5em - 1px);margin-right:.25em}html.theme--documenter-dark .button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-0.5em - 1px)}html.theme--documenter-dark .button .icon:first-child:last-child{margin-left:calc(-0.5em - 1px);margin-right:calc(-0.5em - 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-ghost{background:none;border-color:rgba(0,0,0,0);color:#1abc9c;text-decoration:none}html.theme--documenter-dark .button.is-ghost:hover,html.theme--documenter-dark .button.is-ghost.is-hovered{color:#1abc9c;text-decoration:underline}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:#fff;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:#0a0a0a;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:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:hover,html.theme--documenter-dark .button.is-light.is-hovered{background-color:#e5eaec;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:focus,html.theme--documenter-dark .button.is-light.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:#ecf0f1;box-shadow:none}html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);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:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !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:rgba(0,0,0,0.7)}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 rgba(0,0,0,0.7) rgba(0,0,0,0.7) !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:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7);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:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-dark,html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:transparent;color:#fff}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:#fff}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:#fff}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:#fff}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:#282f2f;box-shadow:none}html.theme--documenter-dark .button.is-dark.is-inverted,html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#fff;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:#f2f2f2}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:#fff;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 #fff #fff !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:#fff}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 #fff #fff !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:#fff;color:#fff}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:#fff;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:#fff;box-shadow:none;color:#fff}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:#375a7f;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-primary.is-light,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:hover,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-light.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-light.is-hovered.docs-sourcelink{background-color:#e8eef5;border-color:transparent;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:active,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-light.is-active,html.theme--documenter-dark .docstring>section>a.button.is-light.is-active.docs-sourcelink{background-color:#dfe8f1;border-color:transparent;color:#4d7eb2}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:#1abc9c;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-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:hover,html.theme--documenter-dark .button.is-link.is-light.is-hovered{background-color:#e2fbf6;border-color:transparent;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:active,html.theme--documenter-dark .button.is-link.is-light.is-active{background-color:#d7f9f3;border-color:transparent;color:#15987e}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:#024c7d;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-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:hover,html.theme--documenter-dark .button.is-info.is-light.is-hovered{background-color:#def2fe;border-color:transparent;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:active,html.theme--documenter-dark .button.is-info.is-light.is-active{background-color:#d2edfe;border-color:transparent;color:#0e9dfb}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:#008438;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-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:hover,html.theme--documenter-dark .button.is-success.is-light.is-hovered{background-color:#deffec;border-color:transparent;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:active,html.theme--documenter-dark .button.is-success.is-light.is-active{background-color:#d1ffe5;border-color:transparent;color:#00eb64}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:#ad8100;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-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:hover,html.theme--documenter-dark .button.is-warning.is-light.is-hovered{background-color:#fff7de;border-color:transparent;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:active,html.theme--documenter-dark .button.is-warning.is-light.is-active{background-color:#fff3d1;border-color:transparent;color:#d19c00}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:#9e1b0d;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-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:hover,html.theme--documenter-dark .button.is-danger.is-light.is-hovered{background-color:#fce3e0;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:active,html.theme--documenter-dark .button.is-danger.is-light.is-active{background-color:#fcd8d5;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{font-size:.75rem}html.theme--documenter-dark .button.is-small:not(.is-rounded),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button:not(.is-rounded){border-radius:3px}html.theme--documenter-dark .button.is-normal{font-size:1rem}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:#5e6d6f;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 * 0.5));top:calc(50% - (1em * 0.5));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:9999px;padding-left:calc(1em + 0.25em);padding-right:calc(1em + 0.25em)}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:.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){font-size:.75rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:3px}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}@media screen and (max-width: 768px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.5625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:1rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1.25rem}}html.theme--documenter-dark .container{flex-grow:1;margin:0 auto;position:relative;width:auto}html.theme--documenter-dark .container.is-fluid{max-width:none !important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width: 1056px){html.theme--documenter-dark .container{max-width:992px}}@media screen and (max-width: 1215px){html.theme--documenter-dark .container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width: 1407px){html.theme--documenter-dark .container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width: 1216px){html.theme--documenter-dark .container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width: 1408px){html.theme--documenter-dark .container:not(.is-max-desktop):not(.is-max-widescreen){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:inherit}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:.75rem}html.theme--documenter-dark .content.is-normal{font-size:1rem}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 .icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}html.theme--documenter-dark .icon-text .icon{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .icon-text .icon:not(:last-child){margin-right:.25em}html.theme--documenter-dark .icon-text .icon:not(:first-child){margin-left:.25em}html.theme--documenter-dark div.icon-text{display:flex}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:9999px}html.theme--documenter-dark .image.is-fullwidth,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-fullwidth{width:100%}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;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}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{right:.5rem;position:absolute;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:rgba(0,0,0,0.7)}html.theme--documenter-dark .notification.is-dark,html.theme--documenter-dark .content kbd.notification{background-color:#282f2f;color:#fff}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-primary.is-light,html.theme--documenter-dark .docstring>section>a.notification.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .notification.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .notification.is-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .notification.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .notification.is-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .notification.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .notification.is-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .notification.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .notification.is-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .notification.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .notification.is-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}html.theme--documenter-dark .progress::-webkit-progress-bar{background-color:#343c3d}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%, #343c3d 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%, #343c3d 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%, #343c3d 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%, #343c3d 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%, #343c3d 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%, #343c3d 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%, #343c3d 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%, #343c3d 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%, #343c3d 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%, #343c3d 30%)}html.theme--documenter-dark .progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#343c3d;background-image:linear-gradient(to right, #fff 30%, #343c3d 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:indeterminate::-ms-fill{animation-name:none}html.theme--documenter-dark .progress.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.progress{height:.75rem}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:rgba(0,0,0,0.7)}html.theme--documenter-dark .table td.is-dark,html.theme--documenter-dark .table th.is-dark{background-color:#282f2f;border-color:#282f2f;color:#fff}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 td.is-vcentered,html.theme--documenter-dark .table th.is-vcentered{vertical-align:middle}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:.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:1rem}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-top-left-radius:0;border-bottom-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-top-right-radius:0;border-bottom-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:.75rem;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:.25rem;margin-right:-.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:rgba(0,0,0,0.7)}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:#fff}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-primary.is-light:not(body),html.theme--documenter-dark .content kbd.is-primary.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#f1f5f9;color:#4d7eb2}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-link.is-light:not(body),html.theme--documenter-dark .content kbd.is-link.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link.is-light:not(body){background-color:#edfdf9;color:#15987e}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-info.is-light:not(body),html.theme--documenter-dark .content kbd.is-info.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info.is-light:not(body){background-color:#ebf7ff;color:#0e9dfb}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-success.is-light:not(body),html.theme--documenter-dark .content kbd.is-success.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success.is-light:not(body){background-color:#ebfff3;color:#00eb64}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-warning.is-light:not(body),html.theme--documenter-dark .content kbd.is-warning.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning.is-light:not(body){background-color:#fffaeb;color:#d19c00}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-danger.is-light:not(body),html.theme--documenter-dark .content kbd.is-danger.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger.is-light:not(body){background-color:#fdeeec;color:#ec311d}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:.75rem}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:1rem}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:-.375em;margin-right:.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:.1875em;margin-right:-.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:-.375em;margin-right:-.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:9999px}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: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:1rem}html.theme--documenter-dark .title.is-7{font-size:.75rem}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:1rem}html.theme--documenter-dark .subtitle.is-7{font-size:.75rem}html.theme--documenter-dark .heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}html.theme--documenter-dark .number{align-items:center;background-color:#282f2f;border-radius:9999px;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:#868c98}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:#868c98}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:#868c98}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:#868c98}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 0.0625em 0.125em rgba(10,10,10,0.05);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:.75rem}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:9999px;padding-left:calc(calc(0.75em - 1px) + 0.375em);padding-right:calc(calc(0.75em - 1px) + 0.375em)}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:calc(0.75em - 1px);resize:vertical}html.theme--documenter-dark .textarea:not([rows]){max-height:40em;min-height:8em}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,html.theme--documenter-dark .radio input[disabled],html.theme--documenter-dark .checkbox input[disabled]{color:#fff;cursor:not-allowed}html.theme--documenter-dark .radio+.radio{margin-left:.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.5em}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:9999px;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:.75rem}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 !important;opacity:0.5}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:.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:.75rem}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:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7)}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:#fff}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:#fff}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:#fff}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:#fff}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:.75rem}html.theme--documenter-dark .file.is-normal{font-size:1rem}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:#232829;color:#f2f2f2}html.theme--documenter-dark .file-label:hover .file-name{border-color:#596668}html.theme--documenter-dark .file-label:active .file-cta{background-color:#1d2122;color:#f2f2f2}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:#282f2f;color:#fff}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:inherit;text-overflow:ellipsis}html.theme--documenter-dark .file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}html.theme--documenter-dark .file-icon .fa{font-size:14px}html.theme--documenter-dark .label{color:#f2f2f2;display:block;font-size:1rem;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:.75rem}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:.75rem;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:.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:.75rem;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:.75rem}}html.theme--documenter-dark .control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}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:#282f2f}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:.75rem}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:#5e6d6f;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;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.5em}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.5em}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:.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:.75rem}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:1rem;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:.5em}html.theme--documenter-dark .breadcrumb .icon:last-child{margin-left:.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:.75rem}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;border-radius:.25rem;box-shadow:#171717;color:#fff;max-width:100%;position:relative}html.theme--documenter-dark .card-footer:first-child,html.theme--documenter-dark .card-content:first-child,html.theme--documenter-dark .card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-footer:last-child,html.theme--documenter-dark .card-content:last-child,html.theme--documenter-dark .card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}html.theme--documenter-dark .card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 0.125em 0.25em 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:0.75rem 1rem}html.theme--documenter-dark .card-header-title.is-centered{justify-content:center}html.theme--documenter-dark .card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:0.75rem 1rem}html.theme--documenter-dark .card-image{display:block;position:relative}html.theme--documenter-dark .card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}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 #ededed;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 #ededed}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:#171717;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:inherit;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:#ededed;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 .media{align-items:flex-start;display:flex;text-align:inherit}html.theme--documenter-dark .media .content:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .media .media{border-top:1px solid rgba(94,109,111,0.5);display:flex;padding-top:.75rem}html.theme--documenter-dark .media .media .content:not(:last-child),html.theme--documenter-dark .media .media .control:not(:last-child){margin-bottom:.5rem}html.theme--documenter-dark .media .media .media{padding-top:.5rem}html.theme--documenter-dark .media .media .media+.media{margin-top:.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:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .media-content{overflow-x:auto}}html.theme--documenter-dark .menu{font-size:1rem}html.theme--documenter-dark .menu.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.menu{font-size:.75rem}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:1rem}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:.75rem}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}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}html.theme--documenter-dark .message.is-light{background-color:#f9fafb}html.theme--documenter-dark .message.is-light .message-header{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .message.is-light .message-body{border-color:#ecf0f1}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:#fff}html.theme--documenter-dark .message.is-dark .message-body,html.theme--documenter-dark .content kbd.message .message-body{border-color:#282f2f}html.theme--documenter-dark .message.is-primary,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink{background-color:#f1f5f9}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:#4d7eb2}html.theme--documenter-dark .message.is-link{background-color:#edfdf9}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:#15987e}html.theme--documenter-dark .message.is-info{background-color:#ebf7ff}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:#0e9dfb}html.theme--documenter-dark .message.is-success{background-color:#ebfff3}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:#00eb64}html.theme--documenter-dark .message.is-warning{background-color:#fffaeb}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:#d19c00}html.theme--documenter-dark .message.is-danger{background-color:#fdeeec}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:#ec311d}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:.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){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:.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:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-burger{color:rgba(0,0,0,0.7)}@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:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}}html.theme--documenter-dark .navbar.is-dark,html.theme--documenter-dark .content kbd.navbar{background-color:#282f2f;color:#fff}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:#fff}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:#fff}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:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-burger,html.theme--documenter-dark .content kbd.navbar .navbar-burger{color:#fff}@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:#fff}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:#fff}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:#fff}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:#fff}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:#fff}}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;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;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{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.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:1rem;margin:-.25rem}html.theme--documenter-dark .pagination.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination{font-size:.75rem}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:9999px}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:9999px}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.5em}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-previous.is-disabled,html.theme--documenter-dark .pagination-next[disabled],html.theme--documenter-dark .pagination-next.is-disabled,html.theme--documenter-dark .pagination-link[disabled],html.theme--documenter-dark .pagination-link.is-disabled{background-color:#5e6d6f;border-color:#5e6d6f;box-shadow:none;color:#fff;opacity:0.5}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{padding-left:.75em;padding-right:.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}html.theme--documenter-dark .pagination-list li{list-style:none}@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,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{margin-bottom:0;margin-top:0}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;margin-bottom:0;margin-top:0}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{border-radius:8px;box-shadow:#171717;font-size:1rem}html.theme--documenter-dark .panel:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}html.theme--documenter-dark .panel.is-white .panel-block.is-active .panel-icon{color:#fff}html.theme--documenter-dark .panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}html.theme--documenter-dark .panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}html.theme--documenter-dark .panel.is-light .panel-heading{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .panel.is-light .panel-tabs a.is-active{border-bottom-color:#ecf0f1}html.theme--documenter-dark .panel.is-light .panel-block.is-active .panel-icon{color:#ecf0f1}html.theme--documenter-dark .panel.is-dark .panel-heading,html.theme--documenter-dark .content kbd.panel .panel-heading{background-color:#282f2f;color:#fff}html.theme--documenter-dark .panel.is-dark .panel-tabs a.is-active,html.theme--documenter-dark .content kbd.panel .panel-tabs a.is-active{border-bottom-color:#282f2f}html.theme--documenter-dark .panel.is-dark .panel-block.is-active .panel-icon,html.theme--documenter-dark .content kbd.panel .panel-block.is-active .panel-icon{color:#282f2f}html.theme--documenter-dark .panel.is-primary .panel-heading,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-heading{background-color:#375a7f;color:#fff}html.theme--documenter-dark .panel.is-primary .panel-tabs a.is-active,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-tabs a.is-active{border-bottom-color:#375a7f}html.theme--documenter-dark .panel.is-primary .panel-block.is-active .panel-icon,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-block.is-active .panel-icon{color:#375a7f}html.theme--documenter-dark .panel.is-link .panel-heading{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .panel.is-link .panel-tabs a.is-active{border-bottom-color:#1abc9c}html.theme--documenter-dark .panel.is-link .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark .panel.is-info .panel-heading{background-color:#024c7d;color:#fff}html.theme--documenter-dark .panel.is-info .panel-tabs a.is-active{border-bottom-color:#024c7d}html.theme--documenter-dark .panel.is-info .panel-block.is-active .panel-icon{color:#024c7d}html.theme--documenter-dark .panel.is-success .panel-heading{background-color:#008438;color:#fff}html.theme--documenter-dark .panel.is-success .panel-tabs a.is-active{border-bottom-color:#008438}html.theme--documenter-dark .panel.is-success .panel-block.is-active .panel-icon{color:#008438}html.theme--documenter-dark .panel.is-warning .panel-heading{background-color:#ad8100;color:#fff}html.theme--documenter-dark .panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ad8100}html.theme--documenter-dark .panel.is-warning .panel-block.is-active .panel-icon{color:#ad8100}html.theme--documenter-dark .panel.is-danger .panel-heading{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .panel.is-danger .panel-tabs a.is-active{border-bottom-color:#9e1b0d}html.theme--documenter-dark .panel.is-danger .panel-block.is-active .panel-icon{color:#9e1b0d}html.theme--documenter-dark .panel-tabs:not(:last-child),html.theme--documenter-dark .panel-block:not(:last-child){border-bottom:1px solid #ededed}html.theme--documenter-dark .panel-heading{background-color:#343c3d;border-radius:8px 8px 0 0;color:#f2f2f2;font-size:1.25em;font-weight:700;line-height:1.25;padding:0.75em 1em}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:.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 .panel-block:last-child{border-bottom-left-radius:8px;border-bottom-right-radius:8px}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:.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:1rem;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:.5em}html.theme--documenter-dark .tabs .icon:last-child{margin-left:.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-top-left-radius:.4em;border-bottom-left-radius:.4em}html.theme--documenter-dark .tabs.is-toggle li:last-child a{border-top-right-radius:.4em;border-bottom-right-radius:.4em}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:9999px;border-top-left-radius:9999px;padding-left:1.25em}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;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:.75rem}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;width:unset}.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.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-1{margin-left:8.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-2{flex:none;width:16.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-2{margin-left:16.66666674%}.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.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-4{margin-left:33.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-5{flex:none;width:41.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-5{margin-left:41.66666674%}.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.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-7{margin-left:58.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-8{flex:none;width:66.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-8{margin-left:66.66666674%}.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.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-10{margin-left:83.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-11{flex:none;width:91.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-11{margin-left:91.66666674%}.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;width:unset}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.33333337%}html.theme--documenter-dark .column.is-offset-1-mobile{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-mobile{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-mobile{margin-left:16.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-4-mobile{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-mobile{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-mobile{margin-left:41.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-7-mobile{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-mobile{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-mobile{margin-left:66.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-10-mobile{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-mobile{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-mobile{margin-left:91.66666674%}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;width:unset}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.33333337%}html.theme--documenter-dark .column.is-offset-1,html.theme--documenter-dark .column.is-offset-1-tablet{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2,html.theme--documenter-dark .column.is-2-tablet{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2,html.theme--documenter-dark .column.is-offset-2-tablet{margin-left:16.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-4,html.theme--documenter-dark .column.is-offset-4-tablet{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5,html.theme--documenter-dark .column.is-5-tablet{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5,html.theme--documenter-dark .column.is-offset-5-tablet{margin-left:41.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-7,html.theme--documenter-dark .column.is-offset-7-tablet{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8,html.theme--documenter-dark .column.is-8-tablet{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8,html.theme--documenter-dark .column.is-offset-8-tablet{margin-left:66.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-10,html.theme--documenter-dark .column.is-offset-10-tablet{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11,html.theme--documenter-dark .column.is-11-tablet{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11,html.theme--documenter-dark .column.is-offset-11-tablet{margin-left:91.66666674%}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;width:unset}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.33333337%}html.theme--documenter-dark .column.is-offset-1-touch{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-touch{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-touch{margin-left:16.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-4-touch{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-touch{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-touch{margin-left:41.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-7-touch{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-touch{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-touch{margin-left:66.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-10-touch{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-touch{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-touch{margin-left:91.66666674%}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;width:unset}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.33333337%}html.theme--documenter-dark .column.is-offset-1-desktop{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-desktop{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-desktop{margin-left:16.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-4-desktop{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-desktop{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-desktop{margin-left:41.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-7-desktop{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-desktop{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-desktop{margin-left:66.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-10-desktop{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-desktop{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-desktop{margin-left:91.66666674%}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;width:unset}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.33333337%}html.theme--documenter-dark .column.is-offset-1-widescreen{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-widescreen{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-widescreen{margin-left:16.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-4-widescreen{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-widescreen{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-widescreen{margin-left:41.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-7-widescreen{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-widescreen{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-widescreen{margin-left:66.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-10-widescreen{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-widescreen{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-widescreen{margin-left:91.66666674%}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;width:unset}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.33333337%}html.theme--documenter-dark .column.is-offset-1-fullhd{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-fullhd{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-fullhd{margin-left:16.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-4-fullhd{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-fullhd{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-fullhd{margin-left:41.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-7-fullhd{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-fullhd{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-fullhd{margin-left:66.66666674%}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.33333337%}html.theme--documenter-dark .column.is-offset-10-fullhd{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-fullhd{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-fullhd{margin-left:91.66666674%}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.33333337%}html.theme--documenter-dark .tile.is-2{flex:none;width:16.66666674%}html.theme--documenter-dark .tile.is-3{flex:none;width:25%}html.theme--documenter-dark .tile.is-4{flex:none;width:33.33333337%}html.theme--documenter-dark .tile.is-5{flex:none;width:41.66666674%}html.theme--documenter-dark .tile.is-6{flex:none;width:50%}html.theme--documenter-dark .tile.is-7{flex:none;width:58.33333337%}html.theme--documenter-dark .tile.is-8{flex:none;width:66.66666674%}html.theme--documenter-dark .tile.is-9{flex:none;width:75%}html.theme--documenter-dark .tile.is-10{flex:none;width:83.33333337%}html.theme--documenter-dark .tile.is-11{flex:none;width:91.66666674%}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{color:#fff !important;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{color:#0a0a0a !important;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:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .subtitle{color:rgba(0,0,0,0.9)}html.theme--documenter-dark .hero.is-light .subtitle a:not(.button),html.theme--documenter-dark .hero.is-light .subtitle strong{color:rgba(0,0,0,0.7)}@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(0,0,0,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:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .tabs a{color:rgba(0,0,0,0.7);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{color:#ecf0f1 !important;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:rgba(0,0,0,0.7)}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:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);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:#fff}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:#fff}html.theme--documenter-dark .hero.is-dark .subtitle,html.theme--documenter-dark .content kbd.hero .subtitle{color:rgba(255,255,255,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:#fff}@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(255,255,255,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:#fff}html.theme--documenter-dark .hero.is-dark .tabs a,html.theme--documenter-dark .content kbd.hero .tabs a{color:#fff;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{color:#282f2f !important;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:#fff}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:#fff;border-color:#fff;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{color:#375a7f !important;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{color:#1abc9c !important;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{color:#024c7d !important;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{color:#008438 !important;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{color:#ad8100 !important;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{color:#9e1b0d !important;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:1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-large .hero-body{padding:18rem 6rem}}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}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-body{padding:3rem 3rem}}html.theme--documenter-dark .section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){html.theme--documenter-dark .section{padding:3rem 3rem}html.theme--documenter-dark .section.is-medium{padding:9rem 4.5rem}html.theme--documenter-dark .section.is-large{padding:18rem 6rem}}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:rgba(0,0,0,0.7);text-decoration:underline}html.theme--documenter-dark .notification.is-dark a:not(.button),html.theme--documenter-dark .content kbd.notification a:not(.button){color:#fff;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 6 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 6 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:1rem}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:.75rem}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 6 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}html.theme--documenter-dark details.admonition.is-details>.admonition-header{list-style:none}html.theme--documenter-dark details.admonition.is-details>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f055"}html.theme--documenter-dark details.admonition.is-details[open]>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f056"}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{cursor:pointer;display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#282f2f;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #5e6d6f;overflow:auto}html.theme--documenter-dark .docstring>header code{background-color:transparent}html.theme--documenter-dark .docstring>header .docstring-article-toggle-button{min-width:1.1rem;padding:0.2rem 0.2rem 0.2rem 0}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;overflow-x:hidden}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-sidebar-button{display:block;font-size:1.5rem;padding-bottom:0.1rem;margin-right:1rem}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap;gap:1rem;align-items:center}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{display:inline-block}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-navbar-link{margin-left:0.4rem;margin-right:0.4rem}}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:1rem;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:.95rem;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:.75rem;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 6 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:.85rem;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}html.theme--documenter-dark #documenter .docs-sidebar #documenter-search-query{color:#868c98;width:14.4rem;box-shadow:inset 0 1px 2px rgba(10,10,10,0.1)}@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 kbd.search-modal-key-hints{border-radius:0.25rem;border:1px solid rgba(245,245,245,0.6);box-shadow:0 2px 0 1px rgba(245,245,245,0.6);cursor:default;font-size:0.9rem;line-height:1.5;min-width:0.75rem;text-align:center;padding:0.1rem 0.3rem;position:relative;top:-1px}html.theme--documenter-dark .search-min-width-50{min-width:50%}html.theme--documenter-dark .search-min-height-100{min-height:100%}html.theme--documenter-dark .search-modal-card-body{max-height:calc(100vh - 15rem)}html.theme--documenter-dark .search-result-link{border-radius:0.7em;transition:all 300ms}html.theme--documenter-dark .search-result-link:hover,html.theme--documenter-dark .search-result-link:focus{background-color:rgba(0,128,128,0.1)}html.theme--documenter-dark .search-result-link .property-search-result-badge,html.theme--documenter-dark .search-result-link .search-filter{transition:all 300ms}html.theme--documenter-dark .property-search-result-badge,html.theme--documenter-dark .search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:#f5f5f5;background-color:rgba(51,65,85,0.501961);border-radius:0.6rem}html.theme--documenter-dark .search-result-link:hover .property-search-result-badge,html.theme--documenter-dark .search-result-link:hover .search-filter,html.theme--documenter-dark .search-result-link:focus .property-search-result-badge,html.theme--documenter-dark .search-result-link:focus .search-filter{color:#333;background-color:#f1f5f9}html.theme--documenter-dark .search-filter{color:#333;background-color:#f5f5f5;transition:all 300ms}html.theme--documenter-dark .search-filter:hover,html.theme--documenter-dark .search-filter:focus{color:#333}html.theme--documenter-dark .search-filter-selected{color:#f5f5f5;background-color:rgba(139,0,139,0.5)}html.theme--documenter-dark .search-filter-selected:hover,html.theme--documenter-dark .search-filter-selected:focus{color:#f5f5f5}html.theme--documenter-dark .search-result-highlight{background-color:#ffdd57;color:black}html.theme--documenter-dark .search-divider{border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .search-result-title{width:85%;color:#f5f5f5}html.theme--documenter-dark .search-result-code-title{font-size:0.875rem;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar{height:10px;width:10px;background-color:transparent}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-thumb,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-thumb{background-color:gray;border-radius:1rem}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-track,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.6);background-color:transparent}html.theme--documenter-dark .w-100{width:100%}html.theme--documenter-dark .gap-2{gap:0.5rem}html.theme--documenter-dark .gap-4{gap:1rem}html.theme--documenter-dark .gap-8{gap:2rem}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}html.theme--documenter-dark .search-result-link{border-radius:0.7em;transition:all 300ms}html.theme--documenter-dark .search-result-link:hover,html.theme--documenter-dark .search-result-link:focus{background-color:rgba(0,128,128,0.1)}html.theme--documenter-dark .search-result-link .property-search-result-badge,html.theme--documenter-dark .search-result-link .search-filter{transition:all 300ms}html.theme--documenter-dark .search-result-link:hover .property-search-result-badge,html.theme--documenter-dark .search-result-link:hover .search-filter,html.theme--documenter-dark .search-result-link:focus .property-search-result-badge,html.theme--documenter-dark .search-result-link:focus .search-filter{color:#333 !important;background-color:#f1f5f9 !important}html.theme--documenter-dark .property-search-result-badge,html.theme--documenter-dark .search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:whitesmoke;background-color:#33415580;border-radius:0.6rem}html.theme--documenter-dark .search-result-title{color:whitesmoke}html.theme--documenter-dark .search-result-highlight{background-color:greenyellow;color:black}html.theme--documenter-dark .search-divider{border-bottom:1px solid #5e6d6f50}html.theme--documenter-dark .w-100{width:100%}html.theme--documenter-dark .gap-2{gap:0.5rem}html.theme--documenter-dark .gap-4{gap:1rem} diff --git a/v0.37.6/assets/themes/documenter-light.css b/v0.37.6/assets/themes/documenter-light.css new file mode 100644 index 0000000000..2f168c77b4 --- /dev/null +++ b/v0.37.6/assets/themes/documenter-light.css @@ -0,0 +1,9 @@ +.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.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(0.5em - 1px);padding-left:calc(0.75em - 1px);padding-right:calc(0.75em - 1px);padding-top:calc(0.5em - 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}.tabs,.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis,.breadcrumb,.file,.button,.is-unselectable{-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),.pagination:not(:last-child),.message:not(:last-child),.level:not(:last-child),.breadcrumb: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{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,0.2);border:none;border-radius:9999px;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:9999px;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}.navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}.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-primary-light{color:#eef8fc !important}a.has-text-primary-light:hover,a.has-text-primary-light:focus{color:#c3e6f4 !important}.has-background-primary-light{background-color:#eef8fc !important}.has-text-primary-dark{color:#1a6d8e !important}a.has-text-primary-dark:hover,a.has-text-primary-dark:focus{color:#228eb9 !important}.has-background-primary-dark{background-color:#1a6d8e !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-link-light{color:#eff3fb !important}a.has-text-link-light:hover,a.has-text-link-light:focus{color:#c6d6f1 !important}.has-background-link-light{background-color:#eff3fb !important}.has-text-link-dark{color:#3169c4 !important}a.has-text-link-dark:hover,a.has-text-link-dark:focus{color:#5485d4 !important}.has-background-link-dark{background-color:#3169c4 !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-info-light{color:#ecf7fe !important}a.has-text-info-light:hover,a.has-text-info-light:focus{color:#bde2fa !important}.has-background-info-light{background-color:#ecf7fe !important}.has-text-info-dark{color:#0e72b4 !important}a.has-text-info-dark:hover,a.has-text-info-dark:focus{color:#1190e3 !important}.has-background-info-dark{background-color:#0e72b4 !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-success-light{color:#eefcf3 !important}a.has-text-success-light:hover,a.has-text-success-light:focus{color:#c2f4d4 !important}.has-background-success-light{background-color:#eefcf3 !important}.has-text-success-dark{color:#198f43 !important}a.has-text-success-dark:hover,a.has-text-success-dark:focus{color:#21bb57 !important}.has-background-success-dark{background-color:#198f43 !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-warning-light{color:#fffbeb !important}a.has-text-warning-light:hover,a.has-text-warning-light:focus{color:#fff1b8 !important}.has-background-warning-light{background-color:#fffbeb !important}.has-text-warning-dark{color:#947600 !important}a.has-text-warning-dark:hover,a.has-text-warning-dark:focus{color:#c79f00 !important}.has-background-warning-dark{background-color:#947600 !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-danger-light{color:#ffeceb !important}a.has-text-danger-light:hover,a.has-text-danger-light:focus{color:#ffbbb8 !important}.has-background-danger-light{background-color:#ffeceb !important}.has-text-danger-dark{color:#f50c00 !important}a.has-text-danger-dark:hover,a.has-text-danger-dark:focus{color:#ff3429 !important}.has-background-danger-dark{background-color:#f50c00 !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}.is-flex-direction-row{flex-direction:row !important}.is-flex-direction-row-reverse{flex-direction:row-reverse !important}.is-flex-direction-column{flex-direction:column !important}.is-flex-direction-column-reverse{flex-direction:column-reverse !important}.is-flex-wrap-nowrap{flex-wrap:nowrap !important}.is-flex-wrap-wrap{flex-wrap:wrap !important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse !important}.is-justify-content-flex-start{justify-content:flex-start !important}.is-justify-content-flex-end{justify-content:flex-end !important}.is-justify-content-center{justify-content:center !important}.is-justify-content-space-between{justify-content:space-between !important}.is-justify-content-space-around{justify-content:space-around !important}.is-justify-content-space-evenly{justify-content:space-evenly !important}.is-justify-content-start{justify-content:start !important}.is-justify-content-end{justify-content:end !important}.is-justify-content-left{justify-content:left !important}.is-justify-content-right{justify-content:right !important}.is-align-content-flex-start{align-content:flex-start !important}.is-align-content-flex-end{align-content:flex-end !important}.is-align-content-center{align-content:center !important}.is-align-content-space-between{align-content:space-between !important}.is-align-content-space-around{align-content:space-around !important}.is-align-content-space-evenly{align-content:space-evenly !important}.is-align-content-stretch{align-content:stretch !important}.is-align-content-start{align-content:start !important}.is-align-content-end{align-content:end !important}.is-align-content-baseline{align-content:baseline !important}.is-align-items-stretch{align-items:stretch !important}.is-align-items-flex-start{align-items:flex-start !important}.is-align-items-flex-end{align-items:flex-end !important}.is-align-items-center{align-items:center !important}.is-align-items-baseline{align-items:baseline !important}.is-align-items-start{align-items:start !important}.is-align-items-end{align-items:end !important}.is-align-items-self-start{align-items:self-start !important}.is-align-items-self-end{align-items:self-end !important}.is-align-self-auto{align-self:auto !important}.is-align-self-flex-start{align-self:flex-start !important}.is-align-self-flex-end{align-self:flex-end !important}.is-align-self-center{align-self:center !important}.is-align-self-baseline{align-self:baseline !important}.is-align-self-stretch{align-self:stretch !important}.is-flex-grow-0{flex-grow:0 !important}.is-flex-grow-1{flex-grow:1 !important}.is-flex-grow-2{flex-grow:2 !important}.is-flex-grow-3{flex-grow:3 !important}.is-flex-grow-4{flex-grow:4 !important}.is-flex-grow-5{flex-grow:5 !important}.is-flex-shrink-0{flex-shrink:0 !important}.is-flex-shrink-1{flex-shrink:1 !important}.is-flex-shrink-2{flex-shrink:2 !important}.is-flex-shrink-3{flex-shrink:3 !important}.is-flex-shrink-4{flex-shrink:4 !important}.is-flex-shrink-5{flex-shrink:5 !important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left !important}.is-pulled-right{float:right !important}.is-radiusless{border-radius:0 !important}.is-shadowless{box-shadow:none !important}.is-clickable{cursor:pointer !important;pointer-events:all !important}.is-clipped{overflow:hidden !important}.is-relative{position:relative !important}.is-marginless{margin:0 !important}.is-paddingless{padding:0 !important}.m-0{margin:0 !important}.mt-0{margin-top:0 !important}.mr-0{margin-right:0 !important}.mb-0{margin-bottom:0 !important}.ml-0{margin-left:0 !important}.mx-0{margin-left:0 !important;margin-right:0 !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.m-1{margin:.25rem !important}.mt-1{margin-top:.25rem !important}.mr-1{margin-right:.25rem !important}.mb-1{margin-bottom:.25rem !important}.ml-1{margin-left:.25rem !important}.mx-1{margin-left:.25rem !important;margin-right:.25rem !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.m-2{margin:.5rem !important}.mt-2{margin-top:.5rem !important}.mr-2{margin-right:.5rem !important}.mb-2{margin-bottom:.5rem !important}.ml-2{margin-left:.5rem !important}.mx-2{margin-left:.5rem !important;margin-right:.5rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.m-3{margin:.75rem !important}.mt-3{margin-top:.75rem !important}.mr-3{margin-right:.75rem !important}.mb-3{margin-bottom:.75rem !important}.ml-3{margin-left:.75rem !important}.mx-3{margin-left:.75rem !important;margin-right:.75rem !important}.my-3{margin-top:.75rem !important;margin-bottom:.75rem !important}.m-4{margin:1rem !important}.mt-4{margin-top:1rem !important}.mr-4{margin-right:1rem !important}.mb-4{margin-bottom:1rem !important}.ml-4{margin-left:1rem !important}.mx-4{margin-left:1rem !important;margin-right:1rem !important}.my-4{margin-top:1rem !important;margin-bottom:1rem !important}.m-5{margin:1.5rem !important}.mt-5{margin-top:1.5rem !important}.mr-5{margin-right:1.5rem !important}.mb-5{margin-bottom:1.5rem !important}.ml-5{margin-left:1.5rem !important}.mx-5{margin-left:1.5rem !important;margin-right:1.5rem !important}.my-5{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.m-6{margin:3rem !important}.mt-6{margin-top:3rem !important}.mr-6{margin-right:3rem !important}.mb-6{margin-bottom:3rem !important}.ml-6{margin-left:3rem !important}.mx-6{margin-left:3rem !important;margin-right:3rem !important}.my-6{margin-top:3rem !important;margin-bottom:3rem !important}.m-auto{margin:auto !important}.mt-auto{margin-top:auto !important}.mr-auto{margin-right:auto !important}.mb-auto{margin-bottom:auto !important}.ml-auto{margin-left:auto !important}.mx-auto{margin-left:auto !important;margin-right:auto !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.p-0{padding:0 !important}.pt-0{padding-top:0 !important}.pr-0{padding-right:0 !important}.pb-0{padding-bottom:0 !important}.pl-0{padding-left:0 !important}.px-0{padding-left:0 !important;padding-right:0 !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.p-1{padding:.25rem !important}.pt-1{padding-top:.25rem !important}.pr-1{padding-right:.25rem !important}.pb-1{padding-bottom:.25rem !important}.pl-1{padding-left:.25rem !important}.px-1{padding-left:.25rem !important;padding-right:.25rem !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.p-2{padding:.5rem !important}.pt-2{padding-top:.5rem !important}.pr-2{padding-right:.5rem !important}.pb-2{padding-bottom:.5rem !important}.pl-2{padding-left:.5rem !important}.px-2{padding-left:.5rem !important;padding-right:.5rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.p-3{padding:.75rem !important}.pt-3{padding-top:.75rem !important}.pr-3{padding-right:.75rem !important}.pb-3{padding-bottom:.75rem !important}.pl-3{padding-left:.75rem !important}.px-3{padding-left:.75rem !important;padding-right:.75rem !important}.py-3{padding-top:.75rem !important;padding-bottom:.75rem !important}.p-4{padding:1rem !important}.pt-4{padding-top:1rem !important}.pr-4{padding-right:1rem !important}.pb-4{padding-bottom:1rem !important}.pl-4{padding-left:1rem !important}.px-4{padding-left:1rem !important;padding-right:1rem !important}.py-4{padding-top:1rem !important;padding-bottom:1rem !important}.p-5{padding:1.5rem !important}.pt-5{padding-top:1.5rem !important}.pr-5{padding-right:1.5rem !important}.pb-5{padding-bottom:1.5rem !important}.pl-5{padding-left:1.5rem !important}.px-5{padding-left:1.5rem !important;padding-right:1.5rem !important}.py-5{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.p-6{padding:3rem !important}.pt-6{padding-top:3rem !important}.pr-6{padding-right:3rem !important}.pb-6{padding-bottom:3rem !important}.pl-6{padding-left:3rem !important}.px-6{padding-left:3rem !important;padding-right:3rem !important}.py-6{padding-top:3rem !important;padding-bottom:3rem !important}.p-auto{padding:auto !important}.pt-auto{padding-top:auto !important}.pr-auto{padding-right:auto !important}.pb-auto{padding-bottom:auto !important}.pl-auto{padding-left:auto !important}.px-auto{padding-left:auto !important;padding-right:auto !important}.py-auto{padding-top:auto !important;padding-bottom:auto !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}.is-underlined{text-decoration:underline !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}}/*! minireset.css v0.0.6 | 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,video{height:auto;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:inherit}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,optgroup,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:inherit}table th{color:#222}@keyframes spinAround{from{transform:rotate(0deg)}to{transform:rotate(359deg)}}.box{background-color:#fff;border-radius:6px;box-shadow:#bbb;color:#222;display:block;padding:1.25rem}a.box:hover,a.box:focus{box-shadow:0 0.5em 1em -0.125em 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:#222;cursor:pointer;justify-content:center;padding-bottom:calc(0.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(0.5em - 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.5em - 1px);margin-right:.25em}.button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-0.5em - 1px)}.button .icon:first-child:last-child{margin-left:calc(-0.5em - 1px);margin-right:calc(-0.5em - 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-ghost{background:none;border-color:rgba(0,0,0,0);color:#2e63b8;text-decoration:none}.button.is-ghost:hover,.button.is-ghost.is-hovered{color:#2e63b8;text-decoration:underline}.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:#fff;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:#0a0a0a;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:rgba(0,0,0,0.7)}.button.is-light:hover,.button.is-light.is-hovered{background-color:#eee;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-light:focus,.button.is-light.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}.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:rgba(0,0,0,0.7)}.button.is-light[disabled],fieldset[disabled] .button.is-light{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none}.button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);color:#f5f5f5}.button.is-light.is-inverted:hover,.button.is-light.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}.button.is-light.is-inverted[disabled],fieldset[disabled] .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#f5f5f5}.button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !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:rgba(0,0,0,0.7)}.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 rgba(0,0,0,0.7) rgba(0,0,0,0.7) !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:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}.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:rgba(0,0,0,0.7);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:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}.button.is-dark,.content kbd.button{background-color:#363636;border-color:transparent;color:#fff}.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:#fff}.button.is-dark:focus,.content kbd.button:focus,.button.is-dark.is-focused,.content kbd.button.is-focused{border-color:transparent;color:#fff}.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:#fff}.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:#363636;box-shadow:none}.button.is-dark.is-inverted,.content kbd.button.is-inverted{background-color:#fff;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:#f2f2f2}.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:#fff;border-color:transparent;box-shadow:none;color:#363636}.button.is-dark.is-loading::after,.content kbd.button.is-loading::after{border-color:transparent transparent #fff #fff !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:#fff}.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 #fff #fff !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:#fff;color:#fff}.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:#fff;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:#fff;box-shadow:none;color:#fff}.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:#4eb5de;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-primary.is-light,.docstring>section>a.button.is-light.docs-sourcelink{background-color:#eef8fc;color:#1a6d8e}.button.is-primary.is-light:hover,.docstring>section>a.button.is-light.docs-sourcelink:hover,.button.is-primary.is-light.is-hovered,.docstring>section>a.button.is-light.is-hovered.docs-sourcelink{background-color:#e3f3fa;border-color:transparent;color:#1a6d8e}.button.is-primary.is-light:active,.docstring>section>a.button.is-light.docs-sourcelink:active,.button.is-primary.is-light.is-active,.docstring>section>a.button.is-light.is-active.docs-sourcelink{background-color:#d8eff8;border-color:transparent;color:#1a6d8e}.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:#2e63b8;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-link.is-light{background-color:#eff3fb;color:#3169c4}.button.is-link.is-light:hover,.button.is-link.is-light.is-hovered{background-color:#e4ecf8;border-color:transparent;color:#3169c4}.button.is-link.is-light:active,.button.is-link.is-light.is-active{background-color:#dae5f6;border-color:transparent;color:#3169c4}.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:#209cee;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-info.is-light{background-color:#ecf7fe;color:#0e72b4}.button.is-info.is-light:hover,.button.is-info.is-light.is-hovered{background-color:#e0f1fd;border-color:transparent;color:#0e72b4}.button.is-info.is-light:active,.button.is-info.is-light.is-active{background-color:#d4ecfc;border-color:transparent;color:#0e72b4}.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:#22c35b;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-success.is-light{background-color:#eefcf3;color:#198f43}.button.is-success.is-light:hover,.button.is-success.is-light.is-hovered{background-color:#e3faeb;border-color:transparent;color:#198f43}.button.is-success.is-light:active,.button.is-success.is-light.is-active{background-color:#d8f8e3;border-color:transparent;color:#198f43}.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:#ffdd57;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-warning.is-light{background-color:#fffbeb;color:#947600}.button.is-warning.is-light:hover,.button.is-warning.is-light.is-hovered{background-color:#fff8de;border-color:transparent;color:#947600}.button.is-warning.is-light:active,.button.is-warning.is-light.is-active{background-color:#fff6d1;border-color:transparent;color:#947600}.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:#da0b00;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-danger.is-light{background-color:#ffeceb;color:#f50c00}.button.is-danger.is-light:hover,.button.is-danger.is-light.is-hovered{background-color:#ffe0de;border-color:transparent;color:#f50c00}.button.is-danger.is-light:active,.button.is-danger.is-light.is-active{background-color:#ffd3d1;border-color:transparent;color:#f50c00}.button.is-small,#documenter .docs-sidebar form.docs-search>input.button{font-size:.75rem}.button.is-small:not(.is-rounded),#documenter .docs-sidebar form.docs-search>input.button:not(.is-rounded){border-radius:2px}.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 * 0.5));top:calc(50% - (1em * 0.5));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:9999px;padding-left:calc(1em + 0.25em);padding-right:calc(1em + 0.25em)}.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:.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){font-size:.75rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:2px}.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}@media screen and (max-width: 768px){.button.is-responsive.is-small,#documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.5625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.65625rem}.button.is-responsive.is-medium{font-size:.75rem}.button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.button.is-responsive.is-small,#documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.65625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.75rem}.button.is-responsive.is-medium{font-size:1rem}.button.is-responsive.is-large{font-size:1.25rem}}.container{flex-grow:1;margin:0 auto;position:relative;width:auto}.container.is-fluid{max-width:none !important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width: 1056px){.container{max-width:992px}}@media screen and (max-width: 1215px){.container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width: 1407px){.container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width: 1216px){.container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width: 1408px){.container:not(.is-max-desktop):not(.is-max-widescreen){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:inherit}.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-normal{font-size:1rem}.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}.icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}.icon-text .icon{flex-grow:0;flex-shrink:0}.icon-text .icon:not(:last-child){margin-right:.25em}.icon-text .icon:not(:first-child){margin-left:.25em}div.icon-text{display:flex}.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:9999px}.image.is-fullwidth,#documenter .docs-sidebar .docs-logo>img.is-fullwidth{width:100%}.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;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}.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{right:.5rem;position:absolute;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:rgba(0,0,0,0.7)}.notification.is-dark,.content kbd.notification{background-color:#363636;color:#fff}.notification.is-primary,.docstring>section>a.notification.docs-sourcelink{background-color:#4eb5de;color:#fff}.notification.is-primary.is-light,.docstring>section>a.notification.is-light.docs-sourcelink{background-color:#eef8fc;color:#1a6d8e}.notification.is-link{background-color:#2e63b8;color:#fff}.notification.is-link.is-light{background-color:#eff3fb;color:#3169c4}.notification.is-info{background-color:#209cee;color:#fff}.notification.is-info.is-light{background-color:#ecf7fe;color:#0e72b4}.notification.is-success{background-color:#22c35b;color:#fff}.notification.is-success.is-light{background-color:#eefcf3;color:#198f43}.notification.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.notification.is-warning.is-light{background-color:#fffbeb;color:#947600}.notification.is-danger{background-color:#da0b00;color:#fff}.notification.is-danger.is-light{background-color:#ffeceb;color:#f50c00}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#ededed}.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%, #ededed 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%, #ededed 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%, #ededed 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%, #ededed 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%, #ededed 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%, #ededed 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%, #ededed 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%, #ededed 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%, #ededed 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%, #ededed 30%)}.progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#ededed;background-image:linear-gradient(to right, #222 30%, #ededed 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:indeterminate::-ms-fill{animation-name:none}.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:#222}.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:rgba(0,0,0,0.7)}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#fff}.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 td.is-vcentered,.table th.is-vcentered{vertical-align:middle}.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:.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-top-left-radius:0;border-bottom-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-top-right-radius:0;border-bottom-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:.25rem;margin-right:-.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:rgba(0,0,0,0.7)}.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:#fff}.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-primary.is-light:not(body),.content kbd.is-primary.is-light:not(body),.docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#eef8fc;color:#1a6d8e}.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-link.is-light:not(body),.content kbd.is-link.is-light:not(body),.docstring>section>a.docs-sourcelink.is-link.is-light:not(body){background-color:#eff3fb;color:#3169c4}.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-info.is-light:not(body),.content kbd.is-info.is-light:not(body),.docstring>section>a.docs-sourcelink.is-info.is-light:not(body){background-color:#ecf7fe;color:#0e72b4}.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-success.is-light:not(body),.content kbd.is-success.is-light:not(body),.docstring>section>a.docs-sourcelink.is-success.is-light:not(body){background-color:#eefcf3;color:#198f43}.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-warning.is-light:not(body),.content kbd.is-warning.is-light:not(body),.docstring>section>a.docs-sourcelink.is-warning.is-light:not(body){background-color:#fffbeb;color:#947600}.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-danger.is-light:not(body),.content kbd.is-danger.is-light:not(body),.docstring>section>a.docs-sourcelink.is-danger.is-light:not(body){background-color:#ffeceb;color:#f50c00}.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:-.375em;margin-right:.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:.1875em;margin-right:-.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:-.375em;margin-right:-.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:9999px}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:#222;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.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:#222;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#222;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}.number{align-items:center;background-color:#f5f5f5;border-radius:9999px;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:#222}.select select::-moz-placeholder,.textarea::-moz-placeholder,.input::-moz-placeholder,#documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:#707070}.select select::-webkit-input-placeholder,.textarea::-webkit-input-placeholder,.input::-webkit-input-placeholder,#documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:#707070}.select select:-moz-placeholder,.textarea:-moz-placeholder,.input:-moz-placeholder,#documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:#707070}.select select:-ms-input-placeholder,.textarea:-ms-input-placeholder,.input:-ms-input-placeholder,#documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:#707070}.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 0.0625em 0.125em rgba(10,10,10,0.05);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:9999px;padding-left:calc(calc(0.75em - 1px) + 0.375em);padding-right:calc(calc(0.75em - 1px) + 0.375em)}.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:calc(0.75em - 1px);resize:vertical}.textarea:not([rows]){max-height:40em;min-height:8em}.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:#222}.radio[disabled],.checkbox[disabled],fieldset[disabled] .radio,fieldset[disabled] .checkbox,.radio input[disabled],.checkbox input[disabled]{color:#6b6b6b;cursor:not-allowed}.radio+.radio{margin-left:.5em}.select{display:inline-block;max-width:100%;position:relative;vertical-align:top}.select:not(.is-multiple){height:2.5em}.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:9999px;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:#222}.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 !important;opacity:0.5}.select.is-fullwidth{width:100%}.select.is-fullwidth select{width:100%}.select.is-loading::after{margin-top:0;position:absolute;right:.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:rgba(0,0,0,0.7)}.file.is-light:hover .file-cta,.file.is-light.is-hovered .file-cta{background-color:#eee;border-color:transparent;color:rgba(0,0,0,0.7)}.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:rgba(0,0,0,0.7)}.file.is-light:active .file-cta,.file.is-light.is-active .file-cta{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-dark .file-cta,.content kbd.file .file-cta{background-color:#363636;border-color:transparent;color:#fff}.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:#fff}.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:#fff}.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:#fff}.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-normal{font-size:1rem}.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:#222}.file-label:hover .file-name{border-color:#d5d5d5}.file-label:active .file-cta{background-color:#e8e8e8;color:#222}.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:#222}.file-name{border-color:#dbdbdb;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}.file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}.file-icon .fa{font-size:14px}.label{color:#222;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:.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:.75rem}}.control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}.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:#222}.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.5em;pointer-events:none;position:absolute;top:0;width:2.5em;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.5em}.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.5em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute !important;right:.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:.5em}.breadcrumb .icon:last-child{margin-left:.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;border-radius:.25rem;box-shadow:#bbb;color:#222;max-width:100%;position:relative}.card-footer:first-child,.card-content:first-child,.card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-footer:last-child,.card-content:last-child,.card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 0.125em 0.25em 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:0.75rem 1rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:0.75rem 1rem}.card-image{display:block;position:relative}.card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.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 #ededed;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 #ededed}.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:#bbb;padding-bottom:.5rem;padding-top:.5rem}.dropdown-item{color:#222;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:inherit;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:#ededed;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}}.media{align-items:flex-start;display:flex;text-align:inherit}.media .content:not(:last-child){margin-bottom:.75rem}.media .media{border-top:1px solid rgba(219,219,219,0.5);display:flex;padding-top:.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:.5rem}.media .media .media{padding-top:.5rem}.media .media .media+.media{margin-top:.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:inherit}@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}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.message.is-light .message-body{border-color:#f5f5f5}.message.is-dark,.content kbd.message{background-color:#fafafa}.message.is-dark .message-header,.content kbd.message .message-header{background-color:#363636;color:#fff}.message.is-dark .message-body,.content kbd.message .message-body{border-color:#363636}.message.is-primary,.docstring>section>a.message.docs-sourcelink{background-color:#eef8fc}.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:#1a6d8e}.message.is-link{background-color:#eff3fb}.message.is-link .message-header{background-color:#2e63b8;color:#fff}.message.is-link .message-body{border-color:#2e63b8;color:#3169c4}.message.is-info{background-color:#ecf7fe}.message.is-info .message-header{background-color:#209cee;color:#fff}.message.is-info .message-body{border-color:#209cee;color:#0e72b4}.message.is-success{background-color:#eefcf3}.message.is-success .message-header{background-color:#22c35b;color:#fff}.message.is-success .message-body{border-color:#22c35b;color:#198f43}.message.is-warning{background-color:#fffbeb}.message.is-warning .message-header{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.message.is-warning .message-body{border-color:#ffdd57;color:#947600}.message.is-danger{background-color:#ffeceb}.message.is-danger .message-header{background-color:#da0b00;color:#fff}.message.is-danger .message-body{border-color:#da0b00;color:#f50c00}.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:.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){.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:.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:rgba(0,0,0,0.7)}.navbar.is-light .navbar-brand>.navbar-item,.navbar.is-light .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}.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:rgba(0,0,0,0.7)}.navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-burger{color:rgba(0,0,0,0.7)}@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:rgba(0,0,0,0.7)}.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:rgba(0,0,0,0.7)}.navbar.is-light .navbar-start .navbar-link::after,.navbar.is-light .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}.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:rgba(0,0,0,0.7)}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}}.navbar.is-dark,.content kbd.navbar{background-color:#363636;color:#fff}.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:#fff}.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:#fff}.navbar.is-dark .navbar-brand .navbar-link::after,.content kbd.navbar .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-burger,.content kbd.navbar .navbar-burger{color:#fff}@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:#fff}.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:#fff}.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:#fff}.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:#fff}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active,.content kbd.navbar .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#fff}}.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:#222;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;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:#222;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{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.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:9999px}.pagination.is-rounded .pagination-link,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-link{border-radius:9999px}.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:#222;min-width:2.5em}.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-previous.is-disabled,.pagination-next[disabled],.pagination-next.is-disabled,.pagination-link[disabled],.pagination-link.is-disabled{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#6b6b6b;opacity:0.5}.pagination-previous,.pagination-next{padding-left:.75em;padding-right:.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}.pagination-list li{list-style:none}@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,.pagination-next,.pagination-link,.pagination-ellipsis{margin-bottom:0;margin-top:0}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between;margin-bottom:0;margin-top:0}.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{border-radius:6px;box-shadow:#bbb;font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}.panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}.panel.is-white .panel-block.is-active .panel-icon{color:#fff}.panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}.panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}.panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}.panel.is-light .panel-heading{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.panel.is-light .panel-tabs a.is-active{border-bottom-color:#f5f5f5}.panel.is-light .panel-block.is-active .panel-icon{color:#f5f5f5}.panel.is-dark .panel-heading,.content kbd.panel .panel-heading{background-color:#363636;color:#fff}.panel.is-dark .panel-tabs a.is-active,.content kbd.panel .panel-tabs a.is-active{border-bottom-color:#363636}.panel.is-dark .panel-block.is-active .panel-icon,.content kbd.panel .panel-block.is-active .panel-icon{color:#363636}.panel.is-primary .panel-heading,.docstring>section>a.panel.docs-sourcelink .panel-heading{background-color:#4eb5de;color:#fff}.panel.is-primary .panel-tabs a.is-active,.docstring>section>a.panel.docs-sourcelink .panel-tabs a.is-active{border-bottom-color:#4eb5de}.panel.is-primary .panel-block.is-active .panel-icon,.docstring>section>a.panel.docs-sourcelink .panel-block.is-active .panel-icon{color:#4eb5de}.panel.is-link .panel-heading{background-color:#2e63b8;color:#fff}.panel.is-link .panel-tabs a.is-active{border-bottom-color:#2e63b8}.panel.is-link .panel-block.is-active .panel-icon{color:#2e63b8}.panel.is-info .panel-heading{background-color:#209cee;color:#fff}.panel.is-info .panel-tabs a.is-active{border-bottom-color:#209cee}.panel.is-info .panel-block.is-active .panel-icon{color:#209cee}.panel.is-success .panel-heading{background-color:#22c35b;color:#fff}.panel.is-success .panel-tabs a.is-active{border-bottom-color:#22c35b}.panel.is-success .panel-block.is-active .panel-icon{color:#22c35b}.panel.is-warning .panel-heading{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ffdd57}.panel.is-warning .panel-block.is-active .panel-icon{color:#ffdd57}.panel.is-danger .panel-heading{background-color:#da0b00;color:#fff}.panel.is-danger .panel-tabs a.is-active{border-bottom-color:#da0b00}.panel.is-danger .panel-block.is-active .panel-icon{color:#da0b00}.panel-tabs:not(:last-child),.panel-block:not(:last-child){border-bottom:1px solid #ededed}.panel-heading{background-color:#ededed;border-radius:6px 6px 0 0;color:#222;font-size:1.25em;font-weight:700;line-height:1.25;padding:0.75em 1em}.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:.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}.panel-block:last-child{border-bottom-left-radius:6px;border-bottom-right-radius:6px}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:.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:.5em}.tabs .icon:last-child{margin-left:.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-top-left-radius:4px;border-bottom-left-radius:4px}.tabs.is-toggle li:last-child a{border-top-right-radius:4px;border-bottom-right-radius:4px}.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:9999px;border-top-left-radius:9999px;padding-left:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;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;width:unset}.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.33333337%}.columns.is-mobile>.column.is-offset-1{margin-left:8.33333337%}.columns.is-mobile>.column.is-2{flex:none;width:16.66666674%}.columns.is-mobile>.column.is-offset-2{margin-left:16.66666674%}.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.33333337%}.columns.is-mobile>.column.is-offset-4{margin-left:33.33333337%}.columns.is-mobile>.column.is-5{flex:none;width:41.66666674%}.columns.is-mobile>.column.is-offset-5{margin-left:41.66666674%}.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.33333337%}.columns.is-mobile>.column.is-offset-7{margin-left:58.33333337%}.columns.is-mobile>.column.is-8{flex:none;width:66.66666674%}.columns.is-mobile>.column.is-offset-8{margin-left:66.66666674%}.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.33333337%}.columns.is-mobile>.column.is-offset-10{margin-left:83.33333337%}.columns.is-mobile>.column.is-11{flex:none;width:91.66666674%}.columns.is-mobile>.column.is-offset-11{margin-left:91.66666674%}.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;width:unset}.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.33333337%}.column.is-offset-1-mobile{margin-left:8.33333337%}.column.is-2-mobile{flex:none;width:16.66666674%}.column.is-offset-2-mobile{margin-left:16.66666674%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-left:25%}.column.is-4-mobile{flex:none;width:33.33333337%}.column.is-offset-4-mobile{margin-left:33.33333337%}.column.is-5-mobile{flex:none;width:41.66666674%}.column.is-offset-5-mobile{margin-left:41.66666674%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-left:50%}.column.is-7-mobile{flex:none;width:58.33333337%}.column.is-offset-7-mobile{margin-left:58.33333337%}.column.is-8-mobile{flex:none;width:66.66666674%}.column.is-offset-8-mobile{margin-left:66.66666674%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-left:75%}.column.is-10-mobile{flex:none;width:83.33333337%}.column.is-offset-10-mobile{margin-left:83.33333337%}.column.is-11-mobile{flex:none;width:91.66666674%}.column.is-offset-11-mobile{margin-left:91.66666674%}.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;width:unset}.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.33333337%}.column.is-offset-1,.column.is-offset-1-tablet{margin-left:8.33333337%}.column.is-2,.column.is-2-tablet{flex:none;width:16.66666674%}.column.is-offset-2,.column.is-offset-2-tablet{margin-left:16.66666674%}.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.33333337%}.column.is-offset-4,.column.is-offset-4-tablet{margin-left:33.33333337%}.column.is-5,.column.is-5-tablet{flex:none;width:41.66666674%}.column.is-offset-5,.column.is-offset-5-tablet{margin-left:41.66666674%}.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.33333337%}.column.is-offset-7,.column.is-offset-7-tablet{margin-left:58.33333337%}.column.is-8,.column.is-8-tablet{flex:none;width:66.66666674%}.column.is-offset-8,.column.is-offset-8-tablet{margin-left:66.66666674%}.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.33333337%}.column.is-offset-10,.column.is-offset-10-tablet{margin-left:83.33333337%}.column.is-11,.column.is-11-tablet{flex:none;width:91.66666674%}.column.is-offset-11,.column.is-offset-11-tablet{margin-left:91.66666674%}.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;width:unset}.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.33333337%}.column.is-offset-1-touch{margin-left:8.33333337%}.column.is-2-touch{flex:none;width:16.66666674%}.column.is-offset-2-touch{margin-left:16.66666674%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-left:25%}.column.is-4-touch{flex:none;width:33.33333337%}.column.is-offset-4-touch{margin-left:33.33333337%}.column.is-5-touch{flex:none;width:41.66666674%}.column.is-offset-5-touch{margin-left:41.66666674%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-left:50%}.column.is-7-touch{flex:none;width:58.33333337%}.column.is-offset-7-touch{margin-left:58.33333337%}.column.is-8-touch{flex:none;width:66.66666674%}.column.is-offset-8-touch{margin-left:66.66666674%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-left:75%}.column.is-10-touch{flex:none;width:83.33333337%}.column.is-offset-10-touch{margin-left:83.33333337%}.column.is-11-touch{flex:none;width:91.66666674%}.column.is-offset-11-touch{margin-left:91.66666674%}.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;width:unset}.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.33333337%}.column.is-offset-1-desktop{margin-left:8.33333337%}.column.is-2-desktop{flex:none;width:16.66666674%}.column.is-offset-2-desktop{margin-left:16.66666674%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-left:25%}.column.is-4-desktop{flex:none;width:33.33333337%}.column.is-offset-4-desktop{margin-left:33.33333337%}.column.is-5-desktop{flex:none;width:41.66666674%}.column.is-offset-5-desktop{margin-left:41.66666674%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-left:50%}.column.is-7-desktop{flex:none;width:58.33333337%}.column.is-offset-7-desktop{margin-left:58.33333337%}.column.is-8-desktop{flex:none;width:66.66666674%}.column.is-offset-8-desktop{margin-left:66.66666674%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-left:75%}.column.is-10-desktop{flex:none;width:83.33333337%}.column.is-offset-10-desktop{margin-left:83.33333337%}.column.is-11-desktop{flex:none;width:91.66666674%}.column.is-offset-11-desktop{margin-left:91.66666674%}.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;width:unset}.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.33333337%}.column.is-offset-1-widescreen{margin-left:8.33333337%}.column.is-2-widescreen{flex:none;width:16.66666674%}.column.is-offset-2-widescreen{margin-left:16.66666674%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-left:25%}.column.is-4-widescreen{flex:none;width:33.33333337%}.column.is-offset-4-widescreen{margin-left:33.33333337%}.column.is-5-widescreen{flex:none;width:41.66666674%}.column.is-offset-5-widescreen{margin-left:41.66666674%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-left:50%}.column.is-7-widescreen{flex:none;width:58.33333337%}.column.is-offset-7-widescreen{margin-left:58.33333337%}.column.is-8-widescreen{flex:none;width:66.66666674%}.column.is-offset-8-widescreen{margin-left:66.66666674%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-left:75%}.column.is-10-widescreen{flex:none;width:83.33333337%}.column.is-offset-10-widescreen{margin-left:83.33333337%}.column.is-11-widescreen{flex:none;width:91.66666674%}.column.is-offset-11-widescreen{margin-left:91.66666674%}.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;width:unset}.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.33333337%}.column.is-offset-1-fullhd{margin-left:8.33333337%}.column.is-2-fullhd{flex:none;width:16.66666674%}.column.is-offset-2-fullhd{margin-left:16.66666674%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-left:25%}.column.is-4-fullhd{flex:none;width:33.33333337%}.column.is-offset-4-fullhd{margin-left:33.33333337%}.column.is-5-fullhd{flex:none;width:41.66666674%}.column.is-offset-5-fullhd{margin-left:41.66666674%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-left:50%}.column.is-7-fullhd{flex:none;width:58.33333337%}.column.is-offset-7-fullhd{margin-left:58.33333337%}.column.is-8-fullhd{flex:none;width:66.66666674%}.column.is-offset-8-fullhd{margin-left:66.66666674%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-left:75%}.column.is-10-fullhd{flex:none;width:83.33333337%}.column.is-offset-10-fullhd{margin-left:83.33333337%}.column.is-11-fullhd{flex:none;width:91.66666674%}.column.is-offset-11-fullhd{margin-left:91.66666674%}.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.33333337%}.tile.is-2{flex:none;width:16.66666674%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.33333337%}.tile.is-5{flex:none;width:41.66666674%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.33333337%}.tile.is-8{flex:none;width:66.66666674%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.33333337%}.tile.is-11{flex:none;width:91.66666674%}.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{color:#fff !important;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{color:#0a0a0a !important;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:rgba(0,0,0,0.7)}.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:rgba(0,0,0,0.7)}.hero.is-light .subtitle{color:rgba(0,0,0,0.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:rgba(0,0,0,0.7)}@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(0,0,0,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:rgba(0,0,0,0.7)}.hero.is-light .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{color:#f5f5f5 !important;opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,0.7)}.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:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);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:#fff}.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:#fff}.hero.is-dark .subtitle,.content kbd.hero .subtitle{color:rgba(255,255,255,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:#fff}@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(255,255,255,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:#fff}.hero.is-dark .tabs a,.content kbd.hero .tabs a{color:#fff;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{color:#363636 !important;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:#fff}.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:#fff;border-color:#fff;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{color:#4eb5de !important;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{color:#2e63b8 !important;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{color:#209cee !important;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{color:#22c35b !important;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{color:#ffdd57 !important;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{color:#da0b00 !important;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:1.5rem}@media screen and (min-width: 769px),print{.hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width: 769px),print{.hero.is-large .hero-body{padding:18rem 6rem}}.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}@media screen and (min-width: 769px),print{.hero-body{padding:3rem 3rem}}.section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){.section{padding:3rem 3rem}.section.is-medium{padding:9rem 4.5rem}.section.is-large{padding:18rem 6rem}}.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 6 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 6 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 6 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}details.admonition.is-details>.admonition-header{list-style:none}details.admonition.is-details>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f055"}details.admonition.is-details[open]>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f056"}.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{cursor:pointer;display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#f5f5f5;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #dbdbdb;overflow:auto}.docstring>header code{background-color:transparent}.docstring>header .docstring-article-toggle-button{min-width:1.1rem;padding:0.2rem 0.2rem 0.2rem 0}.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;overflow-x:hidden}#documenter .docs-main header.docs-navbar .docs-sidebar-button{display:block;font-size:1.5rem;padding-bottom:0.1rem;margin-right:1rem}#documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap;gap:1rem;align-items:center}#documenter .docs-main header.docs-navbar .docs-right .docs-icon,#documenter .docs-main header.docs-navbar .docs-right .docs-label{display:inline-block}#documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}@media screen and (max-width: 1055px){#documenter .docs-main header.docs-navbar .docs-right .docs-navbar-link{margin-left:0.4rem;margin-right:0.4rem}}#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 6 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}#documenter .docs-sidebar #documenter-search-query{color:#707070;width:14.4rem;box-shadow:inset 0 1px 2px rgba(10,10,10,0.1)}@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}}kbd.search-modal-key-hints{border-radius:0.25rem;border:1px solid rgba(0,0,0,0.6);box-shadow:0 2px 0 1px rgba(0,0,0,0.6);cursor:default;font-size:0.9rem;line-height:1.5;min-width:0.75rem;text-align:center;padding:0.1rem 0.3rem;position:relative;top:-1px}.search-min-width-50{min-width:50%}.search-min-height-100{min-height:100%}.search-modal-card-body{max-height:calc(100vh - 15rem)}.search-result-link{border-radius:0.7em;transition:all 300ms}.search-result-link:hover,.search-result-link:focus{background-color:rgba(0,128,128,0.1)}.search-result-link .property-search-result-badge,.search-result-link .search-filter{transition:all 300ms}.property-search-result-badge,.search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:#f5f5f5;background-color:rgba(51,65,85,0.501961);border-radius:0.6rem}.search-result-link:hover .property-search-result-badge,.search-result-link:hover .search-filter,.search-result-link:focus .property-search-result-badge,.search-result-link:focus .search-filter{color:#f1f5f9;background-color:#333}.search-filter{color:#333;background-color:#f5f5f5;transition:all 300ms}.search-filter:hover,.search-filter:focus{color:#333}.search-filter-selected{color:#f5f5f5;background-color:rgba(139,0,139,0.5)}.search-filter-selected:hover,.search-filter-selected:focus{color:#f5f5f5}.search-result-highlight{background-color:#ffdd57;color:black}.search-divider{border-bottom:1px solid #dbdbdb}.search-result-title{width:85%;color:#333}.search-result-code-title{font-size:0.875rem;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}#search-modal .modal-card-body::-webkit-scrollbar,#search-modal .filter-tabs::-webkit-scrollbar{height:10px;width:10px;background-color:transparent}#search-modal .modal-card-body::-webkit-scrollbar-thumb,#search-modal .filter-tabs::-webkit-scrollbar-thumb{background-color:gray;border-radius:1rem}#search-modal .modal-card-body::-webkit-scrollbar-track,#search-modal .filter-tabs::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.6);background-color:transparent}.w-100{width:100%}.gap-2{gap:0.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.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;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#F3F3F3;color:#444}.hljs-comment{color:#697070}.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:#ab5656}.hljs-literal{color:#695}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.gap-4{gap:1rem} diff --git a/v0.37.6/assets/themeswap.js b/v0.37.6/assets/themeswap.js new file mode 100644 index 0000000000..9f5eebe6aa --- /dev/null +++ b/v0.37.6/assets/themeswap.js @@ -0,0 +1,84 @@ +// Small function to quickly swap out themes. Gets put into the tag.. +function set_theme_from_local_storage() { + // Initialize 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 users preference is for dark color scheme + var darkPreference = + window.matchMedia("(prefers-color-scheme: dark)").matches === 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 primaryLightTheme = null; + var primaryDarkTheme = 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. + if (ss.ownerNode.getAttribute("data-theme-primary") !== null) { + primaryLightTheme = themename; + } + // Check if the theme is primary dark theme so that we could store its name in darkTheme + if (ss.ownerNode.getAttribute("data-theme-primary-dark") !== null) { + primaryDarkTheme = 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); + } + var activeTheme = null; + 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; + activeTheme = theme; + } else { + // If we did _not_ find an active theme, then we need to fall back to the primary theme + // which can either be dark or light, depending on the user's OS preference. + var activeTheme = darkPreference ? primaryDarkTheme : primaryLightTheme; + // In case it somehow happens that the relevant primary theme was not found in the + // preceding loop, we abort without doing anything. + if (activeTheme === null) { + console.error("Unable to determine primary theme."); + return; + } + // When switching to the primary light theme, then we must not have a class name + // for the tag. That's only for non-primary or the primary dark theme. + if (darkPreference) { + document.getElementsByTagName("html")[0].className = + "theme--" + activeTheme; + } else { + document.getElementsByTagName("html")[0].className = ""; + } + } + 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; + // we'll disable all the stylesheets, except for the active one + ss.disabled = !(themename == activeTheme); + } +} +set_theme_from_local_storage(); diff --git a/v0.37.6/assets/warner.js b/v0.37.6/assets/warner.js new file mode 100644 index 0000000000..3f6f5d0083 --- /dev/null +++ b/v0.37.6/assets/warner.js @@ -0,0 +1,52 @@ +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/v0.37.6/constructors/index.html b/v0.37.6/constructors/index.html new file mode 100644 index 0000000000..b7d3ddfc88 --- /dev/null +++ b/v0.37.6/constructors/index.html @@ -0,0 +1,84 @@ + +Constructing mathematical objects in AbstractAlgebra.jl · AbstractAlgebra.jl

Constructing mathematical objects in AbstractAlgebra.jl

Constructing objects in Julia

In Julia, one constructs objects of a given type by calling a type constructor. This is simply a function with the same name as the type itself. For example, to construct a BigInt object from an Int in Julia, we simply call the BigInt constructor:

n = BigInt(123)

Note that a number literal too big to fit in an Int or Int128 automatically creates a BigInt:

julia> typeof(12345678765456787654567890987654567898765678909876567890)
+BigInt

How we construct objects in AbstractAlgebra.jl

As we explain in Elements and parents, Julia types don't contain enough information to properly model groups, rings, fields, etc. Instead of using types to construct objects, we use special objects that we refer to as parent objects. They behave a lot like Julia types.

Consider the following simple example, to create a multiprecision integer:

n = ZZ(12345678765456787654567890987654567898765678909876567890)

Here ZZ is not a Julia type, but a callable object. However, for most purposes one can think of such a parent object as though it were a type.

Constructing parent objects

For more complicated groups, rings, fields, etc., one first needs to construct the parent object before one can use it to construct element objects.

AbstractAlgebra.jl provides a set of functions for constructing such parent objects. For example, to create a parent object for univariate polynomials over the integers, we use the polynomial_ring parent object constructor.

R, x = polynomial_ring(ZZ, :x)
+f = x^3 + 3x + 1
+g = R(12)

In this example, R is the parent object and we use it to convert the Int value $12$ to an element of the polynomial ring $\mathbb{Z}[x]$.

List of parent object constructors

For convenience, we provide a list of all the parent object constructors in AbstractAlgebra.jl and explain what mathematical domains they represent.

MathematicsAbstractAlgebra.jl constructor
$R = \mathbb{Z}$R = ZZ
$R = \mathbb{Q}$R = QQ
$R = \mathbb{F}_{p}$R = GF(p)
$R = \mathbb{Z}/n\mathbb{Z}$R, = residue_ring(ZZ, n)
$S = R[x]$S, x = polynomial_ring(R, :x)
$S = R[x, y]$S, (x, y) = polynomial_ring(R, [:x, :y])
$S = R\langle x, y\rangle$S, (x, y) = free_associative_algebra(R, [:x, :y])
$S = K(x)$S, x = rational_function_field(K, :x)
$S = K(x, y)$S, (x, y) = rational_function_field(K, [:x, :y])
$S = R[[x]]$ (to precision $n$)S, x = power_series_ring(R, n, :x)
$S = R[[x, y]]$ (to precision $n$)S, (x, y) = power_series_ring(R, n, [:x, :y])
$S = R((x))$ (to precision $n$)S, x = laurent_series_ring(R, n, :x)
$S = K((x))$ (to precision $n$)S, x = laurent_series_field(K, n, :x)
$S = R((x, y))$ (to precision $n$)S, (x, y) = laurent_polynomial_ring(R, n, [:x, :y])
Puiseux series ring to precision $n$S, x = puiseux_series_ring(R, n, :x)
Puiseux series field to precision $n$S, x = puiseux_series_field(R, n, :x)
$S = K(x)(y)/(f)$S, y = function_field(f, :y) with $f\in K(x)[t]$
$S = \mathrm{Frac}_R$S = fraction_field(R)
$S = R/(f)$S, = residue_ring(R, f)
$S = R/(f)$ (with $(f)$ maximal)S, = residue_field(R, f)
$S = \mathrm{Mat}_{m\times n}(R)$S = matrix_space(R, m, n)

Parent objects with variable names

The multivariate parent object constructors (polynomial_ring, power_series_ring, free_associative_algebra, laurent_polynomial_ring, and rational_function_field) share a common interface for specifying the variable names, which is provided by @varnames_interface.

AbstractAlgebra.@varnames_interfaceMacro
@varnames_interface [M.]f(args..., varnames) macros=:yes n=n range=1:n

Add methods X, vars = f(args..., varnames...) and macro X = @f(args..., varnames...) to current scope.

Created methods

X, gens::Vector{T} = f(args..., varnames::Vector{Symbol})

Base method, called by everything else defined below. If a module M is specified, this is implemented as a call to M.f. Otherwise, a method f with this signature must already exist.


X, gens... = f(args..., varnames...; kv...)
+X, gens... = f(args..., varnames::Tuple; kv...)

Compute X and gens via the base method. Then reshape gens into the shape defined by varnames according to variable_names.

The vararg varnames... method needs at least one argument to avoid confusion. Moreover a single VarName argument will be dispatched to use a univariate method of f if it exists (e.g. polynomial_ring(R, :x)). If you need those cases, use the Tuple method.

Keyword arguments are passed on to the base method.


X, x::Vector{T} = f(args..., n::Int, s::VarName = :x; kv...)

Shorthand for X, x = f(args..., "$s#" => 1:n; kv...). The name of the argument n can be changed via the n option. The range 1:n is given via the range option.

Setting n=:no disables creation of this method.


X = @f(args..., varnames...; kv...)
+X = @f(args..., varnames::Tuple; kv...)
+X = @f(args..., varname::VarName; kv...)

These macros behave like their f(args..., varnames; kv...) counterparts but also introduce the indexed varnames into the current scope. The first version needs at least one varnames argument. The third version calls the univariate method base method if it exists (e.g. polynomial_ring(R, varname)).

Setting macros=:no disables macro creation.

Warning

Turning varnames into a vector of symbols happens by evaluating variable_names(varnames) in the global scope of the current module. For interactive usage in the REPL this is fine, but in general you have no access to local variables and should not use any side effects in varnames.

Examples

julia> f(a, s::Vector{Symbol}) = a, String.(s)
+f (generic function with 1 method)
+
+julia> AbstractAlgebra.@varnames_interface f(a, s)
+@f (macro with 1 method)
+
+julia> f
+f (generic function with 5 methods)
+
+julia> f("hello", [:x, :y, :z])
+("hello", ["x", "y", "z"])
+
+julia> f("hello", :x => (1:1, 1:2), :y => 1:2, [:z])
+("hello", ["x[1, 1]" "x[1, 2]"], ["y[1]", "y[2]"], ["z"])
+
+julia> f("projective", ["x$i$j" for i in 0:1, j in 0:1], [:y0, :y1], [:z])
+("projective", ["x00" "x01"; "x10" "x11"], ["y0", "y1"], ["z"])
+
+julia> f("fun inputs", 'a':'g', Symbol.('x':'z', [0 1]))
+("fun inputs", ["a", "b", "c", "d", "e", "f", "g"], ["x0" "x1"; "y0" "y1"; "z0" "z1"])
+
+julia> @f("hello", "x#" => (1:1, 1:2), "y#" => (1:2), [:z])
+"hello"
+
+julia> (x11, x12, y1, y2, z)
+("x11", "x12", "y1", "y2", "z")
source
AbstractAlgebra.variable_namesFunction
variable_names(a...) -> Vector{Symbol}
+variable_names(a::Tuple) -> Vector{Symbol}

Create a vector of variable names from a variable name specification.

Each argument can be either an Array of VarNames, or of the form s::VarName => iter, or of the form s::VarName => (iter...). Here iter is supposed to be any iterable, typically a range like 1:5. The :s => iter specification is shorthand for ["s[$i]" for i in iter]. Similarly :s => (iter1, iter2) is shorthand for ["s[$i,$j]" for i in iter1, j in iter2], and likewise for three and more iterables.

As an alternative "s#" => iter is shorthand for ["s$i" for i in iter]. This also works for multiple iterators in that"s#" => (iter1, iter2) is shorthand for ["s$i$j" for i in iter1, j in iter2].

Examples

julia> AbstractAlgebra.variable_names([:x, :y])
+2-element Vector{Symbol}:
+ :x
+ :y
+
+julia> AbstractAlgebra.variable_names(:x => (0:0, 0:1), :y => 0:1, [:z])
+5-element Vector{Symbol}:
+ Symbol("x[0, 0]")
+ Symbol("x[0, 1]")
+ Symbol("y[0]")
+ Symbol("y[1]")
+ :z
+
+julia> AbstractAlgebra.variable_names("x#" => (0:0, 0:1), "y#" => 0:1)
+4-element Vector{Symbol}:
+ :x00
+ :x01
+ :y0
+ :y1
+
+julia> AbstractAlgebra.variable_names("x#" => 9:11)
+3-element Vector{Symbol}:
+ :x9
+ :x10
+ :x11
+
+julia> AbstractAlgebra.variable_names(["x$i$i" for i in 1:3])
+3-element Vector{Symbol}:
+ :x11
+ :x22
+ :x33
+
+julia> AbstractAlgebra.variable_names('a':'c', ['z'])
+4-element Vector{Symbol}:
+ :a
+ :b
+ :c
+ :z
source
AbstractAlgebra.reshape_to_varnamesFunction
reshape_to_varnames(vec::Vector{T}, varnames...) :: Tuple{Array{<:Any, T}}
+reshape_to_varnames(vec::Vector{T}, varnames::Tuple) :: Tuple{Array{<:Any, T}}

Turn vec into the shape of varnames. Reverse flattening from variable_names.

Examples

julia> s = ([:a, :b], "x#" => (1:1, 1:2), "y#" => 1:2, [:z]);
+
+julia> AbstractAlgebra.reshape_to_varnames(AbstractAlgebra.variable_names(s...), s...)
+([:a, :b], [:x11 :x12], [:y1, :y2], [:z])
+
+julia> R, v = polynomial_ring(ZZ, AbstractAlgebra.variable_names(s...))
+(Multivariate polynomial ring in 7 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[a, b, x11, x12, y1, y2, z])
+
+julia> (a, b), x, y, z = AbstractAlgebra.reshape_to_varnames(v, s...)
+(AbstractAlgebra.Generic.MPoly{BigInt}[a, b], AbstractAlgebra.Generic.MPoly{BigInt}[x11 x12], AbstractAlgebra.Generic.MPoly{BigInt}[y1, y2], AbstractAlgebra.Generic.MPoly{BigInt}[z])
+
+julia> R, (a, b), x, y, z = polynomial_ring(ZZ, s...)
+(Multivariate polynomial ring in 7 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[a, b], AbstractAlgebra.Generic.MPoly{BigInt}[x11 x12], AbstractAlgebra.Generic.MPoly{BigInt}[y1, y2], AbstractAlgebra.Generic.MPoly{BigInt}[z])
source
diff --git a/v0.37.6/direct_sum/index.html b/v0.37.6/direct_sum/index.html new file mode 100644 index 0000000000..f26af45ae1 --- /dev/null +++ b/v0.37.6/direct_sum/index.html @@ -0,0 +1,99 @@ + +Direct Sums · AbstractAlgebra.jl

Direct Sums

AbstractAlgebra allows the construction of the external direct sum of any nonempty vector of finitely presented modules.

Note that external direct sums are considered equal iff they are the same object.

Generic direct sum type

AbstractAlgebra provides a generic direct sum type Generic.DirectSumModule{T} where T is the element type of the base ring. The implementation is in src/generic/DirectSum.jl

Elements of direct sum modules have type Generic.DirectSumModuleElem{T}.

Abstract types

Direct sum module types belong to the abstract type FPModule{T} and their elements to FPModuleElem{T}.

Constructors

AbstractAlgebra.direct_sumFunction
direct_sum(m::Vector{<:FPModule{T}}) where T <: RingElement
+direct_sum(vals::FPModule{T}...) where T <: RingElement

Return a tuple $M, f, g$ consisting of $M$ the direct sum of the modules m (supplied as a vector of modules), a vector $f$ of the injections of the $m[i]$ into $M$ and a vector $g$ of the projections from $M$ onto the $m[i]$.

source

Examples

julia> F = FreeModule(ZZ, 5)
+Free module of rank 5 over integers
+
+julia> m1 = F(BigInt[4, 7, 8, 2, 6])
+(4, 7, 8, 2, 6)
+
+julia> m2 = F(BigInt[9, 7, -2, 2, -4])
+(9, 7, -2, 2, -4)
+
+julia> S1, f1 = sub(F, [m1, m2])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)
+
+julia> m1 = F(BigInt[3, 1, 7, 7, -7])
+(3, 1, 7, 7, -7)
+
+julia> m2 = F(BigInt[-8, 6, 10, -1, 1])
+(-8, 6, 10, -1, 1)
+
+julia> S2, f2 = sub(F, [m1, m2])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)
+
+julia> m1 = F(BigInt[2, 4, 2, -3, -10])
+(2, 4, 2, -3, -10)
+
+julia> m2 = F(BigInt[5, 7, -6, 9, -5])
+(5, 7, -6, 9, -5)
+
+julia> S3, f3 = sub(F, [m1, m2])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)
+
+julia> D, f = direct_sum(S1, S2, S3)
+(DirectSumModule over integers, AbstractAlgebra.Generic.ModuleHomomorphism{BigInt}[Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers, Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers, Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers], AbstractAlgebra.Generic.ModuleHomomorphism{BigInt}[Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations, Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations, Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations])

Functionality for direct sums

In addition to the Module interface, AbstractAlgebra direct sums implement the following functionality.

Basic manipulation

Examples

julia> F = FreeModule(ZZ, 5)
+Free module of rank 5 over integers
+
+julia> m1 = F(BigInt[4, 7, 8, 2, 6])
+(4, 7, 8, 2, 6)
+
+julia> m2 = F(BigInt[9, 7, -2, 2, -4])
+(9, 7, -2, 2, -4)
+
+julia> S1, f1 = sub(F, [m1, m2])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)
+
+julia> m1 = F(BigInt[3, 1, 7, 7, -7])
+(3, 1, 7, 7, -7)
+
+julia> m2 = F(BigInt[-8, 6, 10, -1, 1])
+(-8, 6, 10, -1, 1)
+
+julia> S2, f2 = sub(F, [m1, m2])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)
+
+julia> m1 = F(BigInt[2, 4, 2, -3, -10])
+(2, 4, 2, -3, -10)
+
+julia> m2 = F(BigInt[5, 7, -6, 9, -5])
+(5, 7, -6, 9, -5)
+
+julia> S3, f3 = sub(F, [m1, m2])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)
+
+julia> D, f = direct_sum(S1, S2, S3)
+(DirectSumModule over integers, AbstractAlgebra.Generic.ModuleHomomorphism{BigInt}[Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers, Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers, Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers], AbstractAlgebra.Generic.ModuleHomomorphism{BigInt}[Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations, Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations, Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations])
+
+julia> summands(D)
+3-element Vector{AbstractAlgebra.Generic.Submodule{BigInt}}:
+ Submodule over Integers with 2 generators and no relations
+ Submodule over Integers with 2 generators and no relations
+ Submodule over Integers with 2 generators and no relations
    (D::DirectSumModule{T}(::Vector{<:FPModuleElem{T}}) where T <: RingElement

Given a vector (or $1$-dim array) of module elements, where the $i$-th entry has to be an element of the $i$-summand of $D$, create the corresponding element in $D$.

Examples

julia> N = FreeModule(QQ, 1);
+
+julia> M = FreeModule(QQ, 2);
+
+julia> D, _ = direct_sum(M, N, M);
+
+julia> D([gen(M, 1), gen(N, 1), gen(M, 2)])
+(1//1, 0//1, 1//1, 0//1, 1//1)

Special Homomorphisms

Due to the special structure as direct sums, homomorphisms can be created by specifying homomorphisms for all summands. In case of the codmain being a direct sum as well, any homomorphism may be thought of as a matrix containing maps from the $i$-th source summand to the $j$-th target module:

ModuleHomomorphism(D::DirectSumModule{T}, S::DirectSumModule{T}, m::Matrix{Any}) where T <: RingElement

Given a matrix $m$ such that the $(i,j)$-th entry is either $0$ (Int(0)) or a ModuleHomomorphism from the $i$-th summand of $D$ to the $j$-th summand of $S$, construct the corresponding homomorphism.

ModuleHomomorphism(D::DirectSumModule{T}, S::FPModuleElem{T}, m::Vector{ModuleHomomorphism})

Given an array $a$ of ModuleHomomorphism such that $a_i$, the $i$-th entry of $a$ is a ModuleHomomorphism from the $i$-th summand of D into S, construct the direct sum of the components.

Given a matrix $m$ such that the $(i,j)$-th entry is either $0$ (Int(0)) or a ModuleHomomorphism from the $i$-th summand of $D$ to the $j$-th summand of $S$, construct the corresponding homomorphism.

Examples

julia> N = FreeModule(QQ, 2);
+
+julia> D, _ = direct_sum(N, N);
+
+julia> p = ModuleHomomorphism(N, N, [3,4] .* basis(N));
+
+julia> q = ModuleHomomorphism(N, N, [5,7] .* basis(N));
+
+julia> phi = ModuleHomomorphism(D, D, [p 0; 0 q])
+Module homomorphism
+  from DirectSumModule over rationals
+  to DirectSumModule over rationals
+
+julia> r = ModuleHomomorphism(N, D, [2,3] .* gens(D)[1:2])
+Module homomorphism
+  from vector space of dimension 2 over rationals
+  to DirectSumModule over rationals
+
+julia> psi = ModuleHomomorphism(D, D, [r, r])
+Module homomorphism
+  from DirectSumModule over rationals
+  to DirectSumModule over rationals
diff --git a/v0.37.6/euclidean_interface/index.html b/v0.37.6/euclidean_interface/index.html new file mode 100644 index 0000000000..7430b8ca64 --- /dev/null +++ b/v0.37.6/euclidean_interface/index.html @@ -0,0 +1,2 @@ + +Euclidean Ring Interface · AbstractAlgebra.jl

Euclidean Ring Interface

If a ring provides a meaningful Euclidean structure such that a useful Euclidean remainder can be computed practically, various additional functionality is provided by AbstractAlgebra.jl for those rings. This functionality depends on the following functions existing. An implementation must provide divrem, and the remaining are optional as generic fallbacks exist.

Base.divremMethod
divrem(f::T, g::T) where T <: RingElem

Return a pair q, r consisting of the Euclidean quotient and remainder of $f$ by $g$. A DivideError should be thrown if $g$ is zero.

source
Base.modMethod
mod(f::T, g::T) where T <: RingElem

Return the Euclidean remainder of $f$ by $g$. A DivideError should be thrown if $g$ is zero.

Note

For best compatibility with the internal assumptions made by AbstractAlgebra, the Euclidean remainder function should provide unique representatives for the residue classes; the mod function should satisfy

  1. mod(a_1, b) = mod(a_2, b) if and only if $b$ divides $a_1 - a_2$, and
  2. mod(0, b) = 0.
source
Base.divMethod
div(f::T, g::T) where T <: RingElem

Return the Euclidean quotient of $f$ by $g$. A DivideError should be thrown if $g$ is zero.

source
AbstractAlgebra.mulmodMethod
mulmod(f::T, g::T, m::T) where T <: RingElem

Return mod(f*g, m) but possibly computed more efficiently.

source
Base.powermodMethod
powermod(f::T, e::Int, m::T) where T <: RingElem

Return mod(f^e, m) but possibly computed more efficiently.

source
Base.invmodMethod
invmod(f::T, m::T) where T <: RingElem

Return an inverse of $f$ modulo $m$, meaning that isone(mod(invmod(f,m)*f,m)) returns true.

If such an inverse doesn't exist, a NotInvertibleError should be thrown.

source
AbstractAlgebra.dividesMethod
divides(f::T, g::T) where T <: RingElem

Return a pair, flag, q, where flag is set to true if $g$ divides $f$, in which case q is set to the quotient, or flag is set to false and q is set to zero(f).

source
AbstractAlgebra.removeMethod
remove(f::T, p::T) where T <: RingElem

Return a pair v, q where $p^v$ is the highest power of $p$ dividing $f$ and $q$ is the cofactor after $f$ is divided by this power.

See also valuation, which only returns the valuation.

source
Base.gcdMethod
gcd(a::T, b::T) where T <: RingElem

Return a greatest common divisor of $a$ and $b$, i.e., an element $g$ which is a common divisor of $a$ and $b$, and with the property that any other common divisor of $a$ and $b$ divides $g$.

Note

For best compatibility with the internal assumptions made by AbstractAlgebra, the return is expected to be unit-normalized in such a way that if the return is a unit, that unit should be one.

source
Base.gcdMethod
gcd(f::T, g::T, hs::T...) where T <: RingElem

Return a greatest common divisor of $f$, $g$ and the elements in hs.

source
Base.gcdMethod
gcd(fs::AbstractArray{<:T}) where T <: RingElem

Return a greatest common divisor of the elements in fs. Requires that fs is not empty.

source
Base.lcmMethod
lcm(f::T, g::T) where T <: RingElem

Return a least common multiple of $f$ and $g$, i.e., an element $d$ which is a common multiple of $f$ and $g$, and with the property that any other common multiple of $f$ and $g$ is a multiple of $d$.

source
Base.lcmMethod
lcm(f::T, g::T, hs::T...) where T <: RingElem

Return a least common multiple of $f$, $g$ and the elements in hs.

source
Base.lcmMethod
lcm(fs::AbstractArray{<:T}) where T <: RingElem

Return a least common multiple of the elements in fs. Requires that fs is not empty.

source
Base.gcdxMethod
gcdx(f::T, g::T) where T <: RingElem

Return a triple d, s, t such that $d = gcd(f, g)$ and $d = sf + tg$, with $s$ loosely reduced modulo $g/d$ and $t$ loosely reduced modulo $f/d$.

source
AbstractAlgebra.gcdinvMethod
gcdinv(f::T, g::T) where T <: RingElem

Return a tuple d, s such that $d = gcd(f, g)$ and $s = (f/d)^{-1} \pmod{g/d}$. Note that $d = 1$ iff $f$ is invertible modulo $g$, in which case $s = f^{-1} \pmod{g}$.

source
AbstractAlgebra.crtMethod
crt(r1::T, m1::T, r2::T, m2::T; check::Bool=true) where T <: RingElement

Return an element congruent to $r_1$ modulo $m_1$ and $r_2$ modulo $m_2$. If check = true and no solution exists, an error is thrown.

If T is a fixed precision integer type (like Int), the result will be correct if abs(ri) <= abs(mi) and abs(m1 * m2) < typemax(T).

source
AbstractAlgebra.crtMethod
crt(r::Vector{T}, m::Vector{T}; check::Bool=true) where T <: RingElement

Return an element congruent to $r_i$ modulo $m_i$ for each $i$.

source
AbstractAlgebra.crt_with_lcmMethod
crt_with_lcm(r1::T, m1::T, r2::T, m2::T; check::Bool=true) where T <: RingElement

Return a tuple consisting of an element congruent to $r_1$ modulo $m_1$ and $r_2$ modulo $m_2$ and the least common multiple of $m_1$ and $m_2$. If check = true and no solution exists, an error is thrown.

source
AbstractAlgebra.crt_with_lcmMethod
crt_with_lcm(r::Vector{T}, m::Vector{T}; check::Bool=true) where T <: RingElement

Return a tuple consisting of an element congruent to $r_i$ modulo $m_i$ for each $i$ and the least common multiple of the $m_i$.

source
diff --git a/v0.37.6/extending_abstractalgebra/index.html b/v0.37.6/extending_abstractalgebra/index.html new file mode 100644 index 0000000000..e06aaa3743 --- /dev/null +++ b/v0.37.6/extending_abstractalgebra/index.html @@ -0,0 +1,97 @@ + +Extending the interface of AbstractAlgebra.jl · AbstractAlgebra.jl

Extending the interface of AbstractAlgebra.jl

In this section we will discuss on how to extend the interface of AbstractAlgebra.jl.

Elements and parents

Any implementation with elements and parents should implement the following interface:

Base.parentFunction
parent(a)

Return parent object of given element $a$.

Examples

julia> G = SymmetricGroup(5); g = Perm([3,4,5,2,1])
+(1,3,5)(2,4)
+
+julia> parent(g) == G
+true
+
+julia> S, x = laurent_series_ring(ZZ, 3, "x")
+(Laurent series ring in x over integers, x + O(x^4))
+
+julia> parent(x) == S
+true
source
AbstractAlgebra.elem_typeFunction
elem_type(parent)
+elem_type(parent_type)

Given a parent object (or its type), return the type of its elements.

Examples

julia> S, x = power_series_ring(QQ, 2, "x")
+(Univariate power series ring over rationals, x + O(x^3))
+
+julia> elem_type(S) == typeof(x)
+true
source
AbstractAlgebra.parent_typeFunction
parent_type(element)
+parent_type(element_type)

Given an element (or its type), return the type of its parent object.

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S = matrix_space(R, 2, 2)
+Matrix space of 2 rows and 2 columns
+  over univariate polynomial ring in x over integers
+
+julia> a = rand(S, 0:1, 0:1);
+
+julia> parent_type(a) == typeof(S)
+true
source

Acquiring associated elements and parents

Further, if one has a base ring, like polynomials over the integers $\mathbb{Z}[x]$, then one should implement

AbstractAlgebra.base_ringFunction
base_ring(a)

Return base ring $R$ of given element or parent $a$.

Examples

julia> S, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> base_ring(S) == QQ
+true
+
+julia> R = GF(7)
+Finite field F_7
+
+julia> base_ring(R)
+Union{}
source

Special elements

For rings, one has to extend the following methods:

Base.oneFunction
one(a)

Return the multiplicative identity in the algebraic structure of $a$, which can be either an element or parent.

Examples

julia> S = matrix_space(ZZ, 2, 2)
+Matrix space of 2 rows and 2 columns
+  over integers
+
+julia> one(S)
+[1   0]
+[0   1]
+
+julia> R, x = puiseux_series_field(QQ, 4, "x")
+(Puiseux series field in x over rationals, x + O(x^5))
+
+julia> one(x)
+1 + O(x^4)
+
+julia> G = GF(5)
+Finite field F_5
+
+julia> one(G)
+1
source
Base.zeroFunction
zero(a)

Return the additive identity in the algebraic structure of $a$, which can be either an element or parent.

Examples

julia> S = matrix_ring(QQ, 2)
+Matrix ring of degree 2
+  over rationals
+
+julia> zero(S)
+[0//1   0//1]
+[0//1   0//1]
+
+julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> zero(x^3 + 2)
+0
source

Groups should only extend at least one of these. The one that is required depends on if the group is additive (commutative) or multiplicative.

Basic manipulation

If one would like to implement a ring, these are the basic manipulation methods that all rings should extend:

Base.isoneFunction
isone(a)

Return true if $a$ is the multiplicative identity, else return false.

Examples

julia> S = matrix_space(ZZ, 2, 2); T = matrix_space(ZZ, 2, 3); U = matrix_space(ZZ, 3, 2);
+
+julia> isone(S([1 0; 0 1]))
+true
+
+julia> isone(T([1 0 0; 0 1 0]))
+false
+
+julia> isone(U([1 0; 0 1; 0 0]))
+false
+
+julia> T, x = puiseux_series_field(QQ, 10, "x")
+(Puiseux series field in x over rationals, x + O(x^11))
+
+julia> isone(x), isone(T(1))
+(false, true)
source
Base.iszeroFunction
iszero(a)

Return true if $a$ is the additative identity, else return false.

Examples

julia> T, x = puiseux_series_field(QQ, 10, "x")
+(Puiseux series field in x over rationals, x + O(x^11))
+
+julia> a = T(0)
+O(x^10)
+
+julia> iszero(a)
+true
source
AbstractAlgebra.is_unitFunction
is_unit(a::T) where {T <: NCRingElem}

Return true if $a$ is invertible, else return false.

Examples

julia> S, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> is_unit(x), is_unit(S(1)), is_unit(S(4))
+(false, true, true)
+
+julia> is_unit(ZZ(-1)), is_unit(ZZ(4))
+(true, false)
source

With the same logic as earlier, groups only need to extend one of the methods isone and iszero.

diff --git a/v0.37.6/field/index.html b/v0.37.6/field/index.html new file mode 100644 index 0000000000..9e22585d62 --- /dev/null +++ b/v0.37.6/field/index.html @@ -0,0 +1,4 @@ + +Field functionality · AbstractAlgebra.jl

Field functionality

Abstract types for rings

All field types in AbstractAlgebra belong to the Field abstract type and field elements belong to the FieldElem abstract type.

As Julia types cannot belong to our FieldElem type hierarchy, we also provide the union type FieldElement which includes FieldElem in union with the Julia types Rational and AbstractFloat.

Note that

Field <: Ring
+FieldElem <: RingElem
+FieldElement <: RingElement

Of course all Ring functionality is available for AbstractAlgebra fields and their elements.

Functions for types and parents of fields

characteristic(R::MyParent)

Return the characteristic of the field. If the characteristic is not known, an exception is raised.

Basic functions

is_unit(f::MyElem)

Return true if the given element is invertible, i.e. nonzero in the field.

diff --git a/v0.37.6/field_interface/index.html b/v0.37.6/field_interface/index.html new file mode 100644 index 0000000000..afd4cf080b --- /dev/null +++ b/v0.37.6/field_interface/index.html @@ -0,0 +1,2 @@ + +Field Interface · AbstractAlgebra.jl

Field Interface

AbstractAlgebra.jl generic code makes use of a standardised set of functions which it expects to be implemented for all fields. Here we document this interface. All libraries which want to make use of the generic capabilities of AbstractAlgebra.jl must supply all of the required functionality for their fields.

Types

Most fields must supply two types:

  • a type for the parent object (representing the field itself)
  • a type for elements of that field

For example, the generic fraction field type in AbstractAlgebra.jl provides two types in generic/GenericTypes.jl:

  • Generic.FracField{T} for the parent objects
  • Generic.FracFieldElem{T} for the actual fractions

The parent type must belong to Field and the element type must belong to FieldElem. Of course, the types may belong to these abstract types transitively.

For parameterised fields, we advise that the types of both the parent objects and element objects to be parameterised by the types of the elements of the base ring.

There can be variations on this theme: e.g. in some areas of mathematics there is a notion of a coefficient domain, in which case it may make sense to parameterise all types by the type of elements of this coefficient domain. But note that this may have implications for the ad hoc operators one might like to explicitly implement.

FieldElement type union

Because of its lack of multiple inheritance, Julia does not allow Julia Base types to belong to FieldElem. To allow us to work equally with AbstractAlgebra and Julia types that represent elements of fields we define a union type FieldElement in src/julia/JuliaTypes.

So far, in addition to FieldElem the union type FieldElement includes the Julia types Rational and AbstractFloat.

Most of the generic code in AbstractAlgebra makes use of the union type FieldElement instead of FieldElem so that the generic functions also accept the Julia Base field types.

Note

One must be careful when defining ad hoc binary operations for field element types. It is often necessary to define separate versions of the functions for FieldElem then for each of the Julia types separately in order to avoid ambiguity warnings.

Note that even though FieldElement is a union type we still have the following inclusion

FieldElement <: RingElement

Parent object caches

In many cases, it is desirable to have only one object in the system to represent each field. This means that if the same field is constructed twice, elements of the two fields will be compatible as far as arithmetic is concerned.

In order to facilitate this, global caches of fields are stored in AbstractAlgebra.jl, usually implemented using dictionaries. For example, the Generic.FracField parent objects are looked up in a dictionary FracDict to see if they have been previously defined.

Whether these global caches are provided or not, depends on both mathematical and algorithmic considerations. E.g. in the case of number fields, it isn't desirable to identify all number fields with the same defining polynomial, as they may be considered with distinct embeddings into one another. In other cases, identifying whether two fields are the same may be prohibitively expensive. Generally, it may only make sense algorithmically to identify two fields if they were constructed from identical data.

If a global cache is provided, it must be optionally possible to construct the parent objects without caching. This is done by passing a boolean value cached to the inner constructor of the parent object. See generic/GenericTypes.jl for examples of how to construct and handle such caches.

Required functions for all fields

In the following, we list all the functions that are required to be provided for fields in AbstractAlgebra.jl or by external libraries wanting to use AbstractAlgebra.jl.

We give this interface for fictitious types MyParent for the type of the field parent object R and MyElem for the type of the elements of the field.

Note

Generic functions in AbstractAlgebra.jl may not rely on the existence of functions that are not documented here. If they do, those functions will only be available for fields that implement that additional functionality, and should be documented as such.

In the first place, all fields are rings and therefore any field type must implement all of the Ring interface. The functionality below is in addition to this basic functionality.

Data type and parent object methods

characteristic(R::MyParent)

Return the characteristic of the field. If the characteristic is not known, an exception is raised.

Basic manipulation of rings and elements

is_unit(f::MyElem)

Return true if the given element is invertible, i.e. nonzero in the field.

diff --git a/v0.37.6/field_introduction/index.html b/v0.37.6/field_introduction/index.html new file mode 100644 index 0000000000..0481c1db20 --- /dev/null +++ b/v0.37.6/field_introduction/index.html @@ -0,0 +1,2 @@ + +Introduction · AbstractAlgebra.jl

Introduction

A number of basic fields are provided, such as the rationals, finite fields, the real field, etc.

Various generic field constructions can then be made recursively on top of these basic fields. For example, fraction fields, residue fields, function fields, etc.

From the point of view of the system, all fields are rings and whether an object is a ring/field or an element thereof can be determined at the type level. There are abstract types for all field and for all field element types.

The field hierarchy can be extended by implementing new fields to follow one or more field interfaces, including the interface that all fields must follow. Once an interface is satisfied, all the corresponding generic functionality will work over the new field.

Implementations of new fields can either be generic or can be specialised implementations provided by, for example, a C library.

diff --git a/v0.37.6/finfield/index.html b/v0.37.6/finfield/index.html new file mode 100644 index 0000000000..2c29fdec05 --- /dev/null +++ b/v0.37.6/finfield/index.html @@ -0,0 +1,55 @@ + +Finite fields · AbstractAlgebra.jl

Finite fields

AbstractAlgebra.jl provides a module, implemented in src/julia/GF.jl for finite fields. The module is a naive implementation that supports only fields of degree $1$ (prime fields). They are modelled as $\mathbb{Z}/p\mathbb{Z}$ for $p$ a prime.

Types and parent objects

Finite fields have type GFField{T} where T is either Int or BigInt.

Elements of such a finite field have type GFElem{T}.

Finite field constructors

In order to construct finite fields in AbstractAlgebra.jl, one must first construct the field itself. This is accomplished with the following constructors.

AbstractAlgebra.GFMethod
GF(p::T; check::Bool=true) where T <: Integer

Return the finite field $\mathbb{F}_p$, where $p$ is a prime. By default, the integer $p$ is checked with a probabilistic algorithm for primality. When check == false, no check is made, but the behaviour of the resulting object is undefined if $p$ is composite.

source

Here are some examples of creating a finite field and making use of the resulting parent object to coerce various elements into the field.

Examples

julia> F = GF(13)
+Finite field F_13
+
+julia> g = F(3)
+3
+
+julia> h = F(g)
+3
+
+julia> GF(4)
+ERROR: DomainError with 4:
+Characteristic is not prime in GF(p)
+Stacktrace:
+[...]

Basic field functionality

The finite field module in AbstractAlgebra.jl implements the full Field interface.

We give some examples of such functionality.

Examples

julia> F = GF(13)
+Finite field F_13
+
+julia> f = F(7)
+7
+
+julia> h = zero(F)
+0
+
+julia> k = one(F)
+1
+
+julia> isone(k)
+true
+
+julia> iszero(h)
+true
+
+julia> T = parent(h)
+Finite field F_13
+
+julia> h == deepcopy(h)
+true
+
+julia> h = h + 2
+2
+
+julia> m = inv(k)
+1
+

Basic manipulation of fields and elements

AbstractAlgebra.dataMethod
data(R::GFElem)

Return the internal data used to represent the finite field element. This coincides with lift except where the internal data ids a machine integer.

source
AbstractAlgebra.liftMethod
lift(R::GFElem)

Lift the finite field element to the integers. The result will be a multiprecision integer regardless of how the field element is represented internally.

source
AbstractAlgebra.genMethod
gen(R::GFField{T}) where T <: Integer

Return a generator of the field. Currently this returns 1.

source

Examples

julia> F = GF(13)
+Finite field F_13
+
+julia> d = degree(F)
+1
+
+julia> n = order(F)
+13
+
+julia> g = gen(F)
+1
+
diff --git a/v0.37.6/fraction/index.html b/v0.37.6/fraction/index.html new file mode 100644 index 0000000000..cebaaaa7eb --- /dev/null +++ b/v0.37.6/fraction/index.html @@ -0,0 +1,190 @@ + +Generic fraction fields · AbstractAlgebra.jl

Generic fraction fields

AbstractAlgebra.jl provides a module, implemented in src/Fraction.jl for fraction fields over any gcd domain belonging to the AbstractAlgebra.jl abstract type hierarchy.

Generic fraction types

AbstractAlgebra.jl implements a generic fraction type Generic.FracFieldElem{T} where T is the type of elements of the base ring. See the file src/generic/GenericTypes.jl for details.

Parent objects of such fraction elements have type Generic.FracField{T}.

Factored fraction types

AbstractAlgebra.jl also implements a fraction type Generic.FactoredFracFieldElem{T} with parent objects of such fractions having type Generic.FactoredFracField{T}. As opposed to the fractions of type Generic.FracFieldElem{T}, which are just a numerator and denominator, these fractions are maintained in factored form as much as possible.

Abstract types

All fraction element types belong to the abstract type FracElem{T} and the fraction field types belong to the abstract type FracField{T}. This enables one to write generic functions that can accept any AbstractAlgebra fraction type.

Note

Both the generic fraction field type Generic.FracField{T} and the abstract type it belongs to, FracField{T} are both called FracField. The former is a (parameterised) concrete type for a fraction field over a given base ring whose elements have type T. The latter is an abstract type representing all fraction field types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).

Fraction field constructors

In order to construct fractions in AbstractAlgebra.jl, one can first construct the fraction field itself. This is accomplished with the following constructor.

fraction_field(R::Ring; cached::Bool = true)

Given a base ring R return the parent object of the fraction field of $R$. By default the parent object S will depend only on R and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

Here are some examples of creating fraction fields and making use of the resulting parent objects to coerce various elements into the fraction field.

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S = fraction_field(R)
+Fraction field
+  of univariate polynomial ring in x over integers
+
+julia> f = S()
+0
+
+julia> g = S(123)
+123
+
+julia> h = S(BigInt(1234))
+1234
+
+julia> k = S(x + 1)
+x + 1

Factored Fraction field constructors

The corresponding factored field uses the following constructor.

FactoredFractionField(R::Ring; cached::Bool = true)

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> S = FactoredFractionField(R)
+Factored fraction field of Multivariate polynomial ring in 2 variables over integers
+
+julia> (X, Y) = (S(x), S(y))
+(x, y)
+
+julia> f = X^6*(X+Y)^2*(X^2+Y)^3*(X+2*Y)^-3*(X+3*Y)^-4
+x^6*(x + y)^2*(x^2 + y)^3/((x + 2*y)^3*(x + 3*y)^4)
+
+julia> numerator(f)
+x^14 + 2*x^13*y + x^12*y^2 + 3*x^12*y + 6*x^11*y^2 + 3*x^10*y^3 + 3*x^10*y^2 + 6*x^9*y^3 + 3*x^8*y^4 + x^8*y^3 + 2*x^7*y^4 + x^6*y^5
+
+julia> denominator(f)
+x^7 + 18*x^6*y + 138*x^5*y^2 + 584*x^4*y^3 + 1473*x^3*y^4 + 2214*x^2*y^5 + 1836*x*y^6 + 648*y^7
+
+julia> derivative(f, x)
+x^5*(x + y)*(x^2 + y)^2*(7*x^5 + 58*x^4*y + 127*x^3*y^2 + x^3*y + 72*x^2*y^3 + 22*x^2*y^2 + 61*x*y^3 + 36*y^4)/((x + 2*y)^4*(x + 3*y)^5)

Fraction constructors

One can construct fractions using the fraction field parent object, as for any ring or field.

(R::FracField)() # constructs zero
+(R::FracField)(c::Integer)
+(R::FracField)(c::elem_type(R))
+(R::FracField{T})(a::T) where T <: RingElement

One may also use the Julia double slash operator to construct elements of the fraction field without constructing the fraction field parent first.

//(x::T, y::T) where T <: RingElement

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S = fraction_field(R)
+Fraction field
+  of univariate polynomial ring in x over rationals
+
+julia> f = S(x + 1)
+x + 1
+
+julia> g = (x^2 + x + 1)//(x^3 + 3x + 1)
+(x^2 + x + 1)//(x^3 + 3*x + 1)
+
+julia> x//f
+x//(x + 1)
+
+julia> f//x
+(x + 1)//x

Functions for types and parents of fraction fields

Fraction fields in AbstractAlgebra.jl implement the Ring interface.

base_ring(R::FracField)
+base_ring(a::FracElem)

Return the base ring of which the fraction field was constructed.

parent(a::FracElem)

Return the fraction field of the given fraction.

characteristic(R::FracField)

Return the characteristic of the base ring of the fraction field. If the characteristic is not known an exception is raised.

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S = fraction_field(R)
+Fraction field
+  of univariate polynomial ring in x over rationals
+
+julia> f = S(x + 1)
+x + 1
+
+julia> U = base_ring(S)
+Univariate polynomial ring in x over rationals
+
+julia> V = base_ring(f)
+Univariate polynomial ring in x over rationals
+
+julia> T = parent(f)
+Fraction field
+  of univariate polynomial ring in x over rationals
+
+julia> m = characteristic(S)
+0

Fraction field functions

Basic functions

Fraction fields implement the Ring interface.

zero(R::FracField)
+one(R::FracField)
+iszero(a::FracElem)
+isone(a::FracElem)
inv(a::T) where T <: FracElem

They also implement the field interface.

is_unit(f::FracElem)

And they implement the fraction field interface.

numerator(a::FracElem)
+denominator(a::FracElem)

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S = fraction_field(R)
+Fraction field
+  of univariate polynomial ring in x over rationals
+
+julia> f = S(x + 1)
+x + 1
+
+julia> g = (x^2 + x + 1)//(x^3 + 3x + 1)
+(x^2 + x + 1)//(x^3 + 3*x + 1)
+
+julia> h = zero(S)
+0
+
+julia> k = one(S)
+1
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> r = deepcopy(f)
+x + 1
+
+julia> n = numerator(g)
+x^2 + x + 1
+
+julia> d = denominator(g)
+x^3 + 3*x + 1

Greatest common divisor

Base.gcdMethod
gcd(a::FracElem{T}, b::FracElem{T}) where {T <: RingElem}

Return a greatest common divisor of $a$ and $b$ if one exists. N.B: we define the GCD of $a/b$ and $c/d$ to be gcd$(ad, bc)/bd$, reduced to lowest terms. This requires the existence of a greatest common divisor function for the base ring.

source

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> f = (x + 1)//(x^3 + 3x + 1)
+(x + 1)//(x^3 + 3*x + 1)
+
+julia> g = (x^2 + 2x + 1)//(x^2 + x + 1)
+(x^2 + 2*x + 1)//(x^2 + x + 1)
+
+julia> h = gcd(f, g)
+(x + 1)//(x^5 + x^4 + 4*x^3 + 4*x^2 + 4*x + 1)
+

Square root

Base.sqrtMethod
Base.sqrt(a::FracElem{T}; check::Bool=true) where T <: RingElem

Return the square root of $a$. By default the function will throw an exception if the input is not square. If check=false this test is omitted.

source

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S = fraction_field(R)
+Fraction field
+  of univariate polynomial ring in x over rationals
+
+julia> a = (21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)
+(21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)
+
+julia> sqrt(a^2)
+(21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)
+
+julia> is_square(a^2)
+true

Remove and valuation

When working over a Euclidean domain, it is convenient to extend valuations to the fraction field. To facilitate this, we define the following functions.

AbstractAlgebra.removeMethod
remove(z::FracElem{T}, p::T) where {T <: RingElem}

Return the tuple $n, x$ such that $z = p^nx$ where $x$ has valuation $0$ at $p$.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> f = (x + 1)//(x^3 + 3x + 1)
+(x + 1)//(x^3 + 3*x + 1)
+
+julia> g = (x^2 + 1)//(x^2 + x + 1)
+(x^2 + 1)//(x^2 + x + 1)
+
+julia> v, q = remove(f^3*g, x + 1)
+(3, (x^2 + 1)//(x^11 + x^10 + 10*x^9 + 12*x^8 + 39*x^7 + 48*x^6 + 75*x^5 + 75*x^4 + 66*x^3 + 37*x^2 + 10*x + 1))
+
+julia> v = valuation(f^3*g, x + 1)
+3
+

Random generation

Random fractions can be generated using rand. The parameters passed after the fraction field tell rand how to generate random elements of the base ring.

rand(R::FracField, v...)

Examples

julia> K = fraction_field(ZZ)
+Rationals
+
+julia> f = rand(K, -10:10)
+-1//3
+
+julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S = fraction_field(R)
+Fraction field
+  of univariate polynomial ring in x over integers
+
+julia> g = rand(S, -1:3, -10:10)
+(-4*x - 4)//(4*x^2 + x - 4)

Extra functionality for factored fractions

The Generic.FactoredFracFieldElem{T} type implements an interface similar to that of the Fac{T} type for iterating over the terms in the factorisation. There is also the function push_term!(a, b, e) for efficiently performing a *= b^e, and the function normalise returns relatively prime terms.

Examples

julia> F = FactoredFractionField(ZZ)
+Factored fraction field of Integers
+
+julia> f = F(-1)
+-1
+
+julia> push_term!(f, 10, 10)
+-10^10
+
+julia> push_term!(f, 42, -8)
+-10^10/42^8
+
+julia> normalise(f)
+-5^10*2^2/21^8
+
+julia> unit(f)
+-1
+
+julia> collect(f)
+2-element Vector{Tuple{BigInt, Int64}}:
+ (10, 10)
+ (42, -8)
diff --git a/v0.37.6/fraction_interface/index.html b/v0.37.6/fraction_interface/index.html new file mode 100644 index 0000000000..6393a6c6fd --- /dev/null +++ b/v0.37.6/fraction_interface/index.html @@ -0,0 +1,2 @@ + +Fraction Field Interface · AbstractAlgebra.jl

Fraction Field Interface

Fraction fields are supported in AbstractAlgebra.jl, at least for gcd domains. In addition to the standard Ring interface, some additional functions are required to be present for fraction fields.

Types and parents

AbstractAlgebra provides two abstract types for fraction fields and their elements:

  • FracField{T} is the abstract type for fraction field parent types
  • FracElem{T} is the abstract type for types of fractions

We have that FracField{T} <: Field and FracElem{T} <: FieldElem.

Note that both abstract types are parameterised. The type T should usually be the type of elements of the base ring of the fraction field.

Fraction fields should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Fraction fields should at least be distinguished based on their base ring.

See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).

Required functionality for fraction fields

In addition to the required functionality for the Field interface the Fraction Field interface has the following required functions.

We suppose that R is a fictitious base ring, and that S is the fraction field with parent object S of type MyFracField{T}. We also assume the fractions in the field have type MyFrac{T}, where T is the type of elements of the base ring.

Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.

Note that the type T must (transitively) belong to the abstract type RingElem.

Constructors

The following constructors create fractions. Note that these constructors don't require construction of the parent object first. This is easier to achieve if the fraction element type doesn't contain a reference to the parent object, but merely contains a reference to the base ring. The parent object can then be constructed on demand.

//(x::T, y::T) where T <: RingElem

Return the fraction $x/y$.

//(x::T, y::FracElem{T}) where T <: RingElem

Return $x/y$ where $x$ is in the base ring of $y$.

//(x::FracElem{T}, y::T) where T <: RingElem

Return $x/y$ where $y$ is in the base ring of $x$.

Basic manipulation of fields and elements

numerator(d::MyFrac{T}) where T <: RingElem

Given a fraction $d = a/b$ return $a$, where $a/b$ is in lowest terms with respect to the canonical_unit and gcd functions on the base ring.

denominator(d::MyFrac{T}) where T <: RingElem

Given a fraction $d = a/b$ return $b$, where $a/b$ is in lowest terms with respect to the canonical_unit and gcd functions on the base ring.

diff --git a/v0.37.6/free_associative_algebra/index.html b/v0.37.6/free_associative_algebra/index.html new file mode 100644 index 0000000000..7dc0a92e28 --- /dev/null +++ b/v0.37.6/free_associative_algebra/index.html @@ -0,0 +1,126 @@ + +Free algebras · AbstractAlgebra.jl

Free algebras

AbstractAlgebra.jl provides a module, implemented in src/FreeAssAlgebra.jl for free associative algebras over any commutative ring belonging to the AbstractAlgebra abstract type hierarchy.

Generic free algebra types

AbstractAlgebra provides a generic type Generic.FreeAssAlgElem{T} where T is the type of elements of the coefficient ring. The elements are implemented using a Julia array of coefficients and a vector of vectors of Ints for the monomial words. Parent objects of such elements have type Generic.FreeAssAlgebra{T}.

The element types belong to the abstract type NCRingElem, and the algebra types belong to the abstract type NCRing.

The following basic functions are implemented.

base_ring(R::FreeAssAlgebra)
+base_ring(a::FreeAssAlgElem)
+parent(a::FreeAssAlgElem)
+characteristic(R::FreeAssAlgebra)

Free algebra constructors

free_associative_algebra(R::Ring, s::AbstractVector{<:VarName}; cached::Bool = true)
+free_associative_algebra(R::Ring, n::Int, s::VarName; cached::Bool = false)

The first constructor, given a base ring R and an array s of variables, will return a tuple S, (x, ...) representing the new algebra $S = R \left<x, \ldots \right>$ and a tuple of generators $(x, ...)$.

The second constructor given a string s and a number of variables n will do the same as the first constructor except that the variables will be automatically numbered as, s1, s2, ..., sn.

By default the parent object S will depend only on R and (x, ...) and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

Examples

julia> R, (x, y) = free_associative_algebra(ZZ, ["x", "y"])
+(Free associative algebra on 2 indeterminates over integers, AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}[x, y])
+
+julia> (x + y + 1)^2
+x^2 + x*y + y*x + y^2 + 2*x + 2*y + 1
+
+
+julia> (x*y*x*x)^4
+x*y*x^3*y*x^3*y*x^3*y*x^2

Free algebra element constructors

Elements of a free algebra can be constructed from the generators in the usual way using arithmetic operations. Also, all of the standard ring element constructors may be used. Finally, the MPolyBuildCtx is overloaded to work with coefficients and monomial words and not exponent vectors.

Examples

julia> R, (x, y, z) = free_associative_algebra(ZZ, ["x", "y", "z"])
+(Free associative algebra on 3 indeterminates over integers, AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}[x, y, z])
+
+julia> B = MPolyBuildCtx(R)
+Builder for an element of Free associative algebra on 3 indeterminates over integers
+
+julia> push_term!(B, ZZ(1), [1,2,3,1]); push_term!(B, ZZ(2), [3,3,1]); finish(B)
+x*y*z*x + 2*z^2*x
+
+julia> push_term!(B, ZZ(3), [3,3,3]); push_term!(B, ZZ(4), Int[]); finish(B)
+3*z^3 + 4
+
+julia> [gen(R, 2), R(9)]
+2-element Vector{AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}}:
+ y
+ 9

Element functions

Basic manipulation

The standard ring functions are available. The following functions from the multivariate polynomial interface are provided.

symbols(S::FreeAssAlgebra)
+number_of_variables(f::FreeAssAlgebra)
+gens(S::FreeAssAlgebra)
+gen(S::FreeAssAlgebra, i::Int)
+is_gen(x::FreeAssAlgElem)
+total_degree(a::FreeAssAlgElem)
+length(f::FreeAssAlgElem)

As with multivariate polynomials, an implementation must provide access to the elements as a sum of individual terms in some order. The length function provides the number of such terms, and the following functions provide the first such term.

leading_coefficient(a::FreeAssAlgElem)
+leading_monomial(a::FreeAssAlgElem)
+leading_term(a::FreeAssAlgElem)
+leading_exponent_word(a::FreeAssAlgElem)

For types that allow constant time access to coefficients, the following are also available, allowing access to the given coefficient, monomial or term. Terms are numbered from the most significant first.

coeff(f::FreeAssAlgElem, n::Int)
+monomial(f::FreeAssAlgElem, n::Int)
+term(f::FreeAssAlgElem, n::Int)

In contrast with the interface for multivariable polynomials, the function exponent_vector is replaced by exponent_word

AbstractAlgebra.Generic.exponent_wordMethod
exponent_word(a::FreeAssAlgElem{T}, i::Int) where T <: RingElement

Return a vector of variable indices corresponding to the monomial of the $i$-th term of $a$. Term numbering begins at $1$, and the variable indices are given in the order of the variables for the ring.

source

Examples

julia> R, (x, y, z) = free_associative_algebra(ZZ, ["x", "y", "z"])
+(Free associative algebra on 3 indeterminates over integers, AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}[x, y, z])
+
+julia> map(total_degree, (R(0), R(1), -x^2*y^2*z^2*x + z*y))
+(-1, 0, 7)
+
+julia> leading_term(-x^2*y^2*z^2*x + z*y)
+-x^2*y^2*z^2*x
+
+julia> leading_monomial(-x^2*y^2*z^2*x + z*y)
+x^2*y^2*z^2*x
+
+julia> leading_coefficient(-x^2*y^2*z^2*x + z*y)
+-1
+
+julia> exponent_word(-x^2*y^2*z^2*x + z*y, 1)
+7-element Vector{Int64}:
+ 1
+ 1
+ 2
+ 2
+ 3
+ 3
+ 1
AbstractAlgebra.evaluateMethod
evaluate(a::FreeAssAlgElem{T}, vals::Vector{U}) where {T <: RingElement, U <: NCRingElem}

Evaluate a by substituting in the array of values for each of the variables. The evaluation will succeed if multiplication is defined between elements of the coefficient ring of a and elements of vals.

The syntax a(vals...) is also supported.

Examples

julia> R, (x, y) = free_associative_algebra(ZZ, ["x", "y"]);
+
+julia> f = x*y - y*x
+x*y - y*x
+
+julia> S = matrix_ring(ZZ, 2);
+
+julia> m1 = S([1 2; 3 4])
+[1   2]
+[3   4]
+
+julia> m2 = S([0 1; 1 0])
+[0   1]
+[1   0]
+
+julia> evaluate(f, [m1, m2])
+[-1   -3]
+[ 3    1]
+
+julia> m1*m2 - m2*m1 == evaluate(f, [m1, m2])
+true
+
+julia> m1*m2 - m2*m1 == f(m1, m2)
+true
source

Iterators

The following iterators are provided for elements of a free associative algebra, with exponent_words providing the analogous functionality that exponent_vectors provides for multivariate polynomials.

terms(p::FreeAssAlgElem)
+coefficients(p::FreeAssAlgElem)
+monomials(p::FreeAssAlgElem)
AbstractAlgebra.exponent_wordsMethod
exponent_words(a::FreeAssAlgElem{T}) where T <: RingElement

Return an iterator for the exponent words of the given polynomial. To retrieve an array of the exponent words, use collect(exponent_words(a)).

source

Examples

julia> R, (a, b, c) = free_associative_algebra(ZZ, ["a", "b", "c"])
+(Free associative algebra on 3 indeterminates over integers, AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}[a, b, c])
+
+julia> collect(terms(3*b*a*c - b + c + 2))
+4-element Vector{Any}:
+ 3*b*a*c
+ -b
+ c
+ 2
+
+julia> collect(coefficients(3*b*a*c - b + c + 2))
+4-element Vector{Any}:
+  3
+ -1
+  1
+  2
+
+julia> collect(monomials(3*b*a*c - b + c + 2))
+4-element Vector{Any}:
+ b*a*c
+ b
+ c
+ 1
+
+julia> collect(exponent_words(3*b*a*c - b + c + 2))
+4-element Vector{Vector{Int64}}:
+ [2, 1, 3]
+ [2]
+ [3]
+ []

Groebner bases

The function groebner_basis provides the computation of a Groebner basis of an ideal, given a set of generators of that ideal. Since such a Groebner basis is not necessarily finite, one can additionally pass a reduction_bound to the function, to only compute a partial Groebner basis.

Examples

julia> R, (x, y, u, v, t, s) = free_associative_algebra(GF(2), ["x", "y", "u", "v", "t", "s"])
+(Free associative algebra on 6 indeterminates over finite field F_2, AbstractAlgebra.Generic.FreeAssAlgElem{AbstractAlgebra.GFElem{Int64}}[x, y, u, v, t, s])
+
+julia> g = Generic.groebner_basis([u*(x*y)^3 + u*(x*y)^2 + u + v, (y*x)^3*t + (y*x)^2*t + t + s])
+5-element Vector{AbstractAlgebra.Generic.FreeAssAlgElem{AbstractAlgebra.GFElem{Int64}}}:
+ u*x*y*x*y*x*y + u*x*y*x*y + u + v
+ y*x*y*x*y*x*t + y*x*y*x*t + t + s
+ u*x*s + v*x*t
+ u*x*y*x*s + v*x*y*x*t
+ u*x*y*x*y*x*s + v*x*y*x*y*x*t

In order to check whether a given element of the algebra is in the ideal generated by a Groebner basis g, one can compute its normal form. ```jldoctest; setup = :(using AbstractAlgebra) julia> R, (x, y, u, v, t, s) = freeassociativealgebra(GF(2), ["x", "y", "u", "v", "t", "s"]);

julia> g = Generic.groebner_basis([u(xy)^3 + u(xy)^2 + u + v, (yx)^3t + (yx)^2t + t + s]);

julia> normal_form(u(xy)^3st + u(xy)^2st +ust + vst, g) 0 ```

diff --git a/v0.37.6/free_module/index.html b/v0.37.6/free_module/index.html new file mode 100644 index 0000000000..1aa1b0f795 --- /dev/null +++ b/v0.37.6/free_module/index.html @@ -0,0 +1,24 @@ + +Free Modules and Vector Spaces · AbstractAlgebra.jl

Free Modules and Vector Spaces

AbstractAlgebra allows the construction of free modules of any rank over any Euclidean ring and the vector space of any dimension over a field. By default the system considers the free module of a given rank over a given ring or vector space of given dimension over a field to be unique.

Generic free module and vector space types

AbstractAlgebra provides generic types for free modules and vector spaces, via the type FreeModule{T} for free modules, where T is the type of the elements of the ring $R$ over which the module is built.

Elements of a free module have type FreeModuleElem{T}.

Vector spaces are simply free modules over a field.

The implementation of generic free modules can be found in src/generic/FreeModule.jl.

The free module of a given rank over a given ring is made unique on the system by caching them (unless an optional cache parameter is set to false).

See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).

Abstract types

The type FreeModule{T} belongs to FPModule{T} and FreeModuleElem{T} to FPModuleElem{T}. Here the FP prefix stands for finitely presented.

Functionality for free modules

As well as implementing the entire module interface, free modules provide the following functionality.

Constructors

Construct the free module/vector space of given rank/dimension.

Examples

julia> M = FreeModule(ZZ, 3)
+Free module of rank 3 over integers
+
+julia> V = VectorSpace(QQ, 2)
+Vector space of dimension 2 over rationals
+

Basic manipulation

rank(M::Generic.FreeModule{T}) where T <: RingElem
+dim(V::Generic.FreeModule{T}) where T <: FieldElem
+basis(V::Generic.FreeModule{T}) where T <: FieldElem

Examples

julia> M = FreeModule(ZZ, 3)
+Free module of rank 3 over integers
+
+julia> V = VectorSpace(QQ, 2)
+Vector space of dimension 2 over rationals
+
+julia> rank(M)
+3
+
+julia> dim(V)
+2
+
+julia> basis(V)
+2-element Vector{AbstractAlgebra.Generic.FreeModuleElem{Rational{BigInt}}}:
+ (1//1, 0//1)
+ (0//1, 1//1)
diff --git a/v0.37.6/function_field/index.html b/v0.37.6/function_field/index.html new file mode 100644 index 0000000000..abe2549b87 --- /dev/null +++ b/v0.37.6/function_field/index.html @@ -0,0 +1,223 @@ + +Rational function fields · AbstractAlgebra.jl

Rational function fields

AbstractAlgebra.jl provides a module, implemented in src/generic/RationalFunctionField.jl for rational function fields $k(x)$ or k[x_1, x_2, \ldots, x_n] over a field $k$.

Generic rational function field type

Rational functions have type Generic.RationalFunctionFieldElem{T, U} where T is the type of elements of the coefficient field $k$ and U is the type of polynomials (either univariate or multivariate) over that field. See the file src/generic/GenericTypes.jl for details.

Parent objects corresponding to the rational function field $k$ have type Generic.RationalFunctionField{T, U}.

Abstract types

The rational function types belong to the abstract type Field and the rational function field types belong to the abstract type FieldElem.

Rational function field constructors

In order to construct rational functions in AbstractAlgebra.jl, one can first construct the function field itself. This is accomplished with one of the following constructors.

rational_function_field(k::Field, s::VarName; cached::Bool = true)
+rational_function_field(k::Field, s::Vector{<:VarName}; cached::Bool = true)

Given a coefficient field k return a tuple (S, x) consisting of the parent object of the rational function field over $k$ and the generator(s) x. By default the parent object S will depend only on R and s and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

Here are some examples of creating rational function fields and making use of the resulting parent objects to coerce various elements into the function field.

Examples

julia> S, x = rational_function_field(QQ, "x")
+(Rational function field over rationals, x)
+
+julia> f = S()
+0
+
+julia> g = S(123)
+123
+
+julia> h = S(BigInt(1234))
+1234
+
+julia> k = S(x + 1)
+x + 1
+
+julia> m = S(numerator(x + 1, false), numerator(x + 2, false))
+(x + 1)//(x + 2)
+
+julia> R, (x, y) = rational_function_field(QQ, ["x", "y"])
+(Rational function field over rationals, AbstractAlgebra.Generic.RationalFunctionFieldElem{Rational{BigInt}, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}}[x, y])
+
+julia> (x + y)//y^2
+(x + y)//y^2

Basic rational function field functionality

Fraction fields in AbstractAlgebra.jl implement the full Field interface and the entire fraction field interface.

We give some examples of such functionality.

Examples

julia> S, x = rational_function_field(QQ, "x")
+(Rational function field over rationals, x)
+
+julia> f = S(x + 1)
+x + 1
+
+julia> g = (x^2 + x + 1)//(x^3 + 3x + 1)
+(x^2 + x + 1)//(x^3 + 3*x + 1)
+
+julia> h = zero(S)
+0
+
+julia> k = one(S)
+1
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> m = characteristic(S)
+0
+
+julia> U = base_ring(S)
+Rationals
+
+julia> V = base_ring(f)
+Rationals
+
+julia> T = parent(f)
+Rational function field
+  over rationals
+
+julia> r = deepcopy(f)
+x + 1
+
+julia> n = numerator(g)
+x^2 + x + 1
+
+julia> d = denominator(g)
+x^3 + 3*x + 1
+

Note that numerator and denominator are returned as elements of a polynomial ring whose variable is printed the same way as that of the generator of the rational function field.

Rational function field functionality provided by AbstractAlgebra.jl

The following functionality is provided for rational function fields.

Greatest common divisor

Base.gcdMethod
gcd(a::RationalFunctionFieldElem{T, U}, b::RationalFunctionFieldElem{T, U}) where {T <: FieldElement, U <: Union{PolyRingElem, MPolyRingElem}}

Return a greatest common divisor of $a$ and $b$ if one exists. N.B: we define the GCD of $a/b$ and $c/d$ to be gcd$(ad, bc)/bd$, reduced to lowest terms.

source

Examples

julia> R, x = rational_function_field(QQ, "x")
+(Rational function field over rationals, x)
+
+julia> f = (x + 1)//(x^3 + 3x + 1)
+(x + 1)//(x^3 + 3*x + 1)
+
+julia> g = (x^2 + 2x + 1)//(x^2 + x + 1)
+(x^2 + 2*x + 1)//(x^2 + x + 1)
+
+julia> h = gcd(f, g)
+(x + 1)//(x^5 + x^4 + 4*x^3 + 4*x^2 + 4*x + 1)
+

Square root

AbstractAlgebra.is_squareMethod
is_square(f::PolyRingElem{T}) where T <: RingElement

Return true if $f$ is a perfect square.

source
is_square(a::FracElem{T}) where T <: RingElem

Return true if $a$ is a square.

source
Base.sqrtMethod
Base.sqrt(f::PolyRingElem{T}; check::Bool=true) where T <: RingElement

Return the square root of $f$. By default the function checks the input is square and raises an exception if not. If check=false this check is omitted.

source
Base.sqrt(a::FracElem{T}; check::Bool=true) where T <: RingElem

Return the square root of $a$. By default the function will throw an exception if the input is not square. If check=false this test is omitted.

source
sqrt(a::Generic.PuiseuxSeriesElem{T}; check::Bool=true) where T <: RingElement

Return the square root of the given Puiseux series $a$. By default the function will throw an exception if the input is not square. If check=false this test is omitted.

source

Examples

julia> R, x = rational_function_field(QQ, "x")
+(Rational function field over rationals, x)
+
+julia> a = (21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)
+(21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)
+
+julia> sqrt(a^2)
+(21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)
+
+julia> is_square(a^2)
+true

Univariate function fields

Univariate function fields in AbstractAlgebra are algebraic extensions $K/k(x)$ of a rational function field $k(x)$ over a field $k$.

These are implemented in a module implemented in src/generic/FunctionField.jl.

Generic function field types

Function field objects $K/k(x)$ in AbstractAlgebra have type Generic.FunctionField{T} where T is the type of elements of the field k.

Corresponding function field elements have type Generic.FunctionFieldElement{T}. See the file src/generic/GenericTypes.jl for details.

Abstract types

Function field types belong to the abstract type Field and their elements to the abstract type FieldElem.

Function field constructors

In order to construct function fields in AbstractAlgebra.jl, one first constructs the rational function field they are an extension of, then supplies a polynomial over this field to the following constructor:

function_field(p::Poly{RationalFunctionFieldElem{T, U}}, s::AbstractString; cached::Bool=true) where {T <: FieldElement, U <: PolyRingElem{T}}

Given an irreducible polynomial p over a rational function field return a tuple (S, z) consisting of the parent object of the function field defined by that polynomial over $k(x)$ and the generator z. By default the parent object S will depend only on p and s and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

Here are some examples of creating function fields and making use of the resulting parent objects to coerce various elements into the function field.

Examples

julia> R1, x1 = rational_function_field(QQ, "x1") # characteristic 0
+(Rational function field over rationals, x1)
+
+julia> U1, z1 = R1["z1"]
+(Univariate polynomial ring in z1 over rational function field, z1)
+
+julia> f = (x1^2 + 1)//(x1 + 1)*z1^3 + 4*z1 + 1//(x1 + 1)
+(x1^2 + 1)//(x1 + 1)*z1^3 + 4*z1 + 1//(x1 + 1)
+
+julia> S1, y1 = function_field(f, "y1")
+(Function Field over Rationals with defining polynomial (x1^2 + 1)*y1^3 + (4*x1 + 4)*y1 + 1, y1)
+
+julia> a = S1()
+0
+
+julia> b = S1((x1 + 1)//(x1 + 2))
+(x1 + 1)//(x1 + 2)
+
+julia> c = S1(1//3)
+1//3
+
+julia> R2, x2 = rational_function_field(GF(23), "x1") # characteristic p
+(Rational function field over finite field F_23, x1)
+
+julia> U2, z2 = R2["z2"]
+(Univariate polynomial ring in z2 over rational function field, z2)
+
+julia> g = z2^2 + 3z2 + 1
+z2^2 + 3*z2 + 1
+
+julia> S2, y2 = function_field(g, "y2")
+(Function Field over Finite field F_23 with defining polynomial y2^2 + 3*y2 + 1, y2)
+
+julia> d = S2(R2(5))
+5
+
+julia> e = S2(y2)
+y2

Basic function field functionality

Function fields implement the full Ring and Field interfaces. We give some examples of such functionality.

Examples

julia> R, x = rational_function_field(GF(23), "x") # characteristic p
+(Rational function field over finite field F_23, x)
+
+julia> U, z = R["z"]
+(Univariate polynomial ring in z over rational function field, z)
+
+julia> g = z^2 + 3z + 1
+z^2 + 3*z + 1
+
+julia> S, y = function_field(g, "y")
+(Function Field over Finite field F_23 with defining polynomial y^2 + 3*y + 1, y)
+
+julia> f = (x + 1)*y + 1
+(x + 1)*y + 1
+
+julia> base_ring(f)
+Rational function field
+  over finite field F_23
+
+julia> f^2
+(20*x^2 + 19*x + 22)*y + 22*x^2 + 21*x
+
+julia> f*inv(f)
+1

Function field functionality provided by AbstractAlgebra.jl

The following functionality is provided for function fields.

Basic manipulation

AbstractAlgebra.varMethod
var(R::FunctionField)

Return the variable name of the generator of the function field R as a symbol.

source
Base.numeratorMethod
Base.numerator(R::FunctionField{T}, canonicalise::Bool=true) where T <: FieldElement
+Base.denominator(R::FunctionField{T}, canonicalise::Bool=true) where T <: FieldElement

Thinking of elements of the rational function field as fractions, put the defining polynomial of the function field over a common denominator and return the numerator/denominator respectively. Note that the resulting polynomials belong to a different ring than the original defining polynomial. The canonicalise is ignored, but exists for compatibility with the Generic interface.

source
Base.numeratorMethod
Base.numerator(a::FunctionFieldElem{T}, canonicalise::Bool=true) where T <: FieldElement
+Base.denominator(a::FunctionFieldElem{T}, canonicalise::Bool=true) where T <: FieldElement

Return the numerator and denominator of the function field element a. Note that elements are stored in fraction free form so that the denominator is a common denominator for the coefficients of the element a. If canonicalise is set to true the fraction is first canonicalised.

source
AbstractAlgebra.degreeMethod
degree(S::FunctionField)

Return the degree of the defining polynomial of the function field, i.e. the degree of the extension that the function field makes of the underlying rational function field.

source
AbstractAlgebra.genMethod
gen(S::FunctionField{T}) where T <: FieldElement

Return the generator of the function field returned by the function field constructor.

source
AbstractAlgebra.is_genMethod
is_gen(a::FunctionFieldElem)

Return true if a is the generator of the function field returned by the function field constructor.

source
AbstractAlgebra.coeffMethod
coeff(a::FunctionFieldElem, n::Int)

Return the degree n coefficient of the element a in its polynomial representation in terms of the generator of the function field. The coefficient is returned as an element of the underlying rational function field.

source
AbstractAlgebra.Generic.num_coeffMethod
num_coeff(a::FunctionFieldElem, n::Int)

Return the degree n coefficient of the numerator of the element a (in its polynomial representation in terms of the generator of the function field, rationalised as per numerator/denominator described above). The coefficient will be an polynomial over the base_ring of the underlying rational function field.

source

Examples

julia> R, x = rational_function_field(QQ, "x")
+(Rational function field over rationals, x)
+
+julia> U, z = R["z"]
+(Univariate polynomial ring in z over rational function field, z)
+
+julia> g = z^2 + 3*(x + 1)//(x + 2)*z + 1
+z^2 + (3*x + 3)//(x + 2)*z + 1
+
+julia> S, y = function_field(g, "y")
+(Function Field over Rationals with defining polynomial (x + 2)*y^2 + (3*x + 3)*y + x + 2, y)
+
+julia> base_field(S)
+Rational function field
+  over rationals
+
+julia> var(S)
+:y
+
+julia> characteristic(S)
+0
+
+julia> defining_polynomial(S)
+z^2 + (3*x + 3)//(x + 2)*z + 1
+
+julia> numerator(S)
+(x + 2)*y^2 + (3*x + 3)*y + x + 2
+
+julia> denominator(S)
+x + 2
+
+julia> a = (x + 1)//(x^2 + 1)*y + 3x + 2
+((x + 1)*y + 3*x^3 + 2*x^2 + 3*x + 2)//(x^2 + 1)
+
+julia> numerator(a, false)
+(x + 1)*y + 3*x^3 + 2*x^2 + 3*x + 2
+
+julia> denominator(a, false)
+x^2 + 1
+
+julia> degree(S)
+2
+
+julia> gen(S)
+y
+
+julia> is_gen(y)
+true
+
+julia> coeff(a, 1)
+(x + 1)//(x^2 + 1)
+
+julia> num_coeff(a, 1)
+x + 1

Trace and norm

LinearAlgebra.normMethod
norm(a::FunctionFieldElem)

Return the absolute norm of a as an element of the underlying rational function field.

source
julia> R, x = rational_function_field(QQ, "x")
+(Rational function field over rationals, x)
+
+julia> U, z = R["z"]
+(Univariate polynomial ring in z over rational function field, z)
+
+julia> g = z^2 + 3*(x + 1)//(x + 2)*z + 1
+z^2 + (3*x + 3)//(x + 2)*z + 1
+
+julia> S, y = function_field(g, "y")
+(Function Field over Rationals with defining polynomial (x + 2)*y^2 + (3*x + 3)*y + x + 2, y)
+
+julia> f = (-3*x - 5//3)//(x - 2)*y + (x^3 + 1//9*x^2 + 5)//(x - 2)
+((-3*x - 5//3)*y + x^3 + 1//9*x^2 + 5)//(x - 2)
+
+julia> norm(f)
+(x^7 + 20//9*x^6 + 766//81*x^5 + 2027//81*x^4 + 110//3*x^3 + 682//9*x^2 + 1060//9*x + 725//9)//(x^3 - 2*x^2 - 4*x + 8)
+
+julia> tr(f)
+(2*x^4 + 38//9*x^3 + 85//9*x^2 + 24*x + 25)//(x^2 - 4)
diff --git a/v0.37.6/functional_map/index.html b/v0.37.6/functional_map/index.html new file mode 100644 index 0000000000..9353024751 --- /dev/null +++ b/v0.37.6/functional_map/index.html @@ -0,0 +1,11 @@ + +Functional maps · AbstractAlgebra.jl

Functional maps

A functional map in AbstractAlgebra is a map which can be applied by evaluating a Julia function or closure. It is represented by a map object that contains such a function/closure, usually in a field called image_fn.

All functional maps belong to the map class FunctionalMap.

A generic concrete type Generic.FunctionalMap is provided by the Generic module to implement a generic functional map type. This allows for functional maps that contain no extra data, other than a Julia function/closure.

Custom map types can also be defined which have map class FunctionalMap.

Functional map interface

All functional map types must define their supertypes as in the following example:

mutable struct MyFunctionalMap{D, C} <: Map{D, C, FunctionalMap, MyFunctionalMap}
+   # some fields
+   image_fn::Function
+end

Of course MyFunctionalMap need not be parameterised if the types D and C of the domain and codomain objects are known.

Required functions for functional maps

The following functions must be defined for all functional map types or classes:

image_fn(M::Map(MyFunctionalMap))

Return the Julia function or closure that corresponds to application of the map $M$. This function only needs to be provided if this function is not stored in an image_fn field of the MyFunctionalMap type.

Generic functional maps

The Generic module provides a concrete type FunctionalMap which merely keeps track of a Julia function/closure implementing the map.

Such maps can be constructed using the following function:

AbstractAlgebra.map_from_funcMethod
map_from_func(image_fn::Function, domain, codomain)

Construct the generic functional map with domain and codomain given by the parent objects $R$ and $S$ corresponding to the Julia function $f$.

Examples

julia> f = map_from_func(x -> x + 1, ZZ, ZZ)
+Map defined by a Julia function
+  from integers
+  to integers
+
+julia> f(ZZ(2))
+3
source
diff --git a/v0.37.6/ideal/index.html b/v0.37.6/ideal/index.html new file mode 100644 index 0000000000..549e629e43 --- /dev/null +++ b/v0.37.6/ideal/index.html @@ -0,0 +1,75 @@ + +Ideal functionality · AbstractAlgebra.jl

Ideal functionality

AbstractAlgebra.jl provides a module, implemented in src/generic/Ideal.jl for ideals of a Euclidean domain (assuming the existence of a gcdx function) or of a univariate or multivariate polynomial ring over the integers. Univariate and multivariate polynomial rings over other domains (other than fields) are not supported at this time.

Info

A more complete implementation for ideals defined over other rings is provided by Hecke and Oscar.

Generic ideal types

AbstractAlgebra.jl provides a generic ideal type based on Julia arrays which is implemented in src/generic/Ideal.jl.

These generic ideals have type Generic.Ideal{T} where T is the type of elements of the ring the ideals belong to. Internally they consist of a Julia array of generators and some additional fields for a parent object, etc. See the file src/generic/GenericTypes.jl for details.

Parent objects of ideals have type Generic.IdealSet{T}.

Abstract types

All ideal types belong to the abstract type Ideal{T} and their parents belong to the abstract type Set. This enables one to write generic functions that can accept any AbstractAlgebra ideal type.

Note

Both the generic ideal type Generic.Ideal{T} and the abstract type it belongs to, Ideal{T}, are called Ideal. The former is a (parameterised) concrete type for an ideal in the ring whose elements have type T. The latter is an abstract type representing all ideal types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).

Ideal constructors

One may construct ideals in AbstractAlgebra.jl with the following constructor.

Generic.Ideal(R::Ring, V::Vector{T}) where T <: RingElement

Given a set of elements V in the ring R, construct the ideal of R generated by the elements V. Note that V may be arbitrary, e.g. it can contain duplicates, zero entries or be empty.

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"]; ordering=:degrevlex)
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> V = [3*x^2*y - 3*y^2, 9*x^2*y + 7*x*y]
+2-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:
+ 3*x^2*y - 3*y^2
+ 9*x^2*y + 7*x*y
+
+julia> I = Generic.Ideal(R, V)
+AbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.MPoly{BigInt}}(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[7*x*y + 9*y^2, 243*y^3 - 147*y^2, x*y^2 + 36*y^3 - 21*y^2, x^2*y + 162*y^3 - 99*y^2])
+
+julia> W = map(ZZ, [2, 5, 7])
+3-element Vector{BigInt}:
+ 2
+ 5
+ 7
+
+julia> J = Generic.Ideal(ZZ, W)
+AbstractAlgebra.Generic.Ideal{BigInt}(Integers, BigInt[1])

Ideal functions

Basic functionality

AbstractAlgebra.gensMethod
gens(I::Ideal{T}) where T <: RingElement

Return a list of generators of the ideal I in reduced form and canonicalised.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> V = [1 + 2x^2 + 3x^3, 5x^4 + 1, 2x - 1]
+3-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:
+ 3*x^3 + 2*x^2 + 1
+ 5*x^4 + 1
+ 2*x - 1
+
+julia> I = Generic.Ideal(R, V)
+AbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.Poly{BigInt}}(Univariate polynomial ring in x over integers, AbstractAlgebra.Generic.Poly{BigInt}[3, x + 1])
+
+julia> gens(I)
+2-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:
+ 3
+ x + 1

Arithmetic of Ideals

Ideals support addition, multiplication, scalar multiplication and equality testing of ideals.

Containment

Base.containsMethod
Base.contains(I::Ideal{T}, J::Ideal{T}) where T <: RingElement

Return true if the ideal J is contained in the ideal I.

source
Base.intersectMethod
intersect(I::Ideal{T}, J::Ideal{T}) where T <: RingElement

Return the intersection of the ideals I and J.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> V = [1 + 2x^2 + 3x^3, 5x^4 + 1, 2x - 1]
+3-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:
+ 3*x^3 + 2*x^2 + 1
+ 5*x^4 + 1
+ 2*x - 1
+
+julia> W = [1 + 2x^2 + 3x^3, 5x^4 + 1]
+2-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:
+ 3*x^3 + 2*x^2 + 1
+ 5*x^4 + 1
+
+julia> I = Generic.Ideal(R, V)
+AbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.Poly{BigInt}}(Univariate polynomial ring in x over integers, AbstractAlgebra.Generic.Poly{BigInt}[3, x + 1])
+
+julia> J = Generic.Ideal(R, W)
+AbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.Poly{BigInt}}(Univariate polynomial ring in x over integers, AbstractAlgebra.Generic.Poly{BigInt}[282, 3*x + 255, x^2 + 107])
+
+julia> contains(J, I)
+false
+
+julia> contains(I, J)
+true
+
+julia> intersection(I, J) == J
+true

Normal form

For ideal of polynomial rings it is possible to return the normal form of a polynomial with respect to an ideal.

AbstractAlgebra.Generic.normal_formMethod
normal_form(p::U, I::Ideal{U}) where {T <: RingElement, U <: Union{AbstractAlgebra.PolyRingElem{T}, AbstractAlgebra.MPolyRingElem{T}}}

Return the normal form of the polynomial p with respect to the ideal I.

source

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"]; ordering=:degrevlex)
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> V = [3*x^2*y - 3*y^2, 9*x^2*y + 7*x*y]
+2-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:
+ 3*x^2*y - 3*y^2
+ 9*x^2*y + 7*x*y
+
+julia> I = Generic.Ideal(R, V)
+AbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.MPoly{BigInt}}(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[7*x*y + 9*y^2, 243*y^3 - 147*y^2, x*y^2 + 36*y^3 - 21*y^2, x^2*y + 162*y^3 - 99*y^2])
+
+
+julia> normal_form(30x^5*y + 2x + 1, I)
+135*y^4 + 138*y^3 - 147*y^2 + 2*x + 1
diff --git a/v0.37.6/img/types.dia b/v0.37.6/img/types.dia new file mode 100644 index 0000000000..484b473f46 Binary files /dev/null and b/v0.37.6/img/types.dia differ diff --git a/v0.37.6/img/types.png b/v0.37.6/img/types.png new file mode 100644 index 0000000000..96eb037d5a Binary files /dev/null and b/v0.37.6/img/types.png differ diff --git a/v0.37.6/index.html b/v0.37.6/index.html new file mode 100644 index 0000000000..14f4b56fa7 --- /dev/null +++ b/v0.37.6/index.html @@ -0,0 +1,44 @@ + +AbstractAlgebra.jl · AbstractAlgebra.jl

AbstractAlgebra.jl

Introduction

AbstractAlgebra.jl is a computer algebra package for the Julia programming language, maintained by William Hart, Tommy Hofmann, Claus Fieker and Fredrik Johansson and other interested contributors.

AbstractAlgebra.jl grew out of the Nemo project after a number of requests from the community for the pure Julia part of Nemo to be split off into a separate project. See the Nemo repository for more details about Nemo.

Features

The features of AbstractAlgebra.jl include:

  • Use of Julia multiprecision integers and rationals
  • Finite fields (prime order, naive implementation only)
  • Number fields (naive implementation only)
  • Univariate polynomials
  • Multivariate polynomials
  • Relative and absolute power series
  • Laurent series
  • Fraction fields
  • Residue rings, including $\mathbb{Z}/n\mathbb{Z}$
  • Matrices and linear algebra

All implementations are fully recursive and generic, so that one can build matrices over polynomial rings, over a finite field, for example.

AbstractAlgebra.jl also provides a set of abstract types for Groups, Rings, Fields, Modules and elements thereof, which allow external types to be made part of the AbstractAlgebra.jl type hierarchy.

Installation

To use AbstractAlgebra we require Julia 1.6 or higher. Please see https://julialang.org/downloads/ for instructions on how to obtain Julia for your system.

At the Julia prompt simply type

julia> using Pkg; Pkg.add("AbstractAlgebra")

Quick start

Here are some examples of using AbstractAlgebra.jl.

This example makes use of multivariate polynomials.

using AbstractAlgebra
+
+R, (x, y, z) = polynomial_ring(ZZ, ["x", "y", "z"])
+
+f = x + y + z + 1
+
+p = f^20;
+
+@time q = p*(p+1);

Here is an example using generic recursive ring constructions.

using AbstractAlgebra
+
+R = GF(7)
+
+S, y = polynomial_ring(R, "y")
+
+T, = residue_ring(S, y^3 + 3y + 1)
+
+U, z = polynomial_ring(T, "z")
+
+f = (3y^2 + y + 2)*z^2 + (2*y^2 + 1)*z + 4y + 3;
+
+g = (7y^2 - y + 7)*z^2 + (3y^2 + 1)*z + 2y + 1;
+
+s = f^4;
+
+t = (s + g)^4;
+
+@time resultant(s, t)

Here is an example using matrices.

using AbstractAlgebra
+
+R, x = polynomial_ring(ZZ, "x")
+
+S = matrix_space(R, 10, 10)
+
+M = rand(S, 0:3, -10:10);
+
+@time det(M)

And here is an example with power series.

using AbstractAlgebra
+
+R, x = QQ["x"]
+
+S, t = power_series_ring(R, 30, "t")
+
+u = t + O(t^100)
+
+@time divexact((u*exp(x*u)), (exp(u)-1));
diff --git a/v0.37.6/integer/index.html b/v0.37.6/integer/index.html new file mode 100644 index 0000000000..5750d5b424 --- /dev/null +++ b/v0.37.6/integer/index.html @@ -0,0 +1,60 @@ + +Integer ring · AbstractAlgebra.jl

Integer ring

AbstractAlgebra.jl provides a module, implemented in src/julia/Integer.jl for making Julia BigInts conform to the AbstractAlgebra.jl Ring interface.

In addition to providing a parent object ZZ for Julia BigInts, we implement any additional functionality required by AbstractAlgebra.jl.

Because BigInt cannot be directly included in the AbstractAlgebra.jl abstract type hierarchy, we achieve integration of Julia BigInts by introducing a type union, called RingElement, which is a union of RingElem and a number of Julia types, including BigInt. Everywhere that RingElem is notionally used in AbstractAlgebra.jl, we are in fact using RingElement, with additional care being taken to avoid ambiguities.

The details of how this is done are technical, and we refer the reader to the implementation for details. For most intents and purposes, one can think of the Julia BigInt type as belonging to RingElem.

One other technicality is that Julia defines certain functions for BigInt, such as sqrt and exp differently to what AbstractAlgebra.jl requires. To get around this, we redefine these functions internally to AbstractAlgebra.jl, without redefining them for users of AbstractAlgebra.jl. This allows the internals of AbstractAlgebra.jl to function correctly, without broadcasting pirate definitions of already defined Julia functions to the world.

To access the internal definitions, one can use AbstractAlgebra.sqrt and AbstractAlgebra.exp, etc.

Types and parent objects

Integers have type BigInt, as in Julia itself. We simply supplement the functionality for this type as required for computer algebra.

The parent objects of such integers has type Integers{BigInt}.

For convenience, we also make Int a part of the AbstractAlgebra.jl type hierarchy and its parent object (accessible as zz) has type Integers{Int}. But we caution that this type is not particularly useful as a model of the integers and may not function as expected within AbstractAlgebra.jl.

Integer constructors

In order to construct integers in AbstractAlgebra.jl, one can first construct the integer ring itself. This is accomplished using the following constructor.

Integers{BigInt}()

This gives the unique object of type Integers{BigInt} representing the ring of integers in AbstractAlgebra.jl.

In practice, one simply uses ZZ which is assigned to be the return value of the above constructor. There is no need to call the constructor in practice.

Here are some examples of creating the integer ring and making use of the resulting parent object to coerce various elements into the ring.

Examples

julia> f = ZZ()
+0
+
+julia> g = ZZ(123)
+123
+
+julia> h = ZZ(BigInt(1234))
+1234
+

Basic ring functionality

The integer ring in AbstractAlgebra.jl implements the full Ring interface and the Euclidean Ring interface.

We give some examples of such functionality.

Examples

julia> f = ZZ(12)
+12
+
+julia> h = zero(ZZ)
+0
+
+julia> k = one(ZZ)
+1
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> T = parent(f)
+Integers
+
+julia> f == deepcopy(f)
+true
+
+julia> g = f + 12
+24
+
+julia> h = powermod(f, 12, ZZ(17))
+4
+
+julia> flag, q = divides(f, ZZ(3))
+(true, 4)
+

Integer functionality provided by AbstractAlgebra.jl

The functionality below supplements that provided by Julia itself for its BigInt type.

Basic functionality

Examples

julia> r = ZZ(-1)
+-1
+
+julia> is_unit(r)
+true
+

Divisibility testing

** Examples **

julia> r = ZZ(6)
+6
+
+julia> s = ZZ(3)
+3
+
+julia> is_divisible_by(r, s)
+true

Square root

AbstractAlgebra.sqrtMethod
sqrt(a::T; check::Bool=true) where T <: Integer

Return the square root of $a$. By default the function will throw an exception if the input is not square. If check=false this test is omitted.

source
AbstractAlgebra.is_squareMethod
is_square(f::PolyRingElem{T}) where T <: RingElement

Return true if $f$ is a perfect square.

source
is_square(a::ResFieldElem{T}) where T <: Integer

Return true if $a$ is a square.

source
is_square(a::T) where T <: Integer

Return true if $a$ is a square.

source
AbstractAlgebra.rootMethod
root(a::T, n::Int; check::Bool=true) where T <: Integer

Return the $n$-th root of $a$. If check=true the function will test if the input was a perfect $n$-th power, otherwise an exception will be raised. We require $n > 0$.

source
AbstractAlgebra.irootMethod
iroot(a::T, n::Int) where T <: Integer

Return the truncated integer part of the $n$-th root of $a$ (round towards zero). We require $n > 0$ and also $a \geq 0$ if $n$ is even.

source
AbstractAlgebra.Generic.is_powerMethod
is_power(a::T, n::Int) where T <: Integer

Return true, q if $a$ is a perfect $n$-th power with $a = q^n$. Otherwise return false, 0. We require $n > 0$.

source
AbstractAlgebra.expMethod
exp(a::T) where T <: Integer

Return $1$ if $a = 0$, otherwise throw an exception. This function is not generally of use to the user, but is used internally in AbstractAlgebra.jl.

source
exp(a::Rational{T}) where T <: Integer

Return $1$ if $a = 0$, otherwise throw an exception.

source

Examples

julia> d = AbstractAlgebra.sqrt(ZZ(36))
+6
+
+julia> is_square(ZZ(9))
+true
+
+julia> m = AbstractAlgebra.exp(ZZ(0))
+1

Coprime bases

AbstractAlgebra.ppioMethod
ppio(a::T, b::T)

Return a pair $(c,d)$ such that $a=c*d$ and $c = gcd(a, b^\infty)$ if $a\neq 0$, and $c=b$, $d=0$ if $a=0$.

source

Examples

julia> c, n = ppio(ZZ(12), ZZ(26))
+(4, 3)
+
diff --git a/v0.37.6/interface_introduction/index.html b/v0.37.6/interface_introduction/index.html new file mode 100644 index 0000000000..2b985f7c8b --- /dev/null +++ b/v0.37.6/interface_introduction/index.html @@ -0,0 +1,2 @@ + +Introduction · AbstractAlgebra.jl

Introduction

AbstractAlgebra defines a series of interfaces that can be extended with new types that implement those interfaces. For example, if one were implementing a new polynomial ring type, one would implement all of the required functionality described in this chapter for the relevant AbstractAlgebra interfaces. This would include the Ring Interface and the Univariate Polynomial Ring Interface.

Once a new type implements all the required functionality, all the corresponding generic functionality would then function automatically for the new type.

One may then go on to implement some of the optional functionality for performance if the provided generic functionality is insufficient.

AbstractAlgebra tries to provide all generic constructions recursively so that one can have towers of generic constructions. This means that new interfaces should generally only be added if they cooperate with all the existing interfaces, at least so far as the theory exists to do so.

diff --git a/v0.37.6/laurent_mpolynomial/index.html b/v0.37.6/laurent_mpolynomial/index.html new file mode 100644 index 0000000000..8305ebced1 --- /dev/null +++ b/v0.37.6/laurent_mpolynomial/index.html @@ -0,0 +1,27 @@ + +Sparse distributed multivariate Laurent polynomials · AbstractAlgebra.jl

Sparse distributed multivariate Laurent polynomials

Every element of the multivariate Laurent polynomial ring $R[x_1, x_1^{-1}, \dots, x_n, x_n^{-1}]$ can be presented as a sum of products of powers of the $x_i$ where the power can be any integer. Therefore, the interface for sparse multivarate polynomials carries over with the additional feature that exponents can be negative.

Generic multivariate Laurent polynomial types

AbstractAlgebra.jl provides a generic implementation of multivariate Laurent polynomials, built in terms of regular multivariate polynomials, in the file src/generic/LaurentMPoly.jl.

The type LaurentMPolyWrap{T, ...} <: LaurentMPolyRingElem{T} implements generic multivariate Laurent polynomials by wrapping regular polynomials: a Laurent polynomial l wraps a polynomial p and a vector of integers $n_i$ such that $l = \prod_i x_i^{n_i} * p$. The representation is said to be normalized when each $n_i$ is as large as possible (or zero when l is zero), but the representation of a given element is not required to be normalized internally.

The corresponding parent type is LaurentMPolyWrapRing{T, ...} <: LaurentMPolyRing{T}.

Abstract types

Two abstract types LaurentMPolyRingElem{T} and LaurentMPolyRing{T} are defined to represent Laurent polynomials and rings thereof, parameterized on a base ring T.

Multivate Laurent polynomial operations

Since, from the point of view of the interface, Laurent polynomials are simply regular polynomials with possibly negative exponents, the following functions from the polynomial interface are completely analogous. As with regular polynomials, an implementation must provide access to the elements as a sum of individual terms in some order. This order currently cannot be specified in the constructor.

laurent_polynomial_ring(R::Ring, S::Vector{<:VarName}; cached::Bool = true)
+laurent_polynomial_ring(R::Ring, n::Int, s::VarName; cached::Bool = false)
(S::LaurentMPolyRing{T})(A::Vector{T}, m::Vector{Vector{Int}})
MPolyBuildCtx(R::LaurentMPolyRing)
+push_term!(M::LaurentMPolyBuildCtx, c::RingElem, v::Vector{Int})
+finish(M::LaurentMPolyBuildCtx)
symbols(S::LaurentMPolyRing)
+number_of_variables(f::LaurentMPolyRing)
+gens(S::LaurentMPolyRing)
+gen(S::LaurentMPolyRing, i::Int)
+is_gen(x::LaurentMPolyRingElem)
+var_index(p::LaurentMPolyRingElem)
+length(f::LaurentMPolyRingElem)
coefficients(p::LaurentMPolyRingElem)
+monomials(p::LaurentMPolyRingElem)
+terms(p::LaurentMPolyRingElem)
+exponent_vectors(p::LaurentMPolyRingElem)
+leading_coefficient(p::LaurentMPolyRingElem)
+leading_monomial(p::LaurentMPolyRingElem)
+leading_term(p::LaurentMPolyRingElem)
+leading_exponent_vector(p::LaurentMPolyRingElem)
change_base_ring(::Ring, p::LaurentMPolyRingElem)
+change_coefficient_ring(::Ring, p::LaurentMPolyRingElem)
+map_coefficients(::Any, p::LaurentMPolyRingElem)
evaluate(p::LaurentMPolyRingElem, ::Vector)
derivative(p::LaurentMPolyRingElem, x::LaurentMPolyRingElem)
+derivative(p::LaurentMPolyRingElem, i::Int)
rand(R::LaurentMPolyRingElem, length_range::AbstractUnitRange{Int}, exp_range::AbstractUnitRange{Int}, v...)

The choice of canonical unit for Laurent polynomials includes the product $\prod_i x_i^{n_i}$ from the normalized representation. In particular, this means that the output of gcd will not have any negative exponents.

julia> R, (x, y) = laurent_polynomial_ring(ZZ, ["x", "y"]);
+
+julia> canonical_unit(2*x^-5 - 3*x + 4*y^-4 + 5*y^2)
+-x^-5*y^-4
+
+julia> gcd(x^-3 - y^3, x^-2 - y^2)
+x*y - 1
diff --git a/v0.37.6/laurent_polynomial/index.html b/v0.37.6/laurent_polynomial/index.html new file mode 100644 index 0000000000..1bc1432d67 --- /dev/null +++ b/v0.37.6/laurent_polynomial/index.html @@ -0,0 +1,49 @@ + +Generic Laurent polynomials · AbstractAlgebra.jl

Generic Laurent polynomials

Laurent polynomials are similar to polynomials but can have terms of negative degrees, and form a ring denoted by $R[x, x^{-1}]$ where R is the coefficient ring.

Generic Laurent polynomial types

AbstractAlgebra.jl provides a generic implementation of Laurent polynomials, built in terms of regular polynomials in the file src/generic/LaurentPoly.jl.

The type LaurentPolyWrap{T, ...} <: LaurentPolyRingElem{T} implements generic Laurent polynomials by wrapping regular polynomials: a Laurent polynomial l wraps a polynomial p and an integer n such that $l = x^{-n} * p$.

The corresponding parent type is LaurentPolyWrapRing{T, ...} <: LaurentPolyRing{T}.

Abstract types

Two abstract types LaurentPolyRingElem{T} and LaurentPolyRing{T} are defined to represent Laurent polynomials and rings thereof, parameterized on a base ring T.

Laurent polynomials ring constructor

In order to instantiate Laurent polynomials, one must first construct the parent ring:

AbstractAlgebra.laurent_polynomial_ringFunction
laurent_polynomial_ring(R::Ring, s::VarName)

Given a base ring R and string s specifying how the generator (variable) should be printed, return a tuple S, x representing the new Laurent polynomial ring $S = R[x, 1/x]$ and the generator $x$ of the ring.

Examples

julia> R, x = laurent_polynomial_ring(ZZ, "x")
+(Univariate Laurent Polynomial Ring in x over Integers, x)
+
+julia> 2x^-3 + x^2
+x^2 + 2*x^-3
+
+julia> rand(R, -3:3, -9:9)
+-3*x^2 - 8*x + 4 + 3*x^-1 - 6*x^-2 + 9*x^-3
source
laurent_polynomial_ring(R::Ring, varnames...; cached::Bool = true)

Given a base ring R and variable names varnames..., say :x, :y, :z, return a tuple S, x, y, z representing the new ring $S = R[x, 1/x, y, 1/y, z, 1/z]$ and the generators $x, y, z$ of the ring.

By default (cached=true), the output S will be cached, i.e. if laurent_polynomial_ring is invoked again with the same arguments, the same (identical) ring is returned. Setting cached to false ensures a distinct new ring is returned, and will also prevent it from being cached.

For information about the many ways to specify varnames... refer to polynomial_ring or the specification in AbstractAlgebra.@varnames_interface.

source

Basic functionality

Laurent polynomials implement the ring interface, and some methods from the polynomial interface, for example:

julia> R, x = laurent_polynomial_ring(ZZ, "x")
+(Univariate Laurent polynomial ring in x over integers, x)
+
+julia> var(R)
+:x
+
+julia> symbols(R)
+1-element Vector{Symbol}:
+ :x
+
+julia> number_of_variables(R)
+1
+
+julia> f = x^-2 + 2x
+2*x + x^-2
+
+julia> coeff.(f, -2:2)
+5-element Vector{BigInt}:
+ 1
+ 0
+ 0
+ 2
+ 0
+
+julia> set_coefficient!(f, 3, ZZ(5))
+5*x^3 + 2*x + x^-2
+
+julia> is_gen(f)
+false
+
+julia> shift_left(f,2)
+5*x^5 + 2*x^3 + 1
+
+julia> map_coefficients(x->2x, f)
+10*x^3 + 4*x + 2*x^-2
+
+julia> change_base_ring(RealField, f)
+5.0*x^3 + 2.0*x + x^-2
+
+julia> leading_coefficient(f), trailing_coefficient(f)
+(5, 1)
diff --git a/v0.37.6/linear_solving/index.html b/v0.37.6/linear_solving/index.html new file mode 100644 index 0000000000..8208dd9792 --- /dev/null +++ b/v0.37.6/linear_solving/index.html @@ -0,0 +1,15 @@ + +Linear solving · AbstractAlgebra.jl

Linear solving

Note

This functionality is experimental and subject to change.

Overview of the functionality

The module AbstractAlgebra.Solve provides the following four functions for solving linear systems:

  • solve
  • can_solve
  • can_solve_with_solution
  • can_solve_with_solution_and_kernel

All of these take the same set of arguments, namely:

  • a matrix $A$ of type MatElem{T};
  • a vector or matrix $B$ of type Vector{T} or MatElem{T};
  • a keyword argument side which can be either :left (default) or :right.

If side is :left, the system $xA = B$ is solved, otherwise the system $Ax = B$ is solved. For matrices defined over a field, the functions internally rely on rref. If the matrices are defined over a ring, the function hnf_with_transform is required internally.

The functionality of the functions can be summarized as follows.

  • solve: return a solution, if it exists, otherwise throw an error.
  • can_solve: return true, if a solution exists, false otherwise.
  • can_solve_with_solution: return true and a solution, if this exists, and false and an empty vector or matrix otherwise.
  • can_solve_with_solution_and_kernel: like can_solve_with_solution and additionally return a matrix whose columns (respectively rows) give a basis of the kernel of $A$.

Solving with several right hand sides

Systems $Ax = b_1,\dots, Ax = b_k$ with the same matrix $A$, but several right hand sides $b_i$ can be solved more efficiently, by first initializing a "context object" C of type SolveCtx.

Now the functions solve, can_solve, etc. can be used with C in place of $A$. This way the time-consuming part of the solving (i.e. computing a reduced form of $A$) is only done once and the result cached in C to be reused.

Detailed documentation

AbstractAlgebra.Solve.solveFunction
solve(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T
+solve(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T
+solve(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T
+solve(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T

Return $x$ of same type as $b$ solving the linear system $xA = b$, if side == :left (default), or $Ax = b$, if side == :right.

If no solution exists, an error is raised.

If a context object C is supplied, then the above applies for A = matrix(C).

See also can_solve_with_solution.

source
AbstractAlgebra.Solve.can_solveFunction
can_solve(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T
+can_solve(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T
+can_solve(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T
+can_solve(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T

Return true if the linear system $xA = b$ or $Ax = b$ with side == :left (default) or side == :right, respectively, has a solution and false otherwise.

If a context object C is supplied, then the above applies for A = matrix(C).

See also can_solve_with_solution.

source
AbstractAlgebra.Solve.can_solve_with_solutionFunction
can_solve_with_solution(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T
+can_solve_with_solution(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T
+can_solve_with_solution(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T
+can_solve_with_solution(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T

Return true and $x$ of same type as $b$ solving the linear system $xA = b$, if such a solution exists. Return false and an empty vector or matrix, if the system has no solution.

If side == :right, the system $Ax = b$ is solved.

If a context object C is supplied, then the above applies for A = matrix(C).

See also solve.

source
AbstractAlgebra.Solve.can_solve_with_solution_and_kernelFunction
can_solve_with_solution_and_kernel(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T
+can_solve_with_solution_and_kernel(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T
+can_solve_with_solution_and_kernel(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T
+can_solve_with_solution_and_kernel(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T

Return true, $x$ of same type as $b$ solving the linear system $xA = b$, together with a matrix $K$ giving the kernel of $A$ (i.e. $KA = 0$), if such a solution exists. Return false, an empty vector or matrix and an empty matrix, if the system has no solution.

If side == :right, the system $Ax = b$ is solved.

If a context object C is supplied, then the above applies for A = matrix(C).

See also solve and kernel.

source
AbstractAlgebra.Solve.kernelFunction
kernel([R::Ring], A::MatElem; side::Symbol = :left)
+kernel(C::SolveCtx; side::Symbol = :left)

Return a matrix $K$ whose rows give a basis for the left kernel of $A$, that is, $KA$ is the zero matrix.

If side == :right, the columns of $K$ give a basis for the right kernel of $A$, that is, $AK$ is the zero matrix.

If a ring $R$ is supplied as a first argument, the kernel is computed over $R$.

If a context object C is supplied, then the above applies for A = matrix(C).

source
diff --git a/v0.37.6/map_cache/index.html b/v0.37.6/map_cache/index.html new file mode 100644 index 0000000000..c8e9d5f714 --- /dev/null +++ b/v0.37.6/map_cache/index.html @@ -0,0 +1,30 @@ + +Cached maps · AbstractAlgebra.jl

Cached maps

All basic map (i.e. those not built up from other maps) in AbstractAlgebra can be cached.

A cache is a dictionary that can be switched on and off at run time that keeps a cache of previous evaluations of the map. This can be useful if the map is extremely difficult to evaluate, e.g. a discrete logarithm map. Rather than evaluate the map afresh each time, the map first looks up the dictionary of previous known values of the map.

To facilitate caching of maps, the Generic module provides a type Generic.MapCache, which can be used to wrap any existing map object with a dictionary.

Importantly, the supertype of the resulting Generic.MapCache object is identical to that of the map being cached. This means that any functions that would accept the original map will also accept the cached version.

Note

Caching of maps only works for maps that correctly abstract access to their fields using accessor functions, as described in the map interface.

Cached map constructors

To construct a cached map from an existing map object, we have the following function:

cached(M::Map; enabled=true, limit=100)

Return a cached map with the same supertype as $M$, caching up to limit values of the map M in a dictionary, assuming that the cache is enabled.

Caches can be disabled by setting the value of the parameter enabled to false. This allows for the user to quickly go through code and completely disable caches of maps that were previously enabled, for testing purposes, etc.

Caches can also be turned on and off at run time (see below).

Examples

julia> f = map_from_func(x -> x + 1, ZZ, ZZ)
+Map defined by a Julia function
+  from integers
+  to integers
+
+julia> g = cached(f);
+
+julia> f(ZZ(1)) == g(ZZ(1))
+true

Functionality for cached maps

The following functions are provided for cached maps.

enable_cache!(M::MapCache)
+disable_cache!(M::MapCache)

Temporarily enable or disable the cache for the given map. The values stored in the cache are not lost when it is disabled.

set_limit!(M::MapCache, limit::Int)

Set the limit on the number of values that can be cached in the dictionary, to the given value. Setting the value to 0 will effectively disable further caching for this map.

Examples

julia> f = cached(map_from_func(x -> x + 1, ZZ, ZZ));
+
+julia> a = f(ZZ(1))
+2
+
+julia> disable_cache!(f)
+
+julia> b = f(ZZ(1))
+2
+
+julia> enable_cache!(f)
+
+julia> c = f(ZZ(1))
+2
+
+julia> set_limit!(f, 200)
+200
+
+julia> d = f(ZZ(1))
+2
diff --git a/v0.37.6/map_interface/index.html b/v0.37.6/map_interface/index.html new file mode 100644 index 0000000000..d0ff1b9960 --- /dev/null +++ b/v0.37.6/map_interface/index.html @@ -0,0 +1,26 @@ + +Map Interface · AbstractAlgebra.jl

Map Interface

Maps in AbstractAlgebra can be constructed from Julia functions, or they can be represented by some other kind of data, e.g. a matrix, or built up from other maps.

In the following, we will always use the word "function" to mean a Julia function, and reserve the word "map" for a map on sets, whether mathematically, or as an object in the system.

Parent objects

Maps in AbstractAlgebra currently don't have parents. This will change later when AbstractAlgebra has a category system, so that the parent of a map can be some sort of Hom set.

Map classes

All maps in AbstractAlgebra belong to a class of maps. The classes are modeled as abstract types that lie in a hierarchy, inheriting from SetMap at the top of the hierarchy. Other classes that inherit from SetMap are FunctionalMap for maps that are constructed from a Julia function (or closure), and IdentityMap for the class of the identity maps within the system.

One might naturally assume that map types belong directly to these classes in the way that types of other objects in the system belong to abstract types in the AbstractAlgebra type hierarchy. However, in order to provide an extensible system, this is not the case.

Instead, a map type MyMap will belong to an abstract type of the form Map{D, C, T, MyMap}, where D is the type of the object representing the domain of the map type (this can also be an abstract type, such as Group), C is the type of the object representing the codomain of the map type and T is the map class that MyMap belongs to, e.g. SetMap or FunctionalMap.

Because a four parameter type system becomes quite cumbersome to use, we provide a number of functions for referring to collections of map types.

If writing a function that accepts any map type, one makes the type of its argument belong to Map. For example f(M::Map) = 1.

If writing a function that accepts any map from a domain of type D to a codomain of type C, one makes writes for example f(M::Map{D, C}) = 2. Note that D and C can be abstract types, such as Group, but otherwise must be the types of the parent objects representing the domain and codomain.

A function that accepts any map belonging to a given map class might be written as f(M::Map(FunctionalMap)) = 3 or f(M::Map(FunctionalMap){D, C}) = 4 for example, where D and C are the types of the parent objects for the domain and codomain.

Finally, if a function should only work for a map of a given map type MyMap, say, one writes this f(M::Map(MyMap)) or f(M::Map(MyMap){D, C}, where as usual D and C are the types of the domain and codomain parent objects.

Implementing new map types

There are two common kinds of map type that developers will need to write. The first has a fixed domain and codomain, and the second is a type parameterised by the types of the domain and codomain. We give two simple examples here of how this might look.

In the case of fixed domain and codomain, e.g. Integers{BigInt}, we would write it as follows:

mutable struct MyMap <: Map{Integers{BigInt}, Integers{BigInt}, SetMap, MyMap}
+   # some data fields
+end

In the case of parameterisation by the type of the domain and codomain:

mutable struct MyMap{D, C} <: Map{D, C, SetMap, MyMap}
+   # some data fields
+end

As mentioned above, to write a function that only accepts maps of type MyMap, one writes the functions as follows:

function my_fun(M::Map(MyMap))

The Map function then computes the correct type to use, which is actually not MyMap if all features of the generic Map infrastructure are required. It is bad practice to write functions for MyMap directly instead of Map(MyMap), since other users will be unable to use generic constructions over the map type MyMap.

Required functionality for maps

All map types must implement a standard interface, which we specify here.

We will define this interface for a custom map type MyMap belonging to Map(SetMap), SetMap being the map class that all maps types belong to.

Note that map types do not need to contain any specific fields, but must provide accessor functions (getters and setters) in the manner described above.

The required accessors for map types of class SetMap are as follows.

domain(M::Map(MyMap))
+codomain(M::Map(MyMap))

Return the domain and codomain parent objects respectively, for the map $M$. It is only necessary to define these functions if the map type MyMap does not contain fields domain and codomain containing these parent objects.

It is also necessary to be able to apply a map. This amounts to overloading the call method for objects belonging to Map(MyMap).

(M::Map(MyMap)(a))

Apply the map M to the element a of the domain of M. Note that it is usual to add a type assertion to the return value of this function, asserting that the return value has type elem_type(C) where C is the type of the codomain parent object.

Optional functionality for maps

The Generic module in AbstractAlgebra automatically provides certain functionality for map types, assuming that they satisfy the full interface described above.

However, certain map types or map classes might like to provide their own implementation of this functionality, overriding the generic functionality.

We describe this optional functionality here.

Show method

Custom map types may like to provide a custom show method if the default of displaying the domain and codomain of the map is not sufficient.

show(io::IO, M::Map(MyMap))

Identity maps

There is a concrete map type Generic.IdentityMap{D} for the identity map on a given domain. Here D is the type of the object representing that domain.

Generic.IdentityMap belongs to the supertype Map{D, C, AbstractAlgebra.IdentityMap, IdentityMap}.

Note that the map class is also called IdentityMap. It is an abstract type, whereas Generic.IdentityMap is a concrete type in the Generic module.

An identity map has the property that when composed with any map whose domain or codomain is compatible, that map will be returned as the composition. Identity maps can therefore serve as a starting point when building up a composition of maps, starting an identity map.

We do not cached identity maps in the system, so that if more than one is created on the same domain, there will be more than one such map in the system. This underscores the fact that there is in general no way for the system to know if two maps compose to give an identity map, and therefore the only two maps that can be composed to give an identity map are identity maps on the same domain.

To construct an identity map for a given domain, specified by a parent object R, say, we have the following function.

AbstractAlgebra.identity_mapMethod
identity_map(R::D) where D <: AbstractAlgebra.Set

Return an identity map on the domain $R$.

Examples

julia> R, t = ZZ[:t]
+(Univariate polynomial ring in t over integers, t)
+
+julia> f = identity_map(R)
+Identity map
+  of univariate polynomial ring in t over integers
+
+julia> f(t)
+t
source

Return an identity map on the domain $R$.

Of course there is nothing stopping a map type or class from implementing its own identity map type, and defining composition of maps of the same kind with such an identity map. In such a case, the class of such an identity map type must belong to IdentityMap so that composition with other map types still works.

Composition of maps

Any two compatible maps in AbstractAlgebra can be composed and any composition can be applied.

In order to facilitate this, the Generic module provides a type Generic.CompositeMap{D, C}, which contains two maps map1 and map2, corresponding to the two maps to be applied in a composition, in the order they should be applied.

To construct a composition map from two existing maps, we have the following function:

AbstractAlgebra.composeMethod
compose(f::Map, g::Map)

Compose the two maps $f$ and $g$, i.e. return the map $h$ such that $h(x) = g(f(x))$.

Examples

julia> f = map_from_func(x -> x + 1, ZZ, ZZ);
+
+julia> g = map_from_func(x -> QQ(x), ZZ, QQ);
+
+julia> h = compose(f, g)
+Functional composite map
+  from integers
+  to rationals
+which is the composite of
+  Map: integers -> integers
+  Map: integers -> rationals
source

As a shortcut for this function we have the following operator:

*(f::Map{D, U}, g::Map{U, C}) where {D, U, C} = compose(f, g)

Note the order of composition. If we have maps $f : X \to Y$, $g : Y \to Z$ the correct order of the maps in this operator is f*g, so that (f*g)(x) = g(f(x)).

This is chosen so that for left $R$-module morphisms represented by a matrix, the order of matrix multiplication will match the order of composition of the corresponding morphisms.

Of course, a custom map type or class of maps can implement its own composition type and compose function.

This is the case with the FunctionalMap class for example, which caches the Julia function/closure corresponding to the composition of two functional maps. As this cached function needs to be stored inside the composition, a special type is necessary for the composition of two functional maps.

By default, compose will check that the two maps are composable, i.e. the codomain of the first map matches the domain of the second map. This is implemented by the following function:

check_composable(f::Map{D, U}, g::Map{U, C})

Raise an exception if the codomain of $f$ doesn't match the domain of $g$.

Note that composite maps should keep track of the two maps they were constructed from. To access these maps, the following functions are provided:

map1(f::CompositeMap)
+map2(f::CompositeMap)

Any custom composite map type must also provide these functions for that map type, even if there exist fields with those names. This is because there is no common map class for all composite map types. Therefore the Generic system cannot provide fallbacks for all such composite map types.

diff --git a/v0.37.6/map_introduction/index.html b/v0.37.6/map_introduction/index.html new file mode 100644 index 0000000000..ac1509d9be --- /dev/null +++ b/v0.37.6/map_introduction/index.html @@ -0,0 +1,2 @@ + +Introduction · AbstractAlgebra.jl

Introduction

Maps in AbstractAlgebra model maps on sets $f : D \to C$ for some domain $D$ and codomain $C$, which have no real limitations except that elements of the codomain and domain be represented by element objects in the system.

Maps $f : D \to C$ in AbstractAlgebra are modeled by Julia objects that are able to be called on a single element $d \in D$ of the domain to yield an element $f(d) \in C$ of the codomain. We say that the map is being applied.

Maps can be constructed from Julia functions, or they can be represented by some other kind of data, e.g. a matrix, or built up from other maps.

Maps in AbstractAlgebra have a domain and codomain, can be applied, composed with other maps. Various special kinds of map provide more functionality.

For details please refer to the Map Interface documentation.

For example, there are functional maps which wrap a Julia function, cached maps which cache values so they do not have to be recomputed each time they are applied to the same inputs and various kinds of maps with inverses, e.g. maps with sections, retractions and full inverses.

The map system uses a complex four parameter Map type, however various helper functions are provided to make it easier to work with.

diff --git a/v0.37.6/map_with_inverse/index.html b/v0.37.6/map_with_inverse/index.html new file mode 100644 index 0000000000..0b1496fee7 --- /dev/null +++ b/v0.37.6/map_with_inverse/index.html @@ -0,0 +1,34 @@ + +Map with inverse · AbstractAlgebra.jl

Map with inverse

It is not possible to provide generic functionality to invert a map. However, sometimes one knows an inverse map explicitly and would like to keep track of this.

Recall that as map composition is not commutative, there is a notion of a left inverse and a right inverse for maps.

To keep track of such inverse maps, AbstractAlgebra provides data types Generic.MapWithRetraction and Generic.MapWithSection.

Given a map $f : X \to Y$, a retraction of $f$ is a map $g : Y \to X$ such that $g(f(x)) = x$ for all $x \in X$.

Given a map $f : X \to Y$, a section of $f$ is a map $g : Y \to X$ such that $f(g(x)) = x$ for all $y \in Y$.

In AbstractAlgebra, a map with retraction/section is an object containing a pair of maps, the second of which is a retraction/section of the first.

Maps with retraction/section can be composed, and we also define the inverse of such a pair to be the map with the pair swapped. Thus the inverse of a map with retraction is a map with section.

Map with inverse constructors

To construct a map with retraction/section from a pair of maps, we have the following functions:

map_with_retraction(m::Map{D, C}, r::Map{C, D}) where {D, C}
+map_with_section(m::Map{D, C}, s::Map{C, D}) where {D, C}

Construct the map with retraction/section given a known retraction/section $r$ or $s$ respectively, of $m$.

For convenience we allow construction of maps with retraction/section from a pair of Julia functions/closures.

map_with_retraction_from_func(f::Function, r::Function, R, S)
+map_with_section_from_func(f::Function, s::Function, R, S)

Construct the map with retraction/section such that the map is given by the function $f$ and the retraction/section is given by the function $r$ or $s$ respectively. Here $R$ is the parent object representing the domain and $S$ is the parent object representing the codomain of $f$.

Examples

julia> f = map_with_retraction_from_func(x -> x + 1, x -> x - 1, ZZ, ZZ)
+Map with retraction
+  from integers
+  to integers
+
+julia> a = f(ZZ(1))
+2

Functionality for maps with inverses

The following functionality is provided for maps with inverses.

inv(M::Generic.MapWithRetraction)
+inv(M::Generic.MapWithSection)

Return the map with the two maps contained in $M$ swapped. In the first case, a MapWithSection is returned. In the second case a MapWithRetraction is returned.

To access the two maps stored in a map with retraction/section, we have the following:

image_map(M::Generic.MapWithRetraction)
+image_map(M::Generic.MapWithSection)
+retraction_map(M::Generic.MapWithRetraction)
+section_map(M::Generic.MapWithSection)

The first two of these functions return the first map in a map with retraction/section, the second two functions return the corresponding second maps.

Examples

julia> f = map_with_retraction_from_func(x -> x + 1, x -> x - 1, ZZ, ZZ)
+Map with retraction
+  from integers
+  to integers
+
+julia> g = inv(f)
+Map with section
+  from integers
+  to integers
+
+julia> h = f*g
+Composite map
+  from integers
+  to integers
+which is the composite of
+  Map: integers -> integers
+  Map: integers -> integers
+
+julia> a = h(ZZ(1))
+1
+
diff --git a/v0.37.6/mathjaxhelper.js b/v0.37.6/mathjaxhelper.js new file mode 100644 index 0000000000..1bd5394af5 --- /dev/null +++ b/v0.37.6/mathjaxhelper.js @@ -0,0 +1,10 @@ +MathJax.Hub.Config({ + extensions: ["tex2jax.js"], + jax: ["input/TeX", "output/HTML-CSS"], + tex2jax: { + inlineMath: [ ['$','$'], ["\\(","\\)"] ], + displayMath: [ ['$$','$$'], ["\\[","\\]"] ], + processEscapes: true + }, +}); + diff --git a/v0.37.6/matrix/index.html b/v0.37.6/matrix/index.html new file mode 100644 index 0000000000..fc5dc0028f --- /dev/null +++ b/v0.37.6/matrix/index.html @@ -0,0 +1,954 @@ + +Matrix functionality · AbstractAlgebra.jl

Matrix functionality

AbstractAlgebra.jl provides a module, implemented in src/Matrix.jl for matrices over any ring belonging to the AbstractAlgebra abstract type hierarchy. This functionality will work for any matrix type which follows the Matrix interface.

Similarly, AbstractAlgebra.jl provides a module in src/MatRing.jl for matrix algebras over a ring.

Generic matrix types

AbstractAlgebra.jl allows the creation of dense matrices over any computable ring $R$. Generic matrices over a ring are implemented in src/generic/Matrix.jl.

Generic matrix rings of $m\times m$ matrices are implemented in src/generic/MatRing.jl.

Generic matrices in AbstractAlgebra.jl have type Generic.MatSpaceElem{T} for matrices in a matrix space, or Generic.MatRingElem{T} for matrices in a matrix algebra, where T is the type of elements of the matrix. Internally, generic matrices are implemented using an object wrapping a Julia two dimensional array, though they are not themselves Julia arrays. See the file src/generic/GenericTypes.jl for details.

For the most part, one doesn't want to work directly with the MatSpaceElem type though, but with an abstract type called Generic.Mat which includes MatSpaceElem and views thereof.

Parents of generic matrices (matrix spaces) have type Generic.MatSpace{T}. Parents of matrices in a matrix algebra have type Generic.MatRing{T}.

The dimensions and base ring $R$ of a generic matrix are stored in its parent object, however to allow creation of matrices without first creating the matrix space parent, generic matrices in Julia do not contain a reference to their parent. They contain the row and column numbers (or degree, in the case of matrix algebras) and the base ring on a per matrix basis. The parent object can then be reconstructed from this data on demand.

Abstract types

The generic matrix types (matrix spaces) belong to the abstract type MatElem{T} and the matrix space parent types belong to MatSpace{T}. Similarly the generic matrix algebra matrix types belong to the abstract type MatRingElem{T} and the parent types belong to MatRing{T} Note that both the concrete type of a matrix space parent object and the abstract class it belongs to have the name MatElem, therefore disambiguation is required to specify which is intended. The same is true for the abstract types for matrix spaces and their elements.

Matrix space constructors

A matrix space in AbstractAlgebra.jl represents a collection of all matrices with given dimensions and base ring.

In order to construct matrices in AbstractAlgebra.jl, one can first construct the matrix space itself. This is accomplished with the following constructor. We discuss creation of matrix algebras separately in a dedicated section elsewhere in the documentation.

matrix_space(R::Ring, rows::Int, cols::Int)

Construct the space of matrices with the given number of rows and columns over the given base ring.

Here are some examples of creating matrix spaces and making use of the resulting parent objects to coerce various elements into the matrix space.

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in t over rationals
+
+julia> A = S()
+[0   0   0]
+[0   0   0]
+[0   0   0]
+
+julia> B = S(12)
+[12    0    0]
+[ 0   12    0]
+[ 0    0   12]
+
+julia> C = S(R(11))
+[11    0    0]
+[ 0   11    0]
+[ 0    0   11]
+

Matrix element constructors

There are a few ways to construct matrices other than by coercing elements as shown above. The first method is from an array of elements.

This can be done with either two or one dimensional arrays.

(S::MatSpace{T})(A::Matrix{S}) where {S <: RingElement, T <: RingElement}
+(S::MatRing{T})(A::Matrix{S}) where {S <: RingElement, T <: RingElement}

Create the matrix in the given space/algebra whose $(i, j)$ entry is given by A[i, j], where S is the type of elements that can be coerced into the base ring of the matrix.

(S::MyMatSpace{T})(A::Vector{S}) where {S <: RingElem, T <: RingElem}
+(S::MyMatAlgebra{T})(A::Vector{S}) where {S <: RingElem, T <: RingElem}

Create the matrix in the given space/algebra of matrices (with dimensions $m\times n$ say), whose $(i, j)$ entry is given by A[i*(n - 1) + j] and where S is the type of elements that can be coerced into the base ring of the matrix.

We also provide the following syntax for constructing literal matrices (similar to how Julia arrays can be be constructed).

R[a b c...;...]

Create the matrix over the base ring $R$ consisting of the given rows (separated by semicolons). Each entry is coerced into $R$ automatically. Note that parentheses may be placed around individual entries if the lists would otherwise be ambiguous, e.g. R[1 2; 2 (- 3)].

Also see the Matrix interface for a list of other ways to create matrices.

Examples

julia> S = matrix_space(QQ, 2, 3)
+Matrix space of 2 rows and 3 columns
+  over rationals
+
+julia> T = matrix_ring(QQ, 2)
+Matrix ring of degree 2
+  over rationals
+
+julia> M1 = S(Rational{BigInt}[2 3 1; 1 0 4])
+[2//1   3//1   1//1]
+[1//1   0//1   4//1]
+
+julia> M2 = S(BigInt[2 3 1; 1 0 4])
+[2//1   3//1   1//1]
+[1//1   0//1   4//1]
+
+julia> M3 = S(BigInt[2, 3, 1, 1, 0, 4])
+[2//1   3//1   1//1]
+[1//1   0//1   4//1]
+
+julia> N1 = T(Rational{BigInt}[2 3; 1 0])
+[2//1   3//1]
+[1//1   0//1]
+
+julia> N2 = T(BigInt[2 3; 1 0])
+[2//1   3//1]
+[1//1   0//1]
+
+julia> N3 = T(BigInt[2, 3, 1, 1])
+[2//1   3//1]
+[1//1   1//1]
+
+julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in t over rationals
+
+julia> M = R[t + 1 1; t^2 0]
+[t + 1   1]
+[  t^2   0]
+
+julia> N = R[t + 1 2 t] # create a row vector
+[t + 1   2   t]
+
+julia> P = R[1; 2; t] # create a column vector
+[1]
+[2]
+[t]

It is also possible to create matrices (in a matrix space only) directly, without first creating the corresponding matrix space (the inner constructor being called directly).

matrix(R::Ring, arr::Matrix{T}) where T <: RingElement

Given an $m\times n$ Julia matrix of entries, construct the corresponding AbstractAlgebra.jl matrix over the given ring R, assuming all the entries can be coerced into R.

matrix(R::Ring, r::Int, c::Int, A::Vector{T}) where T <: RingElement

Construct the given $r\times c$ AbstractAlgebra.jl matrix over the ring R whose $(i, j)$ entry is given by A[c*(i - 1) + j], assuming that all the entries can be coerced into R.

zero_matrix(R::Ring, r::Int, c::Int)

Construct the $r\times c$ AbstractAlgebra.jl zero matrix over the ring R.

Examples

julia> M = matrix(ZZ, BigInt[3 1 2; 2 0 1])
+[3   1   2]
+[2   0   1]
+
+julia> N = matrix(ZZ, 3, 2, BigInt[3, 1, 2, 2, 0, 1])
+[3   1]
+[2   2]
+[0   1]
+
+julia> P = zero_matrix(ZZ, 3, 2)
+[0   0]
+[0   0]
+[0   0]
+
+julia> R = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> M = R()
+[0   0]
+[0   0]

Block diagonal matrix constructors

It is also possible to create block diagonal matrices from a vector of existing matrices. It is also possible to construct them from Julia matrices if one supplies the base ring.

Note that if the input matrices are not square, the output matrix may not be square.

AbstractAlgebra.block_diagonal_matrixMethod
block_diagonal_matrix(V::Vector{<:MatElem{T}}) where T <: NCRingElement

Create the block diagonal matrix whose blocks are given by the matrices in V. There must be at least one matrix in V.

source
AbstractAlgebra.block_diagonal_matrixMethod
block_diagonal_matrix(R::NCRing, V::Vector{<:Matrix{T}}) where T <: NCRingElement

Create the block diagonal matrix over the ring R whose blocks are given by the matrices in V. Entries are coerced into R upon creation.

source

Examples

julia> block_diagonal_matrix(ZZ, [[1 2; 3 4], [4 5 6; 7 8 9]])
+[1   2   0   0   0]
+[3   4   0   0   0]
+[0   0   4   5   6]
+[0   0   7   8   9]
+
+julia> M = matrix(ZZ, [1 2; 3 4])
+[1   2]
+[3   4]
+
+julia> N = matrix(ZZ, [4 5 6; 7 8 9])
+[4   5   6]
+[7   8   9]
+
+julia> block_diagonal_matrix([M, N])
+[1   2   0   0   0]
+[3   4   0   0   0]
+[0   0   4   5   6]
+[0   0   7   8   9]

Conversion to Julia matrices, iteration and broacasting

While AbstractAlgebra matrices are not instances of AbstractArray, they are closely related to Julia matrices. For convenience, a Matrix and an Array constructors taking an AbstractAlgebra matrix as input are provided:

Base.MatrixMethod
Matrix(A::MatrixElem{T}) where {T<:NCRingElement}
+Matrix{U}(A::MatrixElem{T}) where {U<:NCRingElement, T<:NCRingElement}

Convert A to a Julia Matrix{U} of the same dimensions with the same elements. If U is omitted then eltype(M) is used in its place.

Examples

julia> A = ZZ[1 2 3; 4 5 6]
+[1   2   3]
+[4   5   6]
+
+julia> Matrix(A)
+2×3 Matrix{BigInt}:
+ 1  2  3
+ 4  5  6
+
+julia> Matrix{Int}(A)
+2×3 Matrix{Int64}:
+ 1  2  3
+ 4  5  6
source
Core.ArrayMethod
Array(A::MatrixElem{T}) where T <: NCRingElement

Convert A to a Julia Matrix of the same dimensions with the same elements.

Examples

julia> R, x = ZZ["x"]; A = R[x^0 x^1; x^2 x^3]
+[  1     x]
+[x^2   x^3]
+
+julia> Array(A)
+2×2 Matrix{AbstractAlgebra.Generic.Poly{BigInt}}:
+ 1    x
+ x^2  x^3
source

Matrices also support iteration, and therefore functions accepting an iterator can be called on them, e.g.:

julia> M = matrix_space(ZZ, 2, 3); x = M(1:6)
+[1   2   3]
+[4   5   6]
+
+julia> collect(x)
+2×3 Matrix{BigInt}:
+ 1  2  3
+ 4  5  6
+
+julia> Set(x)
+Set{BigInt} with 6 elements:
+  5
+  4
+  6
+  2
+  3
+  1

Matrices also support broadcasting, which amounts to elementwise application of functions to matrices:

julia> k = GF(5);
+
+julia> A = ZZ[1 2; 3 4];
+
+julia> k.(A)
+[1   2]
+[3   4]
+
+julia> 3 .* A .+ 2
+[ 5    8]
+[11   14]
+
+julia> B = ZZ[3 4; 5 6];
+
+julia> ((x, y) -> x^2 + y^2).(A, B)
+[10   20]
+[34   52]

Views

As per Julia, AbstractAlgebra supports the construction of matrix views. These allow one to work with a submatrix of a given matrix. Modifying the submatrix also modifies the original matrix.

The syntax for views is as for Julia's own views.

Examples

julia> M = matrix(ZZ, 3, 3, BigInt[1, 2, 3, 2, 3, 4, 3, 4, 5])
+[1   2   3]
+[2   3   4]
+[3   4   5]
+
+julia> N1 = @view M[1:2, :]
+[1   2   3]
+[2   3   4]
+
+julia> N2 = @view M[:, 1:2]
+[1   2]
+[2   3]
+[3   4]
+
+julia> R = N1*N2
+[14   20]
+[20   29]

Matrix functionality provided by AbstractAlgebra.jl

Most of the following generic functionality is available for both matrix spaces and matrix algebras. Exceptions include functions that do not return or accept square matrices or which cannot specify a parent. Such functions include solve, kernel, and nullspace which can't be provided for matrix algebras.

For details on functionality that is provided for matrix algebras only, see the dedicated section of the documentation.

Basic matrix functionality

As well as the Ring and Matrix interfaces, the following functions are provided to manipulate matrices and to set and retrieve entries and other basic data associated with the matrices.

AbstractAlgebra.Generic.dense_matrix_typeMethod
dense_matrix_type(::Type{T}) where T<:NCRingElement
+dense_matrix_type(::T) where T<:NCRingElement
+dense_matrix_type(::Type{S}) where S<:NCRing
+dense_matrix_type(::S) where S<:NCRing

Return the type of matrices with coefficients of type T respectively elem_type(S).

source
Base.lengthMethod
length(a::MatrixElem{T}) where T <: NCRingElement

Return the number of entries in the given matrix.

source
Base.isemptyMethod
isempty(a::MatrixElem{T}) where T <: NCRingElement

Return true if a does not contain any entry (i.e. length(a) == 0), and false otherwise.

source
AbstractAlgebra.identity_matrixMethod
identity_matrix(M::MatElem{T}) where T <: NCRingElement

Construct the identity matrix in the same matrix space as M, i.e. with ones down the diagonal and zeroes elsewhere. M must be square. This is an alias for one(M).

source
AbstractAlgebra.scalar_matrixMethod
scalar_matrix(R::NCRing, n::Int, a::NCRingElement)
+scalar_matrix(n::Int, a::NCRingElement)

Return the $n \times n$ matrix over R with a along the main diagonal and zeroes elsewhere. If R is not specified, it defaults to parent(a).

source
AbstractAlgebra.diagonal_matrixMethod
diagonal_matrix(x::NCRingElement, m::Int, [n::Int])

Return the $m \times n$ matrix over $R$ with x along the main diagonal and zeroes elsewhere. If n is not specified, it defaults to m.

Examples

julia> diagonal_matrix(ZZ(2), 2, 3)
+[2   0   0]
+[0   2   0]
+
+julia> diagonal_matrix(QQ(-1), 3)
+[-1//1    0//1    0//1]
+[ 0//1   -1//1    0//1]
+[ 0//1    0//1   -1//1]
source
Base.zeroMethod
zero(a::MatSpace)

Return the zero matrix in the given matrix space.

source
Base.zeroMethod
zero(x::MatrixElem{T}, R::NCRing, r::Int, c::Int) where T <: NCRingElement
+zero(x::MatrixElem{T}, R::NCRing=base_ring(x)) where T <: NCRingElement
+zero(x::MatrixElem{T}, r::Int, c::Int) where T <: NCRingElement

Return a zero matrix similar to the given matrix, with optionally different base ring or dimensions.

source
Base.oneMethod
one(a::MatSpace)

Return the identity matrix of given matrix space. The matrix space must contain square matrices or else an error is thrown.

source
Base.oneMethod
one(a::MatrixElem{T}) where T <: NCRingElement

Return the identity matrix in the same matrix space as $a$. If the space does not contain square matrices, an error is thrown.

source
AbstractAlgebra.lower_triangular_matrixMethod
lower_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}

Return the $n$ by $n$ matrix whose entries on and below the main diagonal are the elements of L, and which has zeroes elsewhere. The value of $n$ is determined by the condition that L has length $n(n+1)/2$.

An exception is thrown if there is no integer $n$ with this property.

Examples

julia> lower_triangular_matrix([1, 2, 3])
+[1   0]
+[2   3]
source
AbstractAlgebra.upper_triangular_matrixMethod
upper_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}

Return the $n$ by $n$ matrix whose entries on and above the main diagonal are the elements of L, and which has zeroes elsewhere. The value of $n$ is determined by the condition that L has length $n(n+1)/2$.

An exception is thrown if there is no integer $n$ with this property.

Examples

julia> upper_triangular_matrix([1, 2, 3])
+[1   2]
+[0   3]
source
AbstractAlgebra.strictly_lower_triangular_matrixMethod
strictly_lower_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}

Return the $n$ by $n$ matrix whose entries below the main diagonal are the elements of L, and which has zeroes elsewhere. The value of $n$ is determined by the condition that L has length $(n-1)n/2$.

An exception is thrown if there is no integer $n$ with this property.

Examples

julia> strictly_lower_triangular_matrix([1, 2, 3])
+[0   0   0]
+[1   0   0]
+[2   3   0]
source
AbstractAlgebra.strictly_upper_triangular_matrixMethod
strictly_upper_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}

Return the $n$ by $n$ matrix whose entries above the main diagonal are the elements of L, and which has zeroes elsewhere. The value of $n$ is determined by the condition that L has length $(n-1)n/2$.

An exception is thrown if there is no integer $n$ with this property.

Examples

julia> strictly_upper_triangular_matrix([1, 2, 3])
+[0   1   2]
+[0   0   3]
+[0   0   0]
source
AbstractAlgebra.is_lower_triangularMethod
is_lower_triangular(A::MatrixElem)

Return true if $A$ is an lower triangular matrix, that is, all entries above the main diagonal are zero. Note that this definition also applies to non-square matrices.

Alias for LinearAlgebra.istril.

Examples

julia> is_lower_triangular(QQ[1 2 ; 0 4])
+false
+
+julia> is_lower_triangular(QQ[1 0 ; 3 4])
+true
+
+julia> is_lower_triangular(QQ[1 2 ;])
+false
+
+julia> is_lower_triangular(QQ[1 ; 2])
+true
source
AbstractAlgebra.is_upper_triangularMethod
is_upper_triangular(A::MatrixElem)

Return true if $A$ is an upper triangular matrix, that is, all entries below the main diagonal are zero. Note that this definition also applies to non-square matrices.

Alias for LinearAlgebra.istriu.

Examples

julia> is_upper_triangular(QQ[1 2 ; 0 4])
+true
+
+julia> is_upper_triangular(QQ[1 0 ; 3 4])
+false
+
+julia> is_upper_triangular(QQ[1 2 ;])
+true
+
+julia> is_upper_triangular(QQ[1 ; 2])
+false
source
AbstractAlgebra.is_diagonalMethod
is_diagonal(A::MatrixElem)

Return true if $A$ is a diagonal matrix, that is, all entries off the main diagonal are zero. Note that this definition also applies to non-square matrices.

Alias for LinearAlgebra.isdiag.

Examples

julia> is_diagonal(QQ[1 0 ; 0 4])
+true
+
+julia> is_diagonal(QQ[1 2 ; 3 4])
+false
+
+julia> is_diagonal(QQ[1 0 ;])
+true
source
Base.mapMethod
map(f, a::MatrixElem{T}) where T <: NCRingElement

Transform matrix a by applying f on each element. This is equivalent to map_entries(f, a).

source
Base.map!Method
map!(f, dst::MatrixElem{T}, src::MatrixElem{U}) where {T <: NCRingElement, U <: NCRingElement}

Like map, but stores the result in dst rather than a new matrix. This is equivalent to map_entries!(f, dst, src).

source

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in t over rationals
+
+julia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])
+[t + 1       t             1]
+[  t^2       t             t]
+[   -2   t + 2   t^2 + t + 1]
+
+julia> B = S([R(2) R(3) R(1); t t + 1 t + 2; R(-1) t^2 t^3])
+[ 2       3       1]
+[ t   t + 1   t + 2]
+[-1     t^2     t^3]
+
+julia> T = dense_matrix_type(R)
+AbstractAlgebra.Generic.MatSpaceElem{AbstractAlgebra.Generic.Poly{Rational{BigInt}}}
+
+julia> r = number_of_rows(B)
+3
+
+julia> c = number_of_columns(B)
+3
+
+julia> length(B)
+9
+
+julia> isempty(B)
+false
+
+julia> M = A + B
+[  t + 3         t + 3                   2]
+[t^2 + t       2*t + 1             2*t + 2]
+[     -3   t^2 + t + 2   t^3 + t^2 + t + 1]
+
+julia> N = 2 + A
+[t + 3       t             1]
+[  t^2   t + 2             t]
+[   -2   t + 2   t^2 + t + 3]
+
+julia> M1 = deepcopy(A)
+[t + 1       t             1]
+[  t^2       t             t]
+[   -2   t + 2   t^2 + t + 1]
+
+julia> A != B
+true
+
+julia> isone(one(S))
+true
+
+julia> V = A[1:2, :]
+[t + 1   t   1]
+[  t^2   t   t]
+
+julia> W = A^3
+[    3*t^4 + 4*t^3 + t^2 - 3*t - 5            t^4 + 5*t^3 + 10*t^2 + 7*t + 4                 2*t^4 + 7*t^3 + 9*t^2 + 8*t + 1]
+[t^5 + 4*t^4 + 3*t^3 - 7*t^2 - 4*t               4*t^4 + 8*t^3 + 7*t^2 + 2*t                 t^5 + 5*t^4 + 9*t^3 + 7*t^2 - t]
+[  t^5 + 3*t^4 - 10*t^2 - 16*t - 2   t^5 + 6*t^4 + 12*t^3 + 11*t^2 + 5*t - 2   t^6 + 3*t^5 + 8*t^4 + 15*t^3 + 10*t^2 + t - 5]
+
+julia> Z = divexact(2*A, 2)
+[t + 1       t             1]
+[  t^2       t             t]
+[   -2   t + 2   t^2 + t + 1]
+
+julia> M = matrix(ZZ, BigInt[2 3 0; 1 1 1])
+[2   3   0]
+[1   1   1]
+
+julia> M[1, 2] = BigInt(4)
+4
+
+julia> c = M[1, 1]
+2
+

Transpose

Base.transposeMethod
transpose(x::MatrixElem{T}) where T <: NCRingElement

Return the transpose of the given matrix.

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in t over rationals
+
+julia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])
+[t + 1       t             1]
+[  t^2       t             t]
+[   -2   t + 2   t^2 + t + 1]
+
+julia> B = transpose(A)
+[t + 1   t^2            -2]
+[    t     t         t + 2]
+[    1     t   t^2 + t + 1]
+
source

Submatrices

Submatrices are only available for matrix spaces, not for matrix algebras and generally only available for generic matrices built on Julia arrays.

Submatrices return a new matrix with the same entries as the submatrix with the given range of rows and columns. They are best illustrated with examples.

Examples

julia> M = matrix(ZZ, BigInt[1 2 3; 2 3 4; 3 4 5])
+[1   2   3]
+[2   3   4]
+[3   4   5]
+
+julia> N1 = M[1:2, :]
+[1   2   3]
+[2   3   4]
+
+julia> N2 = M[:, :]
+[1   2   3]
+[2   3   4]
+[3   4   5]
+
+julia> N3 = M[2:3, 2:3]
+[3   4]
+[4   5]
+

Elementary row and column operations

AbstractAlgebra.add_columnMethod
add_column(a::MatrixElem{T}, s::RingElement, i::Int, j::Int, rows = 1:nrows(a)) where T <: RingElement

Create a copy of $a$ and add $s$ times the $i$-th row to the $j$-th row of $a$.

By default, the transformation is applied to all rows of $a$. This can be changed using the optional rows argument.

source
AbstractAlgebra.add_column!Method
add_column!(a::MatrixElem{T}, s::RingElement, i::Int, j::Int, rows = 1:nrows(a)) where T <: RingElement

Add $s$ times the $i$-th row to the $j$-th row of $a$.

By default, the transformation is applied to all rows of $a$. This can be changed using the optional rows argument.

source
AbstractAlgebra.add_rowMethod
add_row(a::MatrixElem{T}, s::RingElement, i::Int, j::Int, cols = 1:ncols(a)) where T <: RingElement

Create a copy of $a$ and add $s$ times the $i$-th row to the $j$-th row of $a$.

By default, the transformation is applied to all columns of $a$. This can be changed using the optional cols argument.

source
AbstractAlgebra.add_row!Method
add_row!(a::MatrixElem{T}, s::RingElement, i::Int, j::Int, cols = 1:ncols(a)) where T <: RingElement

Add $s$ times the $i$-th row to the $j$-th row of $a$.

By default, the transformation is applied to all columns of $a$. This can be changed using the optional cols argument.

source
AbstractAlgebra.multiply_columnMethod
multiply_column(a::MatrixElem{T}, s::RingElement, i::Int, rows = 1:nrows(a)) where T <: RingElement

Create a copy of $a$ and multiply the $i$th column of $a$ with $s$.

By default, the transformation is applied to all rows of $a$. This can be changed using the optional rows argument.

source
AbstractAlgebra.multiply_column!Method
multiply_column!(a::MatrixElem{T}, s::RingElement, i::Int, rows = 1:nrows(a)) where T <: RingElement

Multiply the $i$th column of $a$ with $s$.

By default, the transformation is applied to all rows of $a$. This can be changed using the optional rows argument.

source
AbstractAlgebra.multiply_rowMethod
multiply_row(a::MatrixElem{T}, s::RingElement, i::Int, cols = 1:ncols(a)) where T <: RingElement

Create a copy of $a$ and multiply the $i$th row of $a$ with $s$.

By default, the transformation is applied to all columns of $a$. This can be changed using the optional cols argument.

source
AbstractAlgebra.multiply_row!Method
multiply_row!(a::MatrixElem{T}, s::RingElement, i::Int, cols = 1:ncols(a)) where T <: RingElement

Multiply the $i$th row of $a$ with $s$.

By default, the transformation is applied to all columns of $a$. This can be changed using the optional cols argument.

source

Examples

julia> M = ZZ[1 2 3; 2 3 4; 4 5 5]
+[1   2   3]
+[2   3   4]
+[4   5   5]
+
+julia> add_column(M, 2, 3, 1)
+[ 7   2   3]
+[10   3   4]
+[14   5   5]
+
+julia> add_row(M, 1, 2, 3)
+[1   2   3]
+[2   3   4]
+[6   8   9]
+
+julia> multiply_column(M, 2, 3)
+[1   2    6]
+[2   3    8]
+[4   5   10]
+
+julia> multiply_row(M, 2, 3)
+[1    2    3]
+[2    3    4]
+[8   10   10]

Swapping rows and columns

AbstractAlgebra.swap_rowsMethod
swap_rows(a::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement

Return a matrix $b$ with the entries of $a$, where the $i$th and $j$th row are swapped.

Examples

julia> M = identity_matrix(ZZ, 3)
+[1   0   0]
+[0   1   0]
+[0   0   1]
+
+julia> swap_rows(M, 1, 2)
+[0   1   0]
+[1   0   0]
+[0   0   1]
+
+julia> M  # was not modified
+[1   0   0]
+[0   1   0]
+[0   0   1]
source
AbstractAlgebra.swap_rows!Method
swap_rows!(a::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement

Swap the $i$th and $j$th row of $a$ in place. The function returns the mutated matrix (since matrices are assumed to be mutable in AbstractAlgebra.jl).

Examples

julia> M = identity_matrix(ZZ, 3)
+[1   0   0]
+[0   1   0]
+[0   0   1]
+
+julia> swap_rows!(M, 1, 2)
+[0   1   0]
+[1   0   0]
+[0   0   1]
+
+julia> M  # was modified
+[0   1   0]
+[1   0   0]
+[0   0   1]
source
AbstractAlgebra.swap_colsMethod
swap_cols(a::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement

Return a matrix $b$ with the entries of $a$, where the $i$th and $j$th row are swapped.

source
AbstractAlgebra.swap_cols!Method
swap_cols!(a::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement

Swap the $i$th and $j$th column of $a$ in place. The function returns the mutated matrix (since matrices are assumed to be mutable in AbstractAlgebra.jl).

source

Swap the rows of M in place. The function returns the mutated matrix (since matrices are assumed to be mutable in AbstractAlgebra.jl).

Concatenation

The following are only available for matrix spaces, not for matrix algebras.

hcat(M::T, N::T) where T <: MatElem

Return the horizontal concatenation of $M$ and $N$. It is assumed that the number of rows of $M$ and $N$ are the same.

vcat(M::T, N::T) where T <: MatElem

Return the vertical concatenation of $M$ and $N$. It is assumed that the number of columns of $M$ and $N$ are the same.

Examples

julia> M = matrix(ZZ, BigInt[1 2 3; 2 3 4; 3 4 5])
+[1   2   3]
+[2   3   4]
+[3   4   5]
+
+julia> N = matrix(ZZ, BigInt[1 0 1; 0 1 0; 1 0 1])
+[1   0   1]
+[0   1   0]
+[1   0   1]
+
+julia> P = hcat(M, N)
+[1   2   3   1   0   1]
+[2   3   4   0   1   0]
+[3   4   5   1   0   1]
+
+julia> Q = vcat(M, N)
+[1   2   3]
+[2   3   4]
+[3   4   5]
+[1   0   1]
+[0   1   0]
+[1   0   1]
+

Similar and zero

Both similar and zero construct new matrices, but the entries are either undefined with similar or zero-initialized with zero.

similar(x::MatElem, R::Ring=base_ring(x))
+zero(x::MatElem, R::Ring=base_ring(x))

Construct the matrix with the same dimensions as the given matrix, and the same base ring unless explicitly specified.

similar(x::MatElem, R::Ring, r::Int, c::Int)
+similar(x::MatElem, r::Int, c::Int)
+zero(x::MatElem, R::Ring, r::Int, c::Int)
+zero(x::MatElem, r::Int, c::Int)

Construct the $r\times c$ matrix with R as base ring (which defaults to the base ring of the the given matrix). If $x$ belongs to a matrix algebra and $r \neq c$, an exception is raised, and it's also possible to specify only one Int as the order (e.g. similar(x, n)).

Base.isassigned(M::MatElem, i, j)

Test whether the given matrix has a value associated with indices i and j.

Examples

julia> M = matrix(ZZ, BigInt[3 1 2; 2 0 1])
+[3   1   2]
+[2   0   1]
+
+julia> isassigned(M, 1, 2)
+true
+
+julia> isassigned(M, 4, 4)
+false
+
+julia> A = similar(M)
+[#undef   #undef   #undef]
+[#undef   #undef   #undef]
+
+julia> isassigned(A, 1, 2)
+false
+
+julia> B = zero(M)
+[0   0   0]
+[0   0   0]
+
+julia> C = similar(M, 4, 5)
+[#undef   #undef   #undef   #undef   #undef]
+[#undef   #undef   #undef   #undef   #undef]
+[#undef   #undef   #undef   #undef   #undef]
+[#undef   #undef   #undef   #undef   #undef]
+
+julia> base_ring(B)
+Integers
+
+julia> D = zero(M, QQ, 2, 2)
+[0//1   0//1]
+[0//1   0//1]
+
+julia> base_ring(D)
+Rationals

Symmetry testing

AbstractAlgebra.is_symmetricMethod
is_symmetric(M::MatrixElem)

Return true if the given matrix is symmetric with respect to its main diagonal, i.e., transpose(M) == M, otherwise return false.

Alias for LinearAlgebra.issymmetric.

Examples

julia> M = matrix(ZZ, [1 2 3; 2 4 5; 3 5 6])
+[1   2   3]
+[2   4   5]
+[3   5   6]
+
+julia> is_symmetric(M)
+true
+
+julia> N = matrix(ZZ, [1 2 3; 4 5 6; 7 8 9])
+[1   2   3]
+[4   5   6]
+[7   8   9]
+
+julia> is_symmetric(N)
+false
source
AbstractAlgebra.is_skew_symmetricMethod
is_skew_symmetric(M::MatrixElem)

Return true if the given matrix is skew symmetric with respect to its main diagonal, i.e., transpose(M) == -M, otherwise return false.

Examples

julia> M = matrix(ZZ, [0 -1 -2; 1 0 -3; 2 3 0])
+[0   -1   -2]
+[1    0   -3]
+[2    3    0]
+
+julia> is_skew_symmetric(M)
+true
+
source

Powering

AbstractAlgebra.powersMethod
powers(a::Union{NCRingElement, MatElem}, d::Int)

Return an array $M$ of "powers" of a where $M[i + 1] = a^i$ for $i = 0..d$.

Examples

julia> M = ZZ[1 2 3; 2 3 4; 4 5 5]
+[1   2   3]
+[2   3   4]
+[4   5   5]
+
+julia> A = powers(M, 4)
+5-element Vector{AbstractAlgebra.Generic.MatSpaceElem{BigInt}}:
+ [1 0 0; 0 1 0; 0 0 1]
+ [1 2 3; 2 3 4; 4 5 5]
+ [17 23 26; 24 33 38; 34 48 57]
+ [167 233 273; 242 337 394; 358 497 579]
+ [1725 2398 2798; 2492 3465 4044; 3668 5102 5957]
+
source

Gram matrix

AbstractAlgebra.gramMethod
gram(x::MatElem)

Return the Gram matrix of $x$, i.e. if $x$ is an $r\times c$ matrix return the $r\times r$ matrix whose entries $i, j$ are the dot products of the $i$-th and $j$-th rows, respectively.

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in t over rationals
+
+julia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])
+[t + 1       t             1]
+[  t^2       t             t]
+[   -2   t + 2   t^2 + t + 1]
+
+julia> B = gram(A)
+[2*t^2 + 2*t + 2   t^3 + 2*t^2 + t                   2*t^2 + t - 1]
+[t^3 + 2*t^2 + t       t^4 + 2*t^2                       t^3 + 3*t]
+[  2*t^2 + t - 1         t^3 + 3*t   t^4 + 2*t^3 + 4*t^2 + 6*t + 9]
+
source

Trace

LinearAlgebra.trMethod
tr(x::MatrixElem{T}) where T <: NCRingElement

Return the trace of the matrix $a$, i.e. the sum of the diagonal elements. We require the matrix to be square.

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in t over rationals
+
+julia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])
+[t + 1       t             1]
+[  t^2       t             t]
+[   -2   t + 2   t^2 + t + 1]
+
+julia> b = tr(A)
+t^2 + 3*t + 2
+
source

Content

AbstractAlgebra.contentMethod
content(x::MatrixElem{T}) where T <: RingElement

Return the content of the matrix $a$, i.e. the greatest common divisor of all its entries, assuming it exists.

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in t over rationals
+
+julia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])
+[t + 1       t             1]
+[  t^2       t             t]
+[   -2   t + 2   t^2 + t + 1]
+
+julia> b = content(A)
+1
+
source

Permutation

Base.:*Method
*(P::perm, x::MatrixElem{T}) where T <: NCRingElement

Apply the pemutation $P$ to the rows of the matrix $x$ and return the result.

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in t over rationals
+
+julia> G = SymmetricGroup(3)
+Full symmetric group over 3 elements
+
+julia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])
+[t + 1       t             1]
+[  t^2       t             t]
+[   -2   t + 2   t^2 + t + 1]
+
+julia> P = G([1, 3, 2])
+(2,3)
+
+julia> B = P*A
+[t + 1       t             1]
+[   -2   t + 2   t^2 + t + 1]
+[  t^2       t             t]
+
source

LU factorisation

LinearAlgebra.luMethod
lu(A::MatrixElem{T}, P = SymmetricGroup(nrows(A))) where {T <: FieldElement}

Return a tuple $r, p, L, U$ consisting of the rank of $A$, a permutation $p$ of $A$ belonging to $P$, a lower triangular matrix $L$ and an upper triangular matrix $U$ such that $p(A) = LU$, where $p(A)$ stands for the matrix whose rows are the given permutation $p$ of the rows of $A$.

source
AbstractAlgebra.ffluMethod
fflu(A::MatrixElem{T}, P = SymmetricGroup(nrows(A))) where {T <: RingElement}

Return a tuple $r, d, p, L, U$ consisting of the rank of $A$, a denominator $d$, a permutation $p$ of $A$ belonging to $P$, a lower triangular matrix $L$ and an upper triangular matrix $U$ such that $p(A) = LDU$, where $p(A)$ stands for the matrix whose rows are the given permutation $p$ of the rows of $A$ and such that $D$ is the diagonal matrix diag$(p_1, p_1p_2, \ldots, p_{n-2}p_{n-1}, p_{n-1}p_n)$ where the $p_i$ are the inverses of the diagonal entries of $L$. The denominator $d$ is set to $\pm \mathrm{det}(S)$ where $S$ is an appropriate submatrix of $A$ ($S = A$ if $A$ is square and nonsingular) and the sign is decided by the parity of the permutation.

source

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> K, = residue_field(R, x^3 + 3x + 1); a = K(x);
+
+julia> S = matrix_space(K, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over residue field of univariate polynomial ring modulo x^3 + 3*x + 1
+
+julia> A = S([K(0) 2a + 3 a^2 + 1; a^2 - 2 a - 1 2a; a^2 - 2 a - 1 2a])
+[      0   2*x + 3   x^2 + 1]
+[x^2 - 2     x - 1       2*x]
+[x^2 - 2     x - 1       2*x]
+
+julia> r, P, L, U = lu(A)
+(2, (1,2), [1 0 0; 0 1 0; 1 0 1], [x^2-2 x-1 2*x; 0 2*x+3 x^2+1; 0 0 0])
+
+julia> r, d, P, L, U = fflu(A)
+(2, 3*x^2 - 10*x - 8, (1,2), [x^2-2 0 0; 0 3*x^2-10*x-8 0; x^2-2 0 1], [x^2-2 x-1 2*x; 0 3*x^2-10*x-8 -4*x^2-x-2; 0 0 0])
+

Reduced row-echelon form

AbstractAlgebra.rref_rationalMethod
rref_rational(M::MatrixElem{T}) where {T <: RingElement}

Return a tuple $(r, A, d)$ consisting of the rank $r$ of $M$ and a denominator $d$ in the base ring of $M$ and a matrix $A$ such that $A/d$ is the reduced row echelon form of $M$. Note that the denominator is not usually minimal.

source
AbstractAlgebra.rrefMethod
rref(M::MatrixElem{T}) where {T <: FieldElement}

Return a tuple $(r, A)$ consisting of the rank $r$ of $M$ and a reduced row echelon form $A$ of $M$.

source
AbstractAlgebra.is_rrefMethod
is_rref(M::MatrixElem{T}) where {T <: RingElement}

Return true if $M$ is in reduced row echelon form, otherwise return false.

source
AbstractAlgebra.is_rrefMethod
is_rref(M::MatrixElem{T}) where {T <: RingElement}

Return true if $M$ is in reduced row echelon form, otherwise return false.

source
is_rref(M::MatrixElem{T}) where {T <: FieldElement}

Return true if $M$ is in reduced row echelon form, otherwise return false.

source

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> K, = residue_field(R, x^3 + 3x + 1); a = K(x);
+
+julia> S = matrix_space(K, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over residue field of univariate polynomial ring modulo x^3 + 3*x + 1
+
+julia> M = S([K(0) 2a + 3 a^2 + 1; a^2 - 2 a - 1 2a; a^2 + 3a + 1 2a K(1)])
+[            0   2*x + 3   x^2 + 1]
+[      x^2 - 2     x - 1       2*x]
+[x^2 + 3*x + 1       2*x         1]
+
+julia> r, A = rref(M)
+(3, [1 0 0; 0 1 0; 0 0 1])
+
+julia> is_rref(A)
+true
+
+julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in x over integers
+
+julia> M = S([R(0) 2x + 3 x^2 + 1; x^2 - 2 x - 1 2x; x^2 + 3x + 1 2x R(1)])
+[            0   2*x + 3   x^2 + 1]
+[      x^2 - 2     x - 1       2*x]
+[x^2 + 3*x + 1       2*x         1]
+
+julia> r, A, d = rref_rational(M)
+(3, [-x^5-2*x^4-15*x^3-18*x^2-8*x-7 0 0; 0 -x^5-2*x^4-15*x^3-18*x^2-8*x-7 0; 0 0 -x^5-2*x^4-15*x^3-18*x^2-8*x-7], -x^5 - 2*x^4 - 15*x^3 - 18*x^2 - 8*x - 7)
+
+julia> is_rref(A)
+true

Determinant

LinearAlgebra.detMethod
det(M::MatrixElem{T}) where {T <: RingElement}

Return the determinant of the matrix $M$. We assume $M$ is square.

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> A = R[x 1; 1 x^2];
+
+julia> d = det(A)
+x^3 - 1
source

Rank

LinearAlgebra.rankMethod
rank(M::MatrixElem{T}) where {T <: RingElement}

Return the rank of the matrix $M$.

Examples

julia> A = QQ[1 2; 3 4];
+
+julia> d = rank(A)
+2
source

Minors

AbstractAlgebra.minorsMethod
minors(A::MatElem, k::Int)

Return an array consisting of the k-minors of A.

Examples

julia> A = ZZ[1 2 3; 4 5 6]
+[1   2   3]
+[4   5   6]
+
+julia> minors(A, 2)
+3-element Vector{BigInt}:
+ -3
+ -6
+ -3
+
source

Exterior power

AbstractAlgebra.exterior_powerMethod
exterior_power(A::MatElem, k::Int) -> MatElem

Return the k-th exterior power of A.

Examples

julia> A = matrix(ZZ, 3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
+
+julia> exterior_power(A, 2)
+[-3    -6   -3]
+[-6   -12   -6]
+[-3    -6   -3]
source

Pfaffian

Examples

julia> R, x = polynomial_ring(QQ, ["x$i" for i in 1:6])
+(Multivariate polynomial ring in 6 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x1, x2, x3, x4, x5, x6])
+
+julia> M = R[0 x[1] x[2] x[3]; -x[1] 0 x[4] x[5]; -x[2] -x[4] 0 x[6]; -x[3] -x[5] -x[6] 0]
+[  0    x1    x2   x3]
+[-x1     0    x4   x5]
+[-x2   -x4     0   x6]
+[-x3   -x5   -x6    0]
+
+julia> pfaffian(M)
+x1*x6 - x2*x5 + x3*x4
+
+julia> pfaffians(M, 2)
+6-element Vector{AbstractAlgebra.Generic.MPoly{Rational{BigInt}}}:
+ x1
+ x2
+ x4
+ x3
+ x5
+ x6
+ 

Linear solving

AbstractAlgebra.solveMethod
solve(a::MatElem{S}, b::MatElem{S}) where {S <: RingElement}

Given an $m\times r$ matrix $a$ over a ring and an $m\times n$ matrix $b$ over the same ring, return an $r\times n$ matrix $x$ such that $ax = b$. If no such matrix exists, an exception is raised. See also solve_left.

source
AbstractAlgebra.solve_rationalMethod
solve_rational(M::MatElem{T}, b::MatElem{T}) where T <: RingElement

Given a non-singular $n\times n$ matrix over a ring and an $n\times m$ matrix over the same ring, return a tuple $x, d$ consisting of an $n\times m$ matrix $x$ and a denominator $d$ such that $Ax = db$. The denominator will be the determinant of $A$ up to sign. If $A$ is singular an exception is raised.

source
AbstractAlgebra.can_solve_with_solutionMethod
can_solve_with_solution(a::MatElem{S}, b::MatElem{S}; side::Symbol = :right) where S <: RingElement

Given two matrices $a$ and $b$ over the same ring, try to solve $ax = b$ if side is :right or $xa = b$ if side is :left. In either case, return a tuple (flag, x). If a solution exists, flag is set to true and x is a solution. If no solution exists, flag is set to false and x is arbitrary. If the dimensions of $a$ and $b$ are incompatible, an exception is raised.

source
AbstractAlgebra.can_solveMethod
can_solve(a::MatElem{S}, b::MatElem{S}; side::Symbol = :right) where S <: RingElement

Given two matrices $a$ and $b$ over the same ring, check the solubility of $ax = b$ if side is :right or $xa = b$ if side is :left. Return true if a solution exists, false otherwise. If the dimensions of $a$ and $b$ are incompatible, an exception is raised. If a solution should be computed as well, use can_solve_with_solution instead.

source
AbstractAlgebra.solve_leftMethod
solve_left(a::MatElem{S}, b::MatElem{S}) where S <: RingElement

Given an $r\times n$ matrix $a$ over a ring and an $m\times n$ matrix $b$ over the same ring, return an $m\times r$ matrix $x$ such that $xa = b$. If no such matrix exists, an exception is raised. See also solve.

source
AbstractAlgebra.solve_triuMethod
solve_triu(U::MatElem{T}, b::MatElem{T}, unit::Bool = false) where {T <: FieldElement}

Given a non-singular $n\times n$ matrix $U$ over a field which is upper triangular, and an $n\times m$ matrix $b$ over the same field, return an $n\times m$ matrix $x$ such that $Ux = b$. If $U$ is singular an exception is raised. If unit is true then $U$ is assumed to have ones on its diagonal, and the diagonal will not be read.

source
AbstractAlgebra.can_solve_left_reduced_triuMethod
can_solve_left_reduced_triu(r::MatElem{T},
+                      M::MatElem{T}) where T <: RingElement

Return a tuple flag, x where flag is set to true if $xM = r$ has a solution, where $M$ is an $m\times n$ matrix in (upper triangular) Hermite normal form or reduced row echelon form and $r$ and $x$ are row vectors with $m$ columns (i.e. $1 \times m$ matrices). If there is no solution, flag is set to false and $x$ is set to zero.

source

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> K, = residue_field(R, x^3 + 3x + 1); a = K(x);
+
+julia> S = matrix_space(K, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over residue field of univariate polynomial ring modulo x^3 + 3*x + 1
+
+julia> U = matrix_space(K, 3, 1)
+Matrix space of 3 rows and 1 column
+  over residue field of univariate polynomial ring modulo x^3 + 3*x + 1
+
+julia> A = S([K(0) 2a + 3 a^2 + 1; a^2 - 2 a - 1 2a; a^2 + 3a + 1 2a K(1)])
+[            0   2*x + 3   x^2 + 1]
+[      x^2 - 2     x - 1       2*x]
+[x^2 + 3*x + 1       2*x         1]
+
+julia> b = U([2a, a + 1, (-a - 1)])
+[   2*x]
+[ x + 1]
+[-x - 1]
+
+julia> x = solve(A, b)
+[  1984//7817*x^2 + 1573//7817*x - 937//7817]
+[ -2085//7817*x^2 + 1692//7817*x + 965//7817]
+[-3198//7817*x^2 + 3540//7817*x - 3525//7817]
+
+julia> A = matrix(ZZ, 2, 2, [1, 2, 0, 2])
+[1   2]
+[0   2]
+
+julia> b = matrix(ZZ, 2, 1, [2, 1])
+[2]
+[1]
+
+julia> can_solve(A, b, side = :right)
+false
+
+julia> A = matrix(QQ, 2, 2, [3, 4, 5, 6])
+[3//1   4//1]
+[5//1   6//1]
+
+julia> b = matrix(QQ, 1, 2, [2, 1])
+[2//1   1//1]
+
+julia> can_solve_with_solution(A, b; side = :left)
+(true, [-7//2 5//2])
+
+julia> A = S([a + 1 2a + 3 a^2 + 1; K(0) a^2 - 1 2a; K(0) K(0) a])
+[x + 1   2*x + 3   x^2 + 1]
+[    0   x^2 - 1       2*x]
+[    0         0         x]
+
+julia> bb = U([2a, a + 1, (-a - 1)])
+[   2*x]
+[ x + 1]
+[-x - 1]
+
+julia> x = solve_triu(A, bb, false)
+[ 1//3*x^2 + 8//3*x + 13//3]
+[-3//5*x^2 - 3//5*x - 12//5]
+[                   x^2 + 2]
+
+julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in x over integers
+
+julia> U = matrix_space(R, 3, 2)
+Matrix space of 3 rows and 2 columns
+  over univariate polynomial ring in x over integers
+
+julia> A = S([R(0) 2x + 3 x^2 + 1; x^2 - 2 x - 1 2x; x^2 + 3x + 1 2x R(1)])
+[            0   2*x + 3   x^2 + 1]
+[      x^2 - 2     x - 1       2*x]
+[x^2 + 3*x + 1       2*x         1]
+
+julia> bbb = U(transpose([2x x + 1 (-x - 1); x + 1 (-x) x^2]))
+[   2*x   x + 1]
+[ x + 1      -x]
+[-x - 1     x^2]
+
+julia> x, d = solve_rational(A, bbb)
+([3*x^4-10*x^3-8*x^2-11*x-4 -x^5+3*x^4+x^3-2*x^2+3*x-1; -2*x^5-x^4+6*x^3+2*x+1 x^6+x^5+4*x^4+9*x^3+8*x^2+5*x+2; 6*x^4+12*x^3+15*x^2+6*x-3 -2*x^5-4*x^4-6*x^3-9*x^2-4*x+1], x^5 + 2*x^4 + 15*x^3 + 18*x^2 + 8*x + 7)
+
+julia> S = matrix_space(ZZ, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over integers
+
+julia> T = matrix_space(ZZ, 3, 1)
+Matrix space of 3 rows and 1 column
+  over integers
+
+julia> A = S([BigInt(2) 3 5; 1 4 7; 9 2 2])
+[2   3   5]
+[1   4   7]
+[9   2   2]
+
+julia> B = T([BigInt(4), 5, 7])
+[4]
+[5]
+[7]

Inverse

Base.invMethod
inv(M::MatrixElem{T}) where {T <: RingElement}

Given a non-singular $n\times n$ matrix over a ring, return an $n\times n$ matrix $X$ such that $MX = I_n$, where $I_n$ is the $n\times n$ identity matrix. If $M$ is not invertible over the base ring an exception is raised.

source
AbstractAlgebra.is_invertible_with_inverseMethod
is_invertible_with_inverse(A::MatrixElem{T}; side::Symbol = :left) where {T <: RingElement}

Given an $n\times m$ matrix $A$ over a ring, return a tuple (flag, B). If side is :right and flag is true, $B$ is the right inverse of $A$ i.e. $AB$ is the $n\times n$ unit matrix. If side is :left and flag is true, $B$ is the left inverse of $A$ i.e. $BA$ is the $m\times m$ unit matrix. If flag is false, no right or left inverse exists.

source
AbstractAlgebra.is_invertibleMethod
is_invertible(A::MatrixElem{T}) where {T <: RingElement}

Return true if a given square matrix is invertible, false otherwise. If the inverse should also be computed, use is_invertible_with_inverse.

source

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> K, = residue_field(R, x^3 + 3x + 1); a = K(x);
+
+julia> S = matrix_space(K, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over residue field of univariate polynomial ring modulo x^3 + 3*x + 1
+
+julia> A = S([K(0) 2a + 3 a^2 + 1; a^2 - 2 a - 1 2a; a^2 + 3a + 1 2a K(1)])
+[            0   2*x + 3   x^2 + 1]
+[      x^2 - 2     x - 1       2*x]
+[x^2 + 3*x + 1       2*x         1]
+
+julia> X = inv(A)
+[-343//7817*x^2 + 717//7817*x - 2072//7817   -4964//23451*x^2 + 2195//23451*x - 11162//23451    -232//23451*x^2 - 4187//23451*x - 1561//23451]
+[ 128//7817*x^2 - 655//7817*x + 2209//7817      599//23451*x^2 - 2027//23451*x - 1327//23451   -1805//23451*x^2 + 2702//23451*x - 7394//23451]
+[ 545//7817*x^2 + 570//7817*x + 2016//7817     -1297//23451*x^2 - 5516//23451*x - 337//23451   8254//23451*x^2 - 2053//23451*x + 16519//23451]
+
+julia> is_invertible(A)
+true
+
+julia> is_invertible_with_inverse(A)
+(true, [-343//7817*x^2+717//7817*x-2072//7817 -4964//23451*x^2+2195//23451*x-11162//23451 -232//23451*x^2-4187//23451*x-1561//23451; 128//7817*x^2-655//7817*x+2209//7817 599//23451*x^2-2027//23451*x-1327//23451 -1805//23451*x^2+2702//23451*x-7394//23451; 545//7817*x^2+570//7817*x+2016//7817 -1297//23451*x^2-5516//23451*x-337//23451 8254//23451*x^2-2053//23451*x+16519//23451])
+
+julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S = matrix_space(R, 3, 3)
+Matrix space of 3 rows and 3 columns
+  over univariate polynomial ring in x over integers
+
+julia> A = S([R(0) 2x + 3 x^2 + 1; x^2 - 2 x - 1 2x; x^2 + 3x + 1 2x R(1)])
+[            0   2*x + 3   x^2 + 1]
+[      x^2 - 2     x - 1       2*x]
+[x^2 + 3*x + 1       2*x         1]
+
+julia> X, d = pseudo_inv(A)
+([4*x^2-x+1 -2*x^3+3 x^3-5*x^2-5*x-1; -2*x^3-5*x^2-2*x-2 x^4+3*x^3+2*x^2+3*x+1 -x^4+x^2+2; -x^3+2*x^2+2*x-1 -2*x^3-9*x^2-11*x-3 2*x^3+3*x^2-4*x-6], -x^5 - 2*x^4 - 15*x^3 - 18*x^2 - 8*x - 7)
+

Nullspace

LinearAlgebra.nullspaceMethod
nullspace(M::MatElem{T}) where {T <: RingElement}

Return a tuple $(\nu, N)$ consisting of the nullity $\nu$ of $M$ and a basis $N$ (consisting of column vectors) for the right nullspace of $M$, i.e. such that $MN$ is the zero matrix. If $M$ is an $m\times n$ matrix $N$ will be an $n\times \nu$ matrix. Note that the nullspace is taken to be the vector space kernel over the fraction field of the base ring if the latter is not a field. In AbstractAlgebra we use the name "kernel" for a function to compute an integral kernel.

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S = matrix_space(R, 4, 4)
+Matrix space of 4 rows and 4 columns
+  over univariate polynomial ring in x over integers
+
+julia> M = S([-6*x^2+6*x+12 -12*x^2-21*x-15 -15*x^2+21*x+33 -21*x^2-9*x-9;
+              -8*x^2+8*x+16 -16*x^2+38*x-20 90*x^2-82*x-44 60*x^2+54*x-34;
+              -4*x^2+4*x+8 -8*x^2+13*x-10 35*x^2-31*x-14 22*x^2+21*x-15;
+              -10*x^2+10*x+20 -20*x^2+70*x-25 150*x^2-140*x-85 105*x^2+90*x-50])
+[  -6*x^2 + 6*x + 12   -12*x^2 - 21*x - 15    -15*x^2 + 21*x + 33     -21*x^2 - 9*x - 9]
+[  -8*x^2 + 8*x + 16   -16*x^2 + 38*x - 20     90*x^2 - 82*x - 44    60*x^2 + 54*x - 34]
+[   -4*x^2 + 4*x + 8    -8*x^2 + 13*x - 10     35*x^2 - 31*x - 14    22*x^2 + 21*x - 15]
+[-10*x^2 + 10*x + 20   -20*x^2 + 70*x - 25   150*x^2 - 140*x - 85   105*x^2 + 90*x - 50]
+
+julia> n, N = nullspace(M)
+(2, [1320*x^4-330*x^2-1320*x-1320 1056*x^4+1254*x^3+1848*x^2-66*x-330; -660*x^4+1320*x^3+1188*x^2-1848*x-1056 -528*x^4+132*x^3+1584*x^2+660*x-264; 396*x^3-396*x^2-792*x 0; 0 396*x^3-396*x^2-792*x])
source
nullspace(M::MatElem{T}) where {T <: FieldElement}

Return a tuple $(\nu, N)$ consisting of the nullity $\nu$ of $M$ and a basis $N$ (consisting of column vectors) for the right nullspace of $M$, i.e. such that $MN$ is the zero matrix. If $M$ is an $m\times n$ matrix $N$ will be an $n\times \nu$ matrix.

source

Kernel

AbstractAlgebra.kernelMethod
kernel(A::MatElem{T}; side::Symbol = :right) where T <: RingElement

Return a tuple $(n, M)$, where $n$ is the rank of the kernel of $A$ and $M$ is a basis for it. If side is :right or not specified, the right kernel is computed, i.e. the matrix of columns whose span gives the right kernel space. If side is :left, the left kernel is computed, i.e. the matrix of rows whose span is the left kernel space.

source
AbstractAlgebra.left_kernelMethod
left_kernel(A::MatElem{T}) where T <: RingElement

Return a tuple $(n, M)$ where $M$ is a matrix whose rows generate the kernel of $A$ and $n$ is the rank of the kernel. The transpose of the output of this function is guaranteed to be in flipped upper triangular format (i.e. upper triangular format if columns and rows are reversed).

source
AbstractAlgebra.right_kernelMethod
right_kernel(A::MatElem{T}) where T <: RingElement

Return a tuple $(n, M)$ where $M$ is a matrix whose columns generate the kernel of $A$ and $n$ is the rank of the kernel.

source

Examples

julia> S = matrix_space(ZZ, 4, 4)
+Matrix space of 4 rows and 4 columns
+  over integers
+
+julia> M = S([1 2 0 4;
+              2 0 1 1;
+              0 1 1 -1;
+              2 -1 0 2])
+[1    2   0    4]
+[2    0   1    1]
+[0    1   1   -1]
+[2   -1   0    2]
+
+julia> nr, Nr = kernel(M)
+(1, [-8; -6; 11; 5])
+
+julia> nl, Nl = left_kernel(M)
+(1, [0 -1 1 1])
+

Hessenberg form

LinearAlgebra.hessenbergMethod
hessenberg(A::MatrixElem{T}) where {T <: RingElement}

Return the Hessenberg form of $M$, i.e. an upper Hessenberg matrix which is similar to $M$. The upper Hessenberg form has nonzero entries above and on the diagonal and in the diagonal line immediately below the diagonal.

source

Examples

julia> R, = residue_ring(ZZ, 7);
+
+julia> S = matrix_space(R, 4, 4)
+Matrix space of 4 rows and 4 columns
+  over residue ring of integers modulo 7
+
+julia> M = S([R(1) R(2) R(4) R(3); R(2) R(5) R(1) R(0);
+              R(6) R(1) R(3) R(2); R(1) R(1) R(3) R(5)])
+[1   2   4   3]
+[2   5   1   0]
+[6   1   3   2]
+[1   1   3   5]
+
+julia> A = hessenberg(M)
+[1   5   5   3]
+[2   1   1   0]
+[0   1   3   2]
+[0   0   2   2]
+
+julia> is_hessenberg(A)
+true
+

Characteristic polynomial

AbstractAlgebra.charpolyMethod
charpoly(Y::MatrixElem{T}) where {T <: RingElement}
+charpoly(S::PolyRing{T}, Y::MatrixElem{T}) where {T <: RingElement}

Return the characteristic polynomial $p$ of the square matrix $Y$. If a polynomial ring $S$ over the same base ring as $Y$ is supplied, the resulting polynomial is an element of it.

Examples

julia> R, = residue_ring(ZZ, 7);
+
+julia> S = matrix_space(R, 4, 4)
+Matrix space of 4 rows and 4 columns
+  over residue ring of integers modulo 7
+
+julia> T, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over residue ring, y)
+
+julia> M = S([R(1) R(2) R(4) R(3); R(2) R(5) R(1) R(0);
+              R(6) R(1) R(3) R(2); R(1) R(1) R(3) R(5)])
+[1   2   4   3]
+[2   5   1   0]
+[6   1   3   2]
+[1   1   3   5]
+
+julia> A = charpoly(T, M)
+y^4 + 2*y^2 + 6*y + 2
+
+julia> A = charpoly(M)
+x^4 + 2*x^2 + 6*x + 2
+
source

Minimal polynomial

AbstractAlgebra.minpolyMethod
minpoly(M::MatElem{T}, charpoly_only::Bool = false) where {T <: RingElement}
+minpoly(S::PolyRing{T}, M::MatElem{T}, charpoly_only::Bool = false) where {T <: RingElement}

Return the minimal polynomial $p$ of the square matrix $M$. If a polynomial ring $S$ over the same base ring as $Y$ is supplied, the resulting polynomial is an element of it.

Examples

julia> R = GF(13)
+Finite field F_13
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over finite field F_13, y)
+
+julia> M = R[7 6 1;
+             7 7 5;
+             8 12 5]
+[7    6   1]
+[7    7   5]
+[8   12   5]
+
+julia> A = minpoly(S, M)
+y^2 + 10*y
+
+julia> A = minpoly(M)
+x^2 + 10*x
+
source

Transforms

AbstractAlgebra.similarity!Method
similarity!(A::MatrixElem{T}, r::Int, d::T) where {T <: RingElement}

Applies a similarity transform to the $n\times n$ matrix $M$ in-place. Let $P$ be the $n\times n$ identity matrix that has had all zero entries of row $r$ replaced with $d$, then the transform applied is equivalent to $M = P^{-1}MP$. We require $M$ to be a square matrix. A similarity transform preserves the minimal and characteristic polynomials of a matrix.

Examples

julia> R, = residue_ring(ZZ, 7);
+
+julia> S = matrix_space(R, 4, 4)
+Matrix space of 4 rows and 4 columns
+  over residue ring of integers modulo 7
+
+julia> M = S([R(1) R(2) R(4) R(3); R(2) R(5) R(1) R(0);
+              R(6) R(1) R(3) R(2); R(1) R(1) R(3) R(5)])
+[1   2   4   3]
+[2   5   1   0]
+[6   1   3   2]
+[1   1   3   5]
+
+julia> similarity!(M, 1, R(3))
+
source

Hermite normal form

AbstractAlgebra.hnfMethod
hnf(A::MatrixElem{T}) where {T <: RingElement}

Return the upper right row Hermite normal form of $A$.

source
AbstractAlgebra.hnf_with_transformMethod
hnf_with_transform(A)

Return the tuple $H, U$ consisting of the upper right row Hermite normal form $H$ of $A$ together with invertible matrix $U$ such that $UA = H$.

source

Examples

julia> A = matrix(ZZ, [2 3 -1; 3 5 7; 11 1 12])
+[ 2   3   -1]
+[ 3   5    7]
+[11   1   12]
+
+julia> H = hnf(A)
+[1   0   255]
+[0   1    17]
+[0   0   281]
+
+julia> is_hnf(H)
+true
+
+julia> H, U = hnf_with_transform(A)
+([1 0 255; 0 1 17; 0 0 281], [-47 28 1; -3 2 0; -52 31 1])
+
+julia> U*A
+[1   0   255]
+[0   1    17]
+[0   0   281]

Smith normal form

AbstractAlgebra.snf_with_transformMethod
snf_with_transform(A)

Return the tuple $S, T, U$ consisting of the Smith normal form $S$ of $A$ together with invertible matrices $T$ and $U$ such that $TAU = S$.

source

Examples

julia> A = matrix(ZZ, [2 3 -1; 3 5 7; 11 1 12])
+[ 2   3   -1]
+[ 3   5    7]
+[11   1   12]
+
+julia> S = snf(A)
+[1   0     0]
+[0   1     0]
+[0   0   281]
+
+julia> S, T, U = snf_with_transform(A)
+([1 0 0; 0 1 0; 0 0 281], [1 0 0; 7 1 0; 229 31 1], [0 -3 26; 0 2 -17; -1 0 1])
+
+julia> T*A*U
+[1   0     0]
+[0   1     0]
+[0   0   281]

(Weak) Popov form

AbstractAlgebra.jl provides algorithms for computing the (weak) Popov of a matrix with entries in a univariate polynomial ring over a field.

AbstractAlgebra.is_weak_popovMethod
is_weak_popov(P::MatrixElem{T}, rank::Int) where T <: PolyRingElem

Return true if $P$ is a matrix in weak Popov form of the given rank.

source
AbstractAlgebra.weak_popov_with_transformMethod
weak_popov_with_transform(A::MatElem{T}) where {T <: PolyRingElem}

Compute a tuple $(P, U)$ where $P$ is the weak Popov form of $A$ and $U$ is a transformation matrix so that $P = UA$.

source
AbstractAlgebra.popov_with_transformMethod
popov_with_transform(A::MatElem{T}) where {T <: PolyRingElem}

Compute a tuple $(P, U)$ where $P$ is the Popov form of $A$ and $U$ is a transformation matrix so that $P = UA$.

source

Examples

julia> R, x = polynomial_ring(QQ, "x");
+
+julia> A = matrix(R, map(R, Any[1 2 3 x; x 2*x 3*x x^2; x x^2+1 x^3+x^2 x^4+x^2+1]))
+[1         2           3               x]
+[x       2*x         3*x             x^2]
+[x   x^2 + 1   x^3 + x^2   x^4 + x^2 + 1]
+
+julia> P = weak_popov(A)
+[   1                        2                    3   x]
+[   0                        0                    0   0]
+[-x^3   -2*x^3 + x^2 - 2*x + 1   -2*x^3 + x^2 - 3*x   1]
+
+julia> P, U = weak_popov_with_transform(A)
+([1 2 3 x; 0 0 0 0; -x^3 -2*x^3+x^2-2*x+1 -2*x^3+x^2-3*x 1], [1 0 0; -x 1 0; -x^3-x 0 1])
+
+julia> U*A
+[   1                        2                    3   x]
+[   0                        0                    0   0]
+[-x^3   -2*x^3 + x^2 - 2*x + 1   -2*x^3 + x^2 - 3*x   1]
diff --git a/v0.37.6/matrix_algebras/index.html b/v0.37.6/matrix_algebras/index.html new file mode 100644 index 0000000000..f5336aa64a --- /dev/null +++ b/v0.37.6/matrix_algebras/index.html @@ -0,0 +1,40 @@ + +Generic matrix algebras · AbstractAlgebra.jl

Generic matrix algebras

AbstractAlgebra.jl allows the creation of an algebra (ring) of $m\times m$ matrices over a computable, commutative ring.

Functions specific to generic matrix algebras of $m\times m$ matrices are implemented in src/generic/MatRing.jl. The remaining functionality is in the file src/generic/Matrix.jl.

As well as implementing the entire Matrix interface, including the optional functionality, there are many additional generic algorithms implemented for matrix algebras.

Almost all of the functionality specified for generic matrices is available for matrix algebras. The exceptions are functions such as solve and nullspace which may return non-square matrices, or which don't accept square matrices.

All of the generic functionality is part of the Generic submodule of AbstractAlgebra.jl. This is exported by default, so it is not necessary to qualify names of functions.

Types and parent objects

Generic matrices in AbstractAlgebra.jl have type Generic.MatRingElem{T} for matrices in a matrix algebra, where T is the type of elements of the matrix. Internally, generic matrices are implemented using an object wrapping a Julia two dimensional array, though they are not themselves Julia arrays. See the file src/generic/GenericTypes.jl for details.

Parents of generic matrices in a matrix algebra have type Generic.MatRing{T}.

Note that matrix algebras are noncommutative rings. Thus their types belong to NCRing and NCRingElem. They cannot be used in constructions which require a commutative ring (Ring and RingElem respectively).

The generic matrix algebra matrix types belong to the abstract type MatRingElem{T} and the parent types belong to MatRing{T} Note that both of these require disambiguation from the concrete types in Generic of the same name.

The degree and base ring $R$ of a generic matrix are stored in its parent object, however to allow creation of matrices without first creating the matrix space parent, generic matrices in Julia do not contain a reference to their parent. They contain the row and column numbers (or degree, in the case of matrix algebras) and the base ring on a per matrix basis. The parent object can then be reconstructed from this data on demand.

Matrix algebra constructors

A matrix algebra in AbstractAlgebra.jl represents a collection of all matrices with given degree and base ring.

In order to construct matrices in AbstractAlgebra.jl, one must construct the matrix algebra itself. This is accomplished with the following constructor.

matrix_ring(R::Ring, degree::Int)

Construct the algebra of matrices with the given degree over the given base ring.

Here are some examples of creating matrix algebras and making use of the resulting parent objects to coerce various elements into the matrix algebra.

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_ring(R, 3)
+Matrix ring of degree 3
+  over univariate polynomial ring in t over rationals
+
+julia> A = S()
+[0   0   0]
+[0   0   0]
+[0   0   0]
+
+julia> B = S(12)
+[12    0    0]
+[ 0   12    0]
+[ 0    0   12]
+
+julia> C = S(R(11))
+[11    0    0]
+[ 0   11    0]
+[ 0    0   11]
+

Matrix algebra element constructors

The following additional constructors are provided for constructing various kinds of matrices in a matrix algebra.

AbstractAlgebra.identity_matrixMethod
identity_matrix(M::MatElem{T}) where T <: NCRingElement

Construct the identity matrix in the same matrix space as M, i.e. with ones down the diagonal and zeroes elsewhere. M must be square. This is an alias for one(M).

source
identity_matrix(M::MatRingElem{T}) where T <: RingElement

Return the identity matrix over the same base ring as $M$ and with the same dimensions.

source

Examples

S = matrix_ring(ZZ, 2)
+M = zero(S)
+
+P = identity_matrix(M)

Matrix algebra functionality provided by AbstractAlgebra.jl

Most of the generic matrix functionality described in the generic matrix section of the documentation is available for both matrix spaces and matrix algebras. Exceptions include functions that do not return or accept square matrices or which cannot specify a parent. Such functions include solve and nullspace which can't be provided for matrix algebras.

In addition to the functionality described for matrix spaces, matrix algebras support all noncommutative ring operations, and matrix algebras can be used as a base ring for other generic constructs that accept a noncommutative base ring (NCRing).

In this section we describe functionality provided for matrix algebras only.

Basic matrix functionality

As well as the Ring and Matrix interfaces, the following functions are provided to manipulate matrices.

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S = matrix_ring(R, 3)
+Matrix ring of degree 3
+  over univariate polynomial ring in t over rationals
+
+julia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])
+[t + 1       t             1]
+[  t^2       t             t]
+[   -2   t + 2   t^2 + t + 1]
+
+julia> n = degree(A)
+3
+
diff --git a/v0.37.6/matrix_interface/index.html b/v0.37.6/matrix_interface/index.html new file mode 100644 index 0000000000..165f114899 --- /dev/null +++ b/v0.37.6/matrix_interface/index.html @@ -0,0 +1,16 @@ + +Matrix Interface · AbstractAlgebra.jl

Matrix Interface

Generic matrices are supported in AbstractAlgebra.jl. Both the space of $m\times n$ matrices and the algebra (ring) of $m\times m$ matrices are supported.

As the space of $m\times n$ matrices over a commutative ring is not itself a commutative ring, not all of the Ring interface needs to be implemented for such matrices in.

In particular, the following functions do not need to be implemented: is_domain_type, and divexact. The canonical_unit function should be implemented, but simply needs to return the corresponding value for entry $[1, 1]$ (the function is never called on empty matrices).

For matrix algebras, all of the ring interface must be implemented.

Note

AbstractAlgebra.jl matrices are not the same as Julia matrices. We store a base ring in our matrix and matrices are row major instead of column major in order to support the numerous large C libraries that use this convention.

All AbstractAlgebra.jl matrices are assumed to be mutable. This is usually critical to performance.

Types and parents

AbstractAlgebra provides two abstract types for matrix spaces and their elements:

  • MatSpace{T} is the abstract type for matrix space parent types
  • MatElem{T} is the abstract type for matrix types belonging to a matrix space

It also provides two abstract types for matrix algebras and their elements:

  • MatRing{T} is the abstract type for matrix algebra parent types
  • MatRingElem{T} is the abstract type for matrix types belonging to a matrix algebra

Note that these abstract types are parameterised. The type T should usually be the type of elements of the matrices.

Matrix spaces and matrix algebras should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Matrix spaces and algebras should at least be distinguished based on their base (coefficient) ring and the dimensions of the matrices in the space.

See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).

Required functionality for matrices

In addition to the required (relevant) functionality for the Ring interface (see above), the following functionality is required for the Matrix interface.

We suppose that R is a fictitious base ring (coefficient ring) and that S is a space of $m\times n$ matrices over R, or algebra of $m\times m$ matrices with parent object S of type MyMatSpace{T} or MyMatAlgebra{T}, respectively. We also assume the matrices in the space have type MyMat{T}, where T is the type of elements of the base (element) ring.

Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.

Note that the type T must (transitively) belong to the abstract type RingElem.

Currently only matrices over commutative rings are supported.

Constructors

In addition to the standard constructors, the following constructors, taking an array of elements, must be available.

(S::MyMatSpace{T})(A::Matrix{T}) where T <: RingElem
+(S::MyMatAlgebra{T})(A::Matrix{T}) where T <: RingElem

Create the matrix in the given space/algebra whose $(i, j)$ entry is given by A[i, j].

(S::MyMatSpace{T})(A::Matrix{S}) where {S <: RingElem, T <: RingElem}
+(S::MyMatAlgebra{T})(A::Matrix{S}) where {S <: RingElem, T <: RingElem}

Create the matrix in the given space/algebra whose $(i, j)$ entry is given by A[i, j], where S is the type of elements that can be coerced into the base ring of the matrix.

(S::MyMatSpace{T})(A::Vector{S}) where {S <: RingElem, T <: RingElem}
+(S::MyMatAlgebra{T})(A::Vector{S}) where {S <: RingElem, T <: RingElem}

Create the matrix in the given space/algebra of matrices (with dimensions $m\times n$ say), whose $(i, j)$ entry is given by A[i*(n - 1) + j] and where S is the type of elements that can be coerced into the base ring of the matrix.

It is also possible to create matrices (in a matrix space only) directly, without first creating the corresponding matrix space (the inner constructor being called directly). Note that to support this, matrix space parent objects don't contain a reference to their parent. Instead, parents are constructed on-the-fly if requested. (The same strategy is used for matrix algebras.)

matrix(R::Ring, arr::Matrix{T}) where T <: RingElem

Given an $m\times n$ Julia matrix of entries, construct the corresponding AbstractAlgebra.jl matrix over the given ring R, assuming all the entries can be coerced into R.

matrix(R::Ring, r::Int, c::Int, A::Vector{T}) where T <: RingElem

Construct the given $r\times c$ AbstractAlgebra.jl matrix over the ring R whose $(i, j)$ entry is given by A[c*(i - 1) + j], assuming that all the entries can be coerced into R.

zero_matrix(R::Ring, r::Int, c::Int)

Construct the $r\times c$ AbstractAlgebra.jl zero matrix over the ring R.

Views

Just as Julia supports views of matrices, AbstractAlgebra requires all matrix types to support views. These allow one to work with a submatrix of a given matrix. Modifying the submatrix also modifies the original matrix.

Note that deepcopy of a view type must return the same type, but it should return a view into a deepcopy of the original matrix. Julia enforces this for consistency.

To support views, generic matrices in AbstractAlgebra of type Generic.MatSpaceElem have an associated Generic.MatSpaceView type. Both belong to the Generic.Mat abstract type, so that one can work with that in functions that can accept both views and actual matrices.

The syntax for views is as for Julia's own views.

Note that the parent_type function returns the same type for a view as for the original matrix type. This could potentially cause a problem if the elem_type function is applied to the return value of parent_type and then used in a type assertion. For this reason, there may be some limitations on the use of views.

The similar function also returns a matrix of type MatSpaceElem when applied to a view, rather than another view.

Basic manipulation of matrices

dense_matrix_type(::Type{T}) where T<:NCRingElement
+dense_matrix_type(::T) where T<:NCRingElement
+dense_matrix_type(::Type{S}) where S<:NCRing
+dense_matrix_type(::S) where S<:NCRing

Return the type of dense matrices whose entries have type T respectively elem_type(S). It suffices to provide a method with the first signature. For the other three signatures, the default methods dispatch to the first. E.g. in Nemo, which depends on AbstractAlgebra, we define dense_matrix_type(::Type{ZZRingElem}) = ZZMatrix.

number_of_rows(M::MyMatSpace{T}) where T <: RingElem
+number_of_rows(M::MyMatAlgebra{T}) where T <: RingElem

Return the number of rows of matrices in the matrix space.

number_of_columns(M:MyMatSpace{T}) where T <: RingElem
+number_of_columns(M:MyMatAlgebra{T}) where T <: RingElem

Return the number of columns of matrices in the matrix space.

number_of_rows(f::MyMat{T}) where T <: RingElem

Return the number of rows of the given matrix.

number_of_columns(f::MyMat{T}) where T <: RingElem

Return the number of columns of the given matrix.

getindex(M::MyMat{T}, r::Int, c::Int) where T <: RingElem

Return the $(i, j)$-th entry of the matrix $M$.

setindex!(M::MyMat{T}, d::T, r::Int, c::Int) where T <: RingElem

Set the $(i, j)$-th entry of the matrix $M$ to $d$, which is assumed to be in the base ring of the matrix. The matrix must have such an entry and the matrix is mutated in place and not returned from the function.

Transpose

transpose(::MyMat{T}) where T <: RingElem

Return the transpose of the given matrix.

Optional functionality for matrices

Especially when wrapping C libraries, some functions are best implemented directly, rather than relying on the generic functionality. The following are all provided by the AbstractAlgebra.jl generic code, but can optionally be implemented directly for performance reasons.

Optional submatrices

The following are only available for matrix spaces, not for matrix algebras.

Base.getindex(M::MyMat, rows::AbstractVector{Int}, cols::AbstractVector{Int})

Return a new matrix with the same entries as the submatrix with the given range of rows and columns.

Optional row swapping

swap_rows!(M::MyMat{T}, i::Int, j::Int) where T <: RingElem

Swap the rows of M in place. The function returns the mutated matrix (since matrices are assumed to be mutable in AbstractAlgebra.jl).

Optional concatenation

The following are only available for matrix spaces, not for matrix algebras.

hcat(M::MyMat{T}, N::MyMat{T}) where T <: RingElem

Return the horizontal concatenation of $M$ and $N$. It is assumed that the number of rows of $M$ and $N$ are the same.

vcat(M::MyMat{T}, N::MyMat{T}) where T <: RingElem

Return the vertical concatenation of $M$ and $N$. It is assumed that the number of columns of $M$ and $N$ are the same.

Optional zero tests

The following functions are available for matrices in both matrix algebras and matrix spaces.

is_zero_entry(M::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement
+is_zero_row(M::MatrixElem{T}, i::Int) where T <: NCRingElement
+is_zero_column(M::MatrixElem{T}, j::Int) where T <: NCRingElement

Optional similar and zero

The following functions are available for matrices in both matrix algebras and matrix spaces. Both similar and zero construct new matrices, with the same methods, but the entries are either undefined with similar or zero-initialized with zero.

similar(x::MyMat{T}, R::Ring=base_ring(x)) where T <: RingElem
+zero(x::MyMat{T}, R::Ring=base_ring(x)) where T <: RingElem

Construct the matrix with the same dimensions as the given matrix, and the same base ring unless explicitly specified.

similar(x::MyMat{T}, R::Ring, r::Int, c::Int) where T <: RingElem
+similar(x::MyMat{T}, r::Int, c::Int) where T <: RingElem
+zero(x::MyMat{T}, R::Ring, r::Int, c::Int) where T <: RingElem
+zero(x::MyMat{T}, r::Int, c::Int) where T <: RingElem

Construct the $r\times c$ matrix with R as base ring (which defaults to the base ring of the the given matrix). If $x$ belongs to a matrix algebra and $r \neq c$, an exception is raised, and it's also possible to specify only one Int as the order (e.g. similar(x, n)).

Custom matrices and rings may choose which specific matrix type is best-suited to return for the given ring and dimensionality. If they do not specialize these functions, the default is a Generic.MatSpaceElem matrix, or Generic.MatRingElem for matrix algebras. The default implementation of zero calls out to similar, so it's generally sufficient to specialize only similar. For both similar and zero, only the most general method has to be implemented (e.g. similar(x::MyMat, R::Ring, r::Int, c::Int), as all other methods (which have defaults) call out to this more general method.

Base.isassigned(M::MyMat, i, j)

Test whether the given matrix has a value associated with indices i and j. It is recommended to overload this method for custom matrices.

Optional symmetry test

is_symmetric(a::MatrixElem)

Return true if the given matrix is symmetric with respect to its main diagonal, otherwise return false.

diff --git a/v0.37.6/matrix_introduction/index.html b/v0.37.6/matrix_introduction/index.html new file mode 100644 index 0000000000..e283505cb1 --- /dev/null +++ b/v0.37.6/matrix_introduction/index.html @@ -0,0 +1,2 @@ + +Introduction · AbstractAlgebra.jl

Introduction

AbstractAlgebra provides matrix spaces (mxn matrices) and matrix algebras (nxn matrices) over a ring. Whilst both types of matrix provide matrix multiplication for matrices whose dimensions are compatible for multiplication, only the latter kind of matrices form rings in the system.

Matrix spaces provide a large number of linear algebra operations, including linear solving, elementary row operations, various canonical forms. The system also provides characteristic and minimal polynomial computations, LU decomposition, determinant, matrix inverse, kernel computations.

There is also code for computation of the Hermite and Smith normal forms over Euclidean domains and Popov form for matrices over polynomial rings over a field.

Most of this generic functionality is provided for arbitrary matrix types that satisfy the AbstractAlgebra matrix interface.

diff --git a/v0.37.6/misc/index.html b/v0.37.6/misc/index.html new file mode 100644 index 0000000000..ec7f97e0e5 --- /dev/null +++ b/v0.37.6/misc/index.html @@ -0,0 +1,110 @@ + +Miscellaneous · AbstractAlgebra.jl

Miscellaneous

Printing options

AbstractAlgebra supports printing to LaTeX using the MIME type "text/latex". To enable LaTeX rendering in Jupyter notebooks and query for the current state, use the following functions:

Updating the type diagrams

Updating the diagrams of the documentation can be done by modifying and running the script docs/create_type_diagrams.jl. Note that this requires the package Kroki.

Attributes

Often it is desirable to have a flexible way to attach additional data to mathematical structures such as groups, rings, fields, etc. beyond what the original implementation covers. To facilitate this, we provide an attributes system: for objects of suitable types, one may use set_attribute! to attach key-value pairs to the object, and query them using has_attribute, get_attribute and get_attribute!.

Attributes are supported for all singletons (i.e., instances of an empty struct type), as well as for instances of mutable struct type for which attribute storage was enabled. There are two ways to enable attribute storage for such types:

  1. By applying @attributes to a mutable struct declaration, storage is reserved inside that struct type itself (this increases the size of each struct by 8 bytes if no attributes are set).
  2. By applying @attributes to the name of a mutable struct type, methods are installed which store attributes to instances of the type in a WeakKeyDict outside the struct.
AbstractAlgebra.@attributesMacro
@attributes typedef

This is a helper macro that ensures that there is storage for attributes in the type declared in the expression typedef, which must be either a mutable struct definition expression, or the name of a mutable struct type.

The latter variant is useful to enable attribute storage for types defined in other packages. Note that @attributes is idempotent: when applied to a type for which attribute storage is already available, it does nothing.

For singleton types, attribute storage is also supported, and in fact always enabled. Thus it is not necessary to apply this macro to such a type.

Note

When applied to a struct definition this macro adds a new field to the struct. For structs without constructor, this will change the signature of the default inner constructor, which requires explicit values for every field, including the attribute storage field this macro adds. Usually it is thus preferable to add an explicit default constructor, as in the example below.

Examples

Applying the macro to a struct definition results in internal storage of the attributes:

julia> @attributes mutable struct MyGroup
+           order::Int
+           MyGroup(order::Int) = new(order)
+       end
+
+julia> G = MyGroup(5)
+MyGroup(5, #undef)
+
+julia> set_attribute!(G, :isfinite, :true)
+
+julia> get_attribute(G, :isfinite)
+true

Applying the macro to a typename results in external storage of the attributes:

julia> mutable struct MyOtherGroup
+           order::Int
+           MyOtherGroup(order::Int) = new(order)
+       end
+
+julia> @attributes MyOtherGroup
+
+julia> G = MyOtherGroup(5)
+MyOtherGroup(5)
+
+julia> set_attribute!(G, :isfinite, :true)
+
+julia> get_attribute(G, :isfinite)
+true
source
AbstractAlgebra.@attrMacro
@attr [RetType] funcdef

This macro is applied to the definition of a unary function, and enables caching ("memoization") of its return values based on the argument. This assumes the argument supports attribute storing (see @attributes) via get_attribute!.

The name of the function is used as name for the underlying attribute.

Effectively, this turns code like this:

@attr RetType function myattr(obj::Foo)
+   # ... expensive computation
+   return result
+end

into something essentially equivalent to this:

function myattr(obj::Foo)
+  return get_attribute!(obj, :myattr) do
+    # ... expensive computation
+    return result
+  end::RetType
+end

Examples

julia> @attributes mutable struct Foo
+           x::Int
+           Foo(x::Int) = new(x)
+       end;
+
+julia> @attr Int function myattr(obj::Foo)
+                println("Performing expensive computation")
+                return factorial(obj.x)
+             end;
+
+julia> obj = Foo(5);
+
+julia> myattr(obj)
+Performing expensive computation
+120
+
+julia> myattr(obj) # second time uses the cached result
+120
+
source
AbstractAlgebra.get_attributeFunction
get_attribute(f::Function, G::Any, attr::Symbol)

Return the value stored for the attribute attr, or if no value has been set, return f().

This is intended to be called using do block syntax.

get_attribute(obj, attr) do
+    # default value calculated here if needed
+    ...
+end
source
get_attribute(G::Any, attr::Symbol, default::Any = nothing)

Return the value stored for the attribute attr, or if no value has been set, return default.

source
AbstractAlgebra.get_attribute!Function
get_attribute!(f::Function, G::Any, attr::Symbol)

Return the value stored for the attribute attr of G, or if no value has been set, store key => f() and return f().

This is intended to be called using do block syntax.

get_attribute!(obj, attr) do
+    # default value calculated here if needed
+    ...
+end
source
get_attribute!(G::Any, attr::Symbol, default::Any)

Return the value stored for the attribute attr of G, or if no value has been set, store key => default, and return default.

source
AbstractAlgebra.set_attribute!Function
set_attribute!(G::Any, data::Pair{Symbol, <:Any}...)

Attach the given sequence of key=>value pairs as attributes of G.

source
set_attribute!(G::Any, attr::Symbol, value::Any)

Attach the given value as attribute attr of G.

source

Advanced printing

Self-given names

We provide macros @show_name, @show_special and @show_special_elem to change the way certain objects are printed.

In compact and supercompact printing mode, @show_name tries to determine a suitable name to print instead of the object (see AbstractAlgebra.get_name).

@show_special checks if an attribute :show is present. If so, it has to be a function taking IO, optionally a MIME-type, and the object. This is then called instead of the usual show function.

Similarly, @show_special_elem checks if an attribute :show_elem is present in the object's parent. The semantics are the same as for @show_special.

All are supposed to be used within the usual show function, where @show_special_elem is only relevant for element types of algebraic structures.

function show(io::IO, A::MyObj)
+   @show_name(io, A)
+   @show_special(io, A)
+
+   # ... usual stuff
+end
+
+function show(io::IO, ::MIME"text/plain", A::MyObj)
+   @show_name(io, A)
+   @show_special(io, MIME"text/plain"(), A)
+
+   # ... usual stuff
+end

Documentation

AbstractAlgebra.PrettyPrinting.@show_specialMacro
@show_special(io::IO, obj)

If the obj has a show attribute, this gets called with io and obj and returns from the current scope. Otherwise, does nothing.

It is supposed to be used at the start of show methods as shown in the documentation.

source
@show_special(io::IO, mime, obj)

If the obj has a show attribute, this gets called with io, mime and obj and returns from the current scope. Otherwise, does nothing.

It is supposed to be used at the start of show methods as shown in the documentation.

source
AbstractAlgebra.PrettyPrinting.@show_special_elemMacro
@show_special_elem(io::IO, obj)

If the parent of obj has a show_special_elem attribute, this gets called with io and obj and returns from the current scope. Otherwise, does nothing.

It is supposed to be used at the start of show methods as shown in the documentation.

source
@show_special_elem(io::IO, mime, obj)

If the parent of obj has a show attribute, this gets called with io, mime and obj and returns from the current scope. Otherwise, does nothing.

It is supposed to be used at the start of show methods as shown in the documentation.

source
AbstractAlgebra.PrettyPrinting.@show_nameMacro
@show_name(io::IO, obj)

If either property :compact or :supercompact is set to true for io (see IOContext), print the name get_name(obj) of the object obj to the io stream. This macro either prints the name and returns from the current scope, or does nothing.

It is supposed to be used at the start of show methods as shown in the documentation. ```

source
AbstractAlgebra.PrettyPrinting.set_name!Function
set_name!(obj, name::String; override::Bool=true)

Sets the name of the object obj to name. This name is used for printing using AbstractAlgebra.@show_name. If override is false, the name is only set if there is no name already set.

This function errors if obj does not support attribute storage.

source
set_name!(obj; override::Bool=true)

Sets the name of the object obj to the name of a variable in global (Main module) namespace with value bound to the object obj, if such a variable exists (see AbstractAlgebra.find_name). This name is used for printing using AbstractAlgebra.@show_name. If override is false, the name is only set if there is no name already set.

This function errors if obj does not support attribute storage.

source
AbstractAlgebra.PrettyPrinting.find_nameFunction
find_name(obj, M = Main; all::Bool = false) -> Union{String,Nothing}

Return name of a variable in M's namespace with value bound to the object obj, or nothing if no such variable exists. If all is true, private and non-exported variables are also searched.

Note

If the object is stored in several variables, the first one will be used, but a name returned once is kept until the variable no longer contains this object.

For this to work in doctests, one should call AbstractAlgebra.set_current_module(@__MODULE__) in the value argument of Documenter.DocMeta.setdocmeta! and keep the default value of M = Main here.

Warning

This function should not be used directly, but rather through AbstractAlgebra.get_name.

source

Indentation and Decapitalization

To facilitate printing of nested mathematical structures, we provide a modified IOCustom object, that supports indentation and decapitalization.

Example

We illustrate this with an example

struct A{T}
+  x::T
+end
+
+function Base.show(io::IO, a::A)
+  io = AbstractAlgebra.pretty(io)
+  println(io, "Something of type A")
+  print(io, AbstractAlgebra.Indent(), "over ", AbstractAlgebra.Lowercase(), a.x)
+  print(io, AbstractAlgebra.Dedent()) # don't forget to undo the indentation!
+end
+
+struct B
+end
+
+function Base.show(io::IO, b::B)
+  io = AbstractAlgebra.pretty(io)
+  print(io, LowercaseOff(), "Hilbert thing")
+end

At the REPL, this will then be printed as follows:

julia> A(2)
+Something of type A
+  over 2
+
+julia> A(A(2))
+Something of type A
+  over something of type A
+    over 2
+
+julia> A(B())
+Something of type A
+  over Hilbert thing

Documentation

AbstractAlgebra.PrettyPrinting.IndentType
Indent

When printed to an IOCustom object, increases the indentation level by one.

Examples

julia> io = AbstractAlgebra.pretty(stdout);
+
+julia> print(io, AbstractAlgebra.Indent(), "This is indented")
+  This is indented
source
AbstractAlgebra.PrettyPrinting.DedentType
Dedent

When printed to an IOCustom object, decreases the indentation level by one.

Examples

julia> io = AbstractAlgebra.pretty(stdout);
+
+julia> print(io, AbstractAlgebra.Indent(), AbstractAlgebra.Dedent(), "This is indented")
+This is indented
source
AbstractAlgebra.PrettyPrinting.LowercaseType
Lowercase

When printed to an IOCustom object, the next letter printed will be lowercase.

Examples

julia> io = AbstractAlgebra.pretty(stdout);
+
+julia> print(io, AbstractAlgebra.Lowercase(), "Foo")
+foo
source
AbstractAlgebra.PrettyPrinting.LowercaseOffType
LowercaseOff

When printed to an IOCustom object, the case of the next letter will not be changed when printed.

Examples

julia> io = AbstractAlgebra.pretty(stdout);
+
+julia> print(io, AbstractAlgebra.Lowercase(), AbstractAlgebra.LowercaseOff(), "Foo")
+Foo
source
diff --git a/v0.37.6/module/index.html b/v0.37.6/module/index.html new file mode 100644 index 0000000000..0edf73aa3c --- /dev/null +++ b/v0.37.6/module/index.html @@ -0,0 +1,94 @@ + +Finitely presented modules · AbstractAlgebra.jl

Finitely presented modules

AbstractAlgebra allows the construction of finitely presented modules (i.e. with finitely many generators and relations), starting from free modules.

The generic code provided by AbstractAlgebra will only work for modules over euclidean domains.

Free modules can be built over both commutative and noncommutative rings. Other types of module are restricted to fields and euclidean rings.

Abstract types

AbstractAlgebra provides two abstract types for finitely presented modules and their elements:

  • FPModule{T} is the abstract type for finitely presented module parent

types

  • FPModuleElem{T} is the abstract type for finitely presented module

element types

Note that the abstract types are parameterised. The type T should usually be the type of elements of the ring the module is over.

Module functions

All finitely presented modules over a Euclidean domain implement the following functions.

Basic functions

zero(M::FPModule)
iszero(m::FPModuleElem{T}) where T <: RingElement

Return true if the given module element is zero.

number_of_generators(M::FPModule{T}) where T <: RingElement

Return the number of generators of the module $M$ in its current representation.

gen(M::FPModule{T}, i::Int) where T <: RingElement

Return the $i$-th generator (indexed from $1$) of the module $M$.

gens(M::FPModule{T}) where T <: RingElement

Return a Julia array of the generators of the module $M$.

rels(M::FPModule{T}) where T <: RingElement

Return a Julia vector of all the relations between the generators of M. Each relation is given as an AbstractAlgebra row matrix.

Examples

julia> M = FreeModule(QQ, 2)
+Vector space of dimension 2 over rationals
+
+julia> n = number_of_generators(M)
+2
+
+julia> G = gens(M)
+2-element Vector{AbstractAlgebra.Generic.FreeModuleElem{Rational{BigInt}}}:
+ (1//1, 0//1)
+ (0//1, 1//1)
+
+julia> R = rels(M)
+AbstractAlgebra.Generic.MatSpaceElem{Rational{BigInt}}[]
+
+julia> g1 = gen(M, 1)
+(1//1, 0//1)
+
+julia> !iszero(g1)
+true
+
+julia> M = FreeModule(QQ, 2)
+Vector space of dimension 2 over rationals
+
+julia> z = zero(M)
+(0//1, 0//1)
+
+julia> iszero(z)
+true

Element constructors

We can construct elements of a module $M$ by specifying linear combinations of the generators of $M$. This is done by passing a vector of ring elements.

(M::FPModule{T})(v::Vector{T}) where T <: RingElement

Construct the element of the module $M$ corresponding to $\sum_i g[i]v[i]$ where $g[i]$ are the generators of the module $M$. The resulting element will lie in the module $M$.

Coercions

Given a module $M$ and an element $n$ of a module $N$, it is possible to coerce $n$ into $M$ using the notation $M(n)$ in certain circumstances.

In particular the element $n$ will be automatically coerced along any canonical injection of a submodule map and along any canonical projection of a quotient map. There must be a path from $N$ to $M$ along such maps.

Examples

F = FreeModule(ZZ, 3)
+
+S1, f = sub(F, [rand(F, -10:10)])
+
+S, g = sub(F, [rand(F, -10:10)])
+Q, h = quo(F, S)
+
+m = rand(S1, -10:10)
+n = Q(m)

Arithmetic operators

Elements of a module can be added, subtracted or multiplied by an element of the ring the module is defined over and compared for equality.

In the case of a noncommutative ring, both left and right scalar multiplication are defined.

Basic manipulation

zero(M::FPModule)

Examples

julia> M = FreeModule(QQ, 2)
+Vector space of dimension 2 over rationals
+
+julia> z = zero(M)
+(0//1, 0//1)

Element indexing

Base.getindexMethod
getindex(a::Fac, b) -> Int

If $b$ is a factor of $a$, the corresponding exponent is returned. Otherwise an error is thrown.

source

Examples

julia> F = FreeModule(ZZ, 3)
+Free module of rank 3 over integers
+
+julia> m = F(BigInt[2, -5, 4])
+(2, -5, 4)
+
+julia> m[1]
+2

Module comparison

Base.:==Method
==(M::FPModule{T}, N::FPModule{T}) where T <: RingElement

Return true if the modules are (constructed to be) the same module elementwise. This is not object equality and it is not isomorphism. In fact, each method of constructing modules (submodules, quotient modules, products, etc.) must extend this notion of equality to the modules they create.

source

Examples

julia> M = FreeModule(QQ, 2)
+Vector space of dimension 2 over rationals
+
+julia> M == M
+true
+

Isomorphism

Note

Note that this function relies on the Smith normal form over the base ring of the modules being able to be made unique. This is true for Euclidean domains for which divrem has a fixed choice of quotient and remainder, but it will not in general be true for Euclidean rings that are not domains.

Examples

julia> M = FreeModule(ZZ, 3)
+Free module of rank 3 over integers
+
+julia> m1 = rand(M, -10:10)
+(3, -1, 0)
+
+julia> m2 = rand(M, -10:10)
+(4, 4, -7)
+
+julia> S, f = sub(M, [m1, m2])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 3 over integers)
+
+julia> I, g = image(f)
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 3 over integers)
+
+julia> is_isomorphic(S, I)
+true
+

Invariant Factor Decomposition

For modules over a euclidean domain one can take the invariant factor decomposition to determine the structure of the module. The invariant factors are unique up to multiplication by a unit, and even unique if a canonical_unit is available for the ring that canonicalises elements.

AbstractAlgebra.snfMethod
snf(m::FPModule{T}) where T <: RingElement

Return a pair M, f consisting of the invariant factor decomposition $M$ of the module m and a module homomorphism (isomorphisms) $f : M \to m$. The module M is itself a module which can be manipulated as any other module in the system.

source

Examples

julia> M = FreeModule(ZZ, 3)
+Free module of rank 3 over integers
+
+julia> m1 = rand(M, -10:10)
+(3, -1, 0)
+
+julia> m2 = rand(M, -10:10)
+(4, 4, -7)
+
+julia> S, f = sub(M, [m1, m2])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 3 over integers)
+
+julia> Q, g = quo(M, S)
+(Quotient module over Integers with 2 generators and relations:
+[16 -21], Hom: free module of rank 3 over integers -> quotient module over Integers with 2 generators and relations:
+[16 -21])
+
+julia> I, f = snf(Q)
+(Invariant factor decomposed module over Integers with invariant factors BigInt[0], Hom: invariant factor decomposed module over Integers with invariant factors BigInt[0] -> quotient module over Integers with 2 generators and relations:
+[16 -21])
+
+julia> invs = invariant_factors(Q)
+1-element Vector{BigInt}:
+ 0
+
diff --git a/v0.37.6/module_homomorphism/index.html b/v0.37.6/module_homomorphism/index.html new file mode 100644 index 0000000000..e104cbdc1b --- /dev/null +++ b/v0.37.6/module_homomorphism/index.html @@ -0,0 +1,54 @@ + +Module Homomorphisms · AbstractAlgebra.jl

Module Homomorphisms

Abstract Algebra provides homomorphisms of finitely presented modules.

Generic module homomorphism types

AbstractAlgebra defines two module homomorphism types, namely Generic.ModuleHomomorphism and Generic.ModuleIsomorphism. Functionality for these is implemented in src/generic/ModuleHomomorphism.jl.

Abstract types

The Generic.ModuleHomomorphism and Generic.ModuleIsomorphism types inherit from Map(FPModuleHomomorphism).

Generic functionality

The following generic functionality is provided for module homomorphisms.

Constructors

Homomorphisms of AbstractAlgebra modules, $f : R^s \to R^t$, can be represented by $s\times t$ matrices over $R$.

AbstractAlgebra.ModuleHomomorphismMethod
ModuleHomomorphism(M1::FPModule{T},
+                   M2::FPModule{T}, m::MatElem{T}) where T <: RingElement

Create the homomorphism $f : M_1 \to M_2$ represented by the matrix $m$.

source
AbstractAlgebra.ModuleIsomorphismMethod
ModuleIsomorphism(M1::FPModule{T}, M2::FPModule{T}, M::MatElem{T},
+                  minv::MatElem{T}) where T <: RingElement

Create the isomorphism $f : M_1 \to M_2$ represented by the matrix $M$. The inverse morphism is automatically computed.

source

Examples

julia> M = FreeModule(ZZ, 2)
+Free module of rank 2 over integers
+
+julia> f = ModuleHomomorphism(M, M, matrix(ZZ, 2, 2, [1, 2, 3, 4]))
+Module homomorphism
+  from free module of rank 2 over integers
+  to free module of rank 2 over integers
+
+julia> m = M([ZZ(1), ZZ(2)])
+(1, 2)
+
+julia> f(m)
+(7, 10)
+

They can also be created by giving images (in the codomain) of the generators of the domain:

ModuleHomomorphism(M1::FPModule{T}, M2::FPModule{T}, v::Vector{<:FPModuleElem{T}}) where T <: RingElement

Kernels

AbstractAlgebra.kernelMethod
kernel(f::ModuleHomomorphism{T}) where T <: RingElement

Return a pair K, g consisting of the kernel object $K$ of the given module homomorphism $f$ (as a submodule of its domain) and the canonical injection from the kernel into the domain of $f$

source

Examples

julia> M = FreeModule(ZZ, 3)
+Free module of rank 3 over integers
+
+julia> m = M([ZZ(1), ZZ(2), ZZ(3)])
+(1, 2, 3)
+
+julia> S, f = sub(M, [m])
+(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 3 over integers)
+
+julia> Q, g = quo(M, S)
+(Quotient module over Integers with 2 generators and no relations, Hom: free module of rank 3 over integers -> quotient module over Integers with 2 generators and no relations)
+
+julia> kernel(g)
+(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 3 over integers)
+

Images

AbstractAlgebra.imageMethod
image(f::Map(FPModuleHomomorphism))

Return a pair I, g consisting of the image object $I$ of the given module homomorphism $f$ (as a submodule of its codomain) and the canonical injection from the image into the codomain of $f$

source
M = FreeModule(ZZ, 3)
+
+m = M([ZZ(1), ZZ(2), ZZ(3)])
+
+S, f = sub(M, [m])
+Q, g = quo(M, S)
+K, k = kernel(g)
+
+image(compose(k, g))

Preimages

AbstractAlgebra.preimageMethod
preimage(f::Map(FPModuleHomomorphism),
+         v::FPModuleElem{T}) where T <: RingElement

Return a preimage of $v$ under the homomorphism $f$, i.e. an element of the domain of $f$ that maps to $v$ under $f$. Note that this has no special mathematical properties. It is an element of the set theoretical preimage of the map $f$ as a map of sets, if one exists. The preimage is neither unique nor chosen in a canonical way in general. When no such element exists, an exception is raised.

source
M = FreeModule(ZZ, 3)
+
+m = M([ZZ(1), ZZ(2), ZZ(3)])
+
+S, f = sub(M, [m])
+Q, g = quo(M, S)
+
+m = rand(M, -10:10)
+n = g(m)
+
+p = preimage(g, n)

Inverses

Module isomorphisms can be cheaply inverted.

Base.invMethod
Base.inv(f::Map(ModuleIsomorphism))

Return the inverse map of the given module isomorphism. This is computed cheaply.

source
M = FreeModule(ZZ, 2)
+N = matrix(ZZ, 2, 2, BigInt[1, 0, 0, 1])
+f = ModuleIsomorphism(M, M, N)
+
+g = inv(f)
diff --git a/v0.37.6/module_interface/index.html b/v0.37.6/module_interface/index.html new file mode 100644 index 0000000000..78698b0fc4 --- /dev/null +++ b/v0.37.6/module_interface/index.html @@ -0,0 +1,2 @@ + +Module Interface · AbstractAlgebra.jl

Module Interface

Note

The module infrastructure in AbstractAlgebra should be considered experimental at this stage. This means that the interface may change in the future.

AbstractAlgebra allows the construction of finitely presented modules (i.e. with finitely many generators and relations), starting from free modules. The generic code provided by AbstractAlgebra will only work for modules over euclidean domains, however there is nothing preventing a library from implementing more general modules using the same interface.

All finitely presented module types in AbstractAlgebra follow the following interface which is a loose interface of functions, without much generic infrastructure built on top.

Free modules can be built over both commutative and noncommutative rings. Other types of module are restricted to fields and euclidean rings.

Abstract types

AbstractAlgebra provides two abstract types for finitely presented modules and their elements:

  • FPModule{T} is the abstract type for finitely presented module parent

types

  • FPModuleElem{T} is the abstract type for finitely presented module

element types

Note that the abstract types are parameterised. The type T should usually be the type of elements of the ring the module is over.

Required functionality for modules

We suppose that R is a fictitious base ring and that S is a module over R with parent object S of type MyModule{T}. We also assume the elements in the module have type MyModuleElem{T}, where T is the type of elements of the ring the module is over.

Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.

Note that the type T must (transitively) belong to the abstract type RingElement or NCRingElem.

We describe the functionality below for modules over commutative rings, i.e. with element type belonging to RingElement, however similar constructors should be available for element types belonging to NCRingElem instead, for free modules over a noncommutative ring.

Although not part of the module interface, implementations of modules that wish to follow our interface should use the same function names for submodules, quotient modules, direct sums and module homomorphisms if they wish to remain compatible with our module generics in the future.

Basic manipulation

iszero(m::MyModuleElem{T}) where T <: RingElement

Return true if the given module element is zero.

number_of_generators(M::MyModule{T}) where T <: RingElement

Return the number of generators of the module $M$ in its current representation.

gen(M::MyModule{T}, i::Int) where T <: RingElement

Return the $i$-th generator (indexed from $1$) of the module $M$.

gens(M::MyModule{T}) where T <: RingElement

Return a Julia array of the generators of the module $M$.

rels(M::MyModule{T}) where T <: RingElement

Return a Julia vector of all the relations between the generators of M. Each relation is given as an AbstractAlgebra row matrix.

Element constructors

We can construct elements of a module $M$ by specifying linear combinations of the generators of $M$. This is done by passing a vector of ring elements.

(M::Module{T})(v::Vector{T}) where T <: RingElement

Construct the element of the module $M$ corresponding to $\sum_i g[i]v[i]$ where $g[i]$ are the generators of the module $M$. The resulting element will lie in the module $M$.

Coercions

Given a module $M$ and an element $n$ of a module $N$, it is possible to coerce $n$ into $M$ using the notation $M(n)$ in certain circumstances.

In particular the element $n$ will be automatically coerced along any canonical injection of a submodule map and along any canonical projection of a quotient map. There must be a path from $N$ to $M$ along such maps.

Arithmetic operators

Elements of a module can be added, subtracted or multiplied by an element of the ring the module is defined over and compared for equality.

In the case of a noncommutative ring, both left and right scalar multiplication are defined.

diff --git a/v0.37.6/module_introduction/index.html b/v0.37.6/module_introduction/index.html new file mode 100644 index 0000000000..1035f17ffb --- /dev/null +++ b/v0.37.6/module_introduction/index.html @@ -0,0 +1,2 @@ + +Introduction · AbstractAlgebra.jl

Introduction

As with many generic constructions in AbstractAlgebra, the modules that are provided in AbstractAlgebra itself work over a Euclidean domain. Moreover, they are limited to finitely presented modules.

Free modules and vector spaces are provided over Euclidean domains and fields respectively and then submodule, quotient module and direct sum module constructions are possible recursively over these.

It's also possible to compute an invariant decomposition using the Smith Normal Form.

The system also provides module homomorphisms and isomorphisms, building on top of the map interface.

As for rings and fields, modules follow an interface which other modules are expected to follow. However, very little generic functionality is provided automatically once this interface is implemented by a new module type.

The purpose of the module interface is simply to encourage uniformity in the module interfaces of systems that build on AbstractAlgebra. Of course modules are so diverse that this is a very loosely defined interface to accommodate the diversity of possible representations and implementations.

diff --git a/v0.37.6/mpoly_interface/index.html b/v0.37.6/mpoly_interface/index.html new file mode 100644 index 0000000000..a0c212bb4d --- /dev/null +++ b/v0.37.6/mpoly_interface/index.html @@ -0,0 +1,7 @@ + +Multivariate Polynomial Ring Interface · AbstractAlgebra.jl

Multivariate Polynomial Ring Interface

Multivariate polynomial rings are supported in AbstractAlgebra.jl, and in addition to the standard Ring interface, numerous additional functions are provided.

Unlike other kinds of rings, even complex operations such as GCD depend heavily on the multivariate representation. Therefore AbstractAlgebra.jl cannot provide much in the way of additional functionality to external multivariate implementations.

This means that external libraries must be able to implement their multivariate formats in whatever way they see fit. The required interface here should be implemented, even if it is not optimal. But it can be extended, either by implementing one of the optional interfaces, or by extending the required interface in some other way.

Naturally, any multivariate polynomial ring implementation provides the full Ring interface, in order to be treated as a ring for the sake of AbstractAlgebra.jl.

Considerations which make it impossible for AbstractAlgebra.jl to provide generic functionality on top of an arbitrary multivariate module include:

  • orderings (lexical, degree, weighted, block, arbitrary)
  • sparse or dense representation
  • distributed or recursive representation
  • packed or unpacked exponents
  • exponent bounds (and whether adaptive or not)
  • random access or iterators
  • whether monomials and polynomials have the same type
  • whether special cache aware data structures such as Geobuckets are used

Types and parents

AbstractAlgebra.jl provides two abstract types for multivariate polynomial rings and their elements:

  • MPolyRing{T} is the abstract type for multivariate polynomial ring parent types
  • MPolyRingElem{T} is the abstract type for multivariate polynomial types

We have that MPolyRing{T} <: Ring and MPolyRingElem{T} <: RingElem.

Note that both abstract types are parameterised. The type T should usually be the type of elements of the coefficient ring of the polynomial ring. For example, in the case of $\mathbb{Z}[x, y]$ the type T would be the type of an integer, e.g. BigInt.

Multivariate polynomial rings should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Multivariate polynomial rings should at least be distinguished based on their base (coefficient) ring and number of variables. But if they have the same base ring, symbols (for their variables/generators) and ordering, they should certainly have the same parent object.

See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).

Required functionality for multivariate polynomials

In addition to the required functionality for the Ring interface, the Multivariate Polynomial interface has the following required functions.

We suppose that R is a fictitious base ring (coefficient ring) and that S is a multivariate polynomial ring over R (i.e. $S = R[x, y, \ldots]$) with parent object S of type MyMPolyRing{T}. We also assume the polynomials in the ring have type MyMPoly{T}, where T is the type of elements of the base (coefficient) ring.

Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.

Note that the type T must (transitively) belong to the abstract type RingElem or more generally the union type RingElement which includes the Julia integer, rational and floating point types.

Constructors

To construct a multivariate polynomial ring, there is the following constructor.

AbstractAlgebra.polynomial_ringMethod
polynomial_ring(R::Ring, varnames::Vector{Symbol}; cached=true, ordering=:lex)

Given a coefficient ring R and variable names, say varnames = [:x1, :x2, ...], return a tuple S, [x1, x2, ...] of the polynomial ring $S = R[x1, x2, \dots]$ and its generators $x1, x2, \dots$.

By default (cached=true), the output S will be cached, i.e. if polynomial_ring is invoked again with the same arguments, the same (identical) ring is returned. Setting cached to false ensures a distinct new ring is returned, and will also prevent it from being cached.

The ordering of the polynomial ring can be one of :lex, :deglex or :degrevlex.

See also: polynomial_ring(::Ring, ::Vararg), @polynomial_ring.

Example

julia> S, generators = polynomial_ring(ZZ, [:x, :y, :z])
+(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y, z])
source

Polynomials in a given ring can be constructed using the generators and basic polynomial arithmetic. However, this is inefficient and the following build context is provided for building polynomials term-by-term. It assumes the polynomial data type is random access, and so the constructor functions must be reimplemented for all other types of polynomials.

MPolyBuildCtx(R::MPolyRing)

Return a build context for creating polynomials in the given polynomial ring.

push_term!(M::MPolyBuildCtx, c::RingElem, v::Vector{Int})

Add the term with coefficient $c$ and exponent vector $v$ to the polynomial under construction in the build context $M$.

finish(M::MPolyBuildCtx)

Finish construction of the polynomial, sort the terms, remove duplicate and zero terms and return the created polynomial.

Data type and parent object methods

symbols(S::MyMPolyRing{T}) where T <: RingElem

Return an array of Symbols representing the variables (generators) of the polynomial ring. Note that these are Symbols not Strings, though their string values will usually be used when printing polynomials.

number_of_variables(f::MyMPolyRing{T}) where T <: RingElem

Return the number of variables of the polynomial ring.

gens(S::MyMPolyRing{T}) where T <: RingElem

Return an array of all the generators (variables) of the given polynomial ring (as polynomials).

The first entry in the array will be the variable with most significance with respect to the ordering.

gen(S::MyMPolyRing{T}, i::Int) where T <: RingElem

Return the $i$-th generator (variable) of the given polynomial ring (as a polynomial).

ordering(S::MyMPolyRing{T})

Return the ordering of the given polynomial ring as a symbol. Supported values currently include :lex, :deglex and :degrevlex.

Basic manipulation of rings and elements

length(f::MyMPoly{T}) where T <: RingElem

Return the number of nonzero terms of the given polynomial. The length of the zero polynomial is defined to be $0$. The return value should be of type Int.

degrees(f::MyMPoly{T}) where T <: RingElem

Return an array of the degrees of the polynomial $f$ in each of the variables.

total_degree(f::MyMPoly{T}) where T <: RingElem

Return the total degree of the polynomial $f$, i.e. the highest sum of exponents occurring in any term of $f$.

is_gen(x::MyMPoly{T}) where T <: RingElem

Return true if $x$ is a generator of the polynomial ring.

coefficients(p::MyMPoly{T}) where T <: RingElem

Return an iterator for the coefficients of the polynomial $p$, starting with the coefficient of the most significant term with respect to the ordering. Generic code will provide this function automatically for random access polynomials that implement the coeff function.

monomials(p::MyMPoly{T}) where T <: RingElem

Return an iterator for the monomials of the polynomial $p$, starting with the monomial of the most significant term with respect to the ordering. Monomials in AbstractAlgebra are defined to have coefficient $1$. See the function terms if you also require the coefficients, however note that only monomials can be compared. Generic code will provide this function automatically for random access polynomials that implement the monomial function.

terms(p::MyMPoly{T}) where T <: RingElem

Return an iterator for the terms of the polynomial $p$, starting with the most significant term with respect to the ordering. Terms in AbstractAlgebra include the coefficient. Generic code will provide this function automatically for random access polynomials that implement the term function.

exponent_vectors(a::MyMPoly{T}) where T <: RingElement

Return an iterator for the exponent vectors for each of the terms of the polynomial starting with the most significant term with respect to the ordering. Each exponent vector is an array of Ints, one for each variable, in the order given when the polynomial ring was created. Generic code will provide this function automatically for random access polynomials that implement the exponent_vector function.

Exact division

For any ring that implements exact division, the following can be implemented.

divexact(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem

Return the exact quotient of $f$ by $g$ if it exists, otherwise throw an error.

divides(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem

Return a tuple (flag, q) where flag is true if $g$ divides $f$, in which case $q$ will be the exact quotient, or flag is false and $q$ is set to zero.

remove(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem

Return a tuple $(v, q)$ such that the highest power of $g$ that divides $f$ is $g^v$ and the cofactor is $q$.

valuation(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem

Return $v$ such that the highest power of $g$ that divides $f$ is $g^v$.

Ad hoc exact division

For any ring that implements exact division, the following can be implemented.

divexact(f::MyMPoly{T}, c::Integer) where T <: RingElem
+divexact(f::MyMPoly{T}, c::Rational) where T <: RingElem
+divexact(f::MyMPoly{T}, c::T) where T <: RingElem

Divide the polynomial exactly by the constant $c$.

Euclidean division

Although multivariate polynomial rings are not in general Euclidean, it is possible to define a quotient with remainder function that depends on the polynomial ordering in the case that the quotient ring is a field or a Euclidean domain. In the case that a polynomial $g$ divides a polynomial $f$, the result no longer depends on the ordering and the remainder is zero, with the quotient agreeing with the exact quotient.

divrem(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem

Return a tuple $(q, r)$ such that $f = qg + r$, where the coefficients of terms of $r$ whose monomials are divisible by the leading monomial of $g$ are reduced modulo the leading coefficient of $g$ (according to the Euclidean function on the coefficients).

Note that the result of this function depends on the ordering of the polynomial ring.

div(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem

As per the divrem function, but returning the quotient only. Especially when the quotient happens to be exact, this function can be exceedingly fast.

GCD

In cases where there is a meaningful Euclidean structure on the coefficient ring, it is possible to compute the GCD of multivariate polynomials.

gcd(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem

Return a greatest common divisor of $f$ and $g$.

Square root

Over rings for which an exact square root is available, it is possible to take the square root of a polynomial or test whether it is a square.

sqrt(f::MyMPoly{T}, check::Bool=true) where T <: RingElem

Return the square root of the polynomial $f$ and raise an exception if it is not a square. If check is set to false, the input is assumed to be a perfect square and this assumption is not fully checked. This can be significantly faster.

is_square(::MyMPoly{T}) where T <: RingElem

Return true if $f$ is a square.

Interface for sparse distributed, random access multivariates

The following additional functions should be implemented by libraries that provide a sparse distributed polynomial format, stored in a representation for which terms can be accessed in constant time (e.g. where arrays are used to store coefficients and exponent vectors).

Sparse distributed, random access constructors

In addition to the standard constructors, the following constructor, taking arrays of coefficients and exponent vectors, should be provided.

(S::MyMPolyRing{T})(A::Vector{T}, m::Vector{Vector{Int}}) where T <: RingElem

Create the polynomial in the given ring with nonzero coefficients specified by the elements of $A$ and corresponding exponent vectors given by the elements of $m$.

There is no assumption about coefficients being nonzero or terms being in order or unique. Zero terms are removed by the function, duplicate terms are combined (added) and the terms are sorted so that they are in the correct order.

Each exponent vector uses a separate integer for each exponent field, the first of which should be the exponent for the most significant variable with respect to the ordering. All exponents must be non-negative.

A library may also optionally provide an interface that makes use of BigInt (or any other big integer type) for exponents instead of Int.

Sparse distributed, random access basic manipulation

coeff(f::MyMPoly{T}, n::Int) where T <: RingElem

Return the coefficient of the $n$-th term of $f$. The first term should be the most significant term with respect to the ordering.

coeff(a::MyMPoly{T}, exps::Vector{Int}) where T <: RingElement

Return the coefficient of the term with the given exponent vector, or zero if there is no such term.

monomial(f::MyMPoly{T}, n::Int) where T <: RingElem
+monomial!(m::MyMPoly{T}, f::MyMPoly{T}, n::Int) where T <: RingElem

Return the $n$-th monomial of $f$ or set $m$ to the $n$-th monomial of $f$, respectively. The first monomial should be the most significant term with respect to the ordering. Monomials have coefficient $1$ in AbstractAlgebra. See the function term if you also require the coefficient, however, note that only monomials can be compared.

term(f::MyMPoly{T}, n::Int) where T <: RingElem

Return the $n$-th term of $f$. The first term should be the one whose monomial is most significant with respect to the ordering.

exponent(f::MyMPoly{T}, i::Int, j::Int) where T <: RingElem

Return the exponent of the $j$-th variable in the $i$-th term of the polynomial $f$. The first term is the one with whose monomial is most significant with respect to the ordering.

exponent_vector(a::MyMPoly{T}, i::Int) where T <: RingElement

Return a vector of exponents, corresponding to the exponent vector of the i-th term of the polynomial. Term numbering begins at $1$ and the exponents are given in the order of the variables for the ring, as supplied when the ring was created.

setcoeff!(a::MyMPoly, exps::Vector{Int}, c::S) where S <: RingElement

Set the coefficient of the term with the given exponent vector to the given value $c$. If no such term exists (and $c \neq 0$), one will be inserted. This function takes $O(\log n)$ operations if a term with the given exponent already exists and $c \neq 0$, or if the term is inserted at the end of the polynomial. Otherwise it can take $O(n)$ operations in the worst case. This function must return the modified polynomial.

Unsafe functions

The following functions must be provided, but are considered unsafe, as they may leave the polynomials in an inconsistent state and they mutate their inputs. As usual, such functions should only be applied on polynomials that have no references elsewhere in the system and are mainly intended to be used in carefully written library code, rather than by users.

Users should instead build polynomials using the constructors described above.

fit!(f::MyMPoly{T}, n::Int) where T <: RingElem

Ensure that the polynomial $f$ internally has space for $n$ nonzero terms. This function must mutate the function in-place if it is mutable. It does not return the mutated polynomial. Immutable types can still be supported by defining this function to do nothing.

setcoeff!(a::MyMPoly{T}, i::Int, c::T) where T <: RingElement
+setcoeff!(a::MyMPoly{T}, i::Int, c::U) where {T <: RingElement, U <: Integer}

Set the $i$-th coefficient of the polynomial $a$ to $c$. No check is performed on the index $i$ or for $c = 0$. It may be necessary to call combine_like_terms after calls to this function, to remove zero terms. The function must return the modified polynomial.

combine_like_terms!(a::MyMPoly{T}) where T <: RingElement

Remove zero terms and combine any adjacent terms with the same exponent vector (by adding them). It is assumed that all the exponent vectors are already in the correct order with respect to the ordering. The function must return the resulting polynomial.

set_exponent_vector!(a::MyMPoly{T}, i::Int, exps::Vector{Int}) where T <: RingElement

Set the $i$-th exponent vector to the given exponent vector. No check is performed on the index $i$, which is assumed to be valid (or that the polynomial has enough space allocated). No sorting of exponents is performed by this function. To sort the terms after setting any number of exponents with this function, run the sort_terms! function. The function must return the modified polynomial.

sort_terms!(a::MyMPoly{T}) where {T <: RingElement}

Sort the terms of the given polynomial according to the polynomial ring ordering. Zero terms and duplicate exponents are ignored. To deal with those call combine_like_terms. The sorted polynomial must be returned by the function.

Optional functionality for multivariate polynomials

The following functions can optionally be implemented for multivariate polynomial types.

Reduction by an ideal

divrem(f::MyMPoly{T}, G::Vector{MyMPoly{T}}) where T <: RingElem

As per the divrem function above, except that each term of $r$ starting with the most significant term, is reduced modulo the leading terms of each of the polynomials in the array $G$ for which the leading monomial is a divisor.

A tuple $(Q, r)$ is returned from the function, where $Q$ is an array of polynomials of the same length as $G$, and such that $f = r + \sum Q[i]G[i]$.

The result is again dependent on the ordering in general, but if the polynomials in $G$ are over a field and the reduced generators of a Groebner basis, then the result is unique.

Evaluation

evaluate(a::MyMPoly{T}, A::Vector{T}) where T <: RingElem

Evaluate the polynomial at the given values in the coefficient ring of the polynomial. The result should be an element of the coefficient ring.

evaluate(f::MyMPoly{T}, A::Vector{U}) where {T <: RingElem, U <: Integer}

Evaluate the polynomial $f$ at the values specified by the entries of the array $A$.

(a::MyMPoly{T})(vals::Union{NCRingElem, RingElement}...) where T <: RingElement

Evaluate the polynomial at the given arguments. This provides functional notation for polynomial evaluation, i.e. $f(a, b, c)$. It must be defined for each supported polynomial type (Julia does not allow functional notation to be defined for an abstract type).

The code for this function in MPoly.jl can be used when implementing this as it provides the most general possible evaluation, which is much more general than the case of evaluation at elements of the same ring.

The evaluation should succeed for any set of values for which a multiplication is defined with the product of a coefficient and all the values before it.

Note

The values at which a polynomial is evaluated may be in non-commutative rings. Products are performed in the order of the variables in the polynomial ring that the polynomial belongs to, preceded by a multiplication by the coefficient on the left.

Derivations

The following function allows to compute derivations of multivariate polynomials of type MPoly.

derivative(f::MyMPoly{T}, j::Int) where T <: RingElem

Compute the derivative of $f$ with respect to the $j$-th variable of the polynomial ring.

diff --git a/v0.37.6/mpolynomial/index.html b/v0.37.6/mpolynomial/index.html new file mode 100644 index 0000000000..3d7b0a6662 --- /dev/null +++ b/v0.37.6/mpolynomial/index.html @@ -0,0 +1,479 @@ + +Sparse distributed multivariate polynomials · AbstractAlgebra.jl

Sparse distributed multivariate polynomials

AbstractAlgebra.jl provides a module, implemented in src/MPoly.jl for sparse distributed multivariate polynomials over any commutative ring belonging to the AbstractAlgebra abstract type hierarchy.

Generic sparse distributed multivariable polynomial types

AbstractAlgebra provides a generic multivariate polynomial type Generic.MPoly{T} where T is the type of elements of the coefficient ring.

The polynomials are implemented using a Julia array of coefficients and a 2-dimensional Julia array of UInts for the exponent vectors. Note that exponent $n$ is represented by the $n$-th column of the exponent array, not the $n$-th row. This is because Julia uses a column major representation. See the file src/generic/GenericTypes.jl for details.

The top bit of each UInt is reserved for overflow detection.

Parent objects of such polynomials have type Generic.MPolyRing{T}.

The string representation of the variables of the polynomial ring and the base/coefficient ring $R$ and the ordering are stored in the parent object.

Abstract types

The polynomial element types belong to the abstract type MPolyRingElem{T} and the polynomial ring types belong to the abstract type MPolyRing{T}.

Note

Note that both the generic polynomial ring type Generic.MPolyRing{T} and the abstract type it belongs to, MPolyRing{T} are both called MPolyRing. The former is a (parameterised) concrete type for a polynomial ring over a given base ring whose elements have type T. The latter is an abstract type representing all multivariate polynomial ring types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).

Polynomial ring constructors

In order to construct multivariate polynomials in AbstractAlgebra.jl, one must first construct the polynomial ring itself. This is accomplished with the following constructors.

AbstractAlgebra.polynomial_ringMethod
polynomial_ring(R::Ring, varnames::Vector{Symbol}; cached=true, ordering=:lex)

Given a coefficient ring R and variable names, say varnames = [:x1, :x2, ...], return a tuple S, [x1, x2, ...] of the polynomial ring $S = R[x1, x2, \dots]$ and its generators $x1, x2, \dots$.

By default (cached=true), the output S will be cached, i.e. if polynomial_ring is invoked again with the same arguments, the same (identical) ring is returned. Setting cached to false ensures a distinct new ring is returned, and will also prevent it from being cached.

The ordering of the polynomial ring can be one of :lex, :deglex or :degrevlex.

See also: polynomial_ring(::Ring, ::Vararg), @polynomial_ring.

Example

julia> S, generators = polynomial_ring(ZZ, [:x, :y, :z])
+(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y, z])
source
AbstractAlgebra.polynomial_ringMethod
polynomial_ring(R::Ring, varnames...; cached=true, ordering=:lex)
+polynomial_ring(R::Ring, varnames::Tuple; cached=true, ordering=:lex)

Like polynomial_ring(::Ring, ::Vector{Symbol}) with more ways to give varnames as specified in variable_names.

Return a tuple S, generators... with generators[i] corresponding to varnames[i].

Note

In the first method, varnames must not be empty, and if it consists of only one name, the univariate polynomial_ring(R::NCRing, s::VarName) method is called instead.

Examples

julia> S, (a, b, c) = polynomial_ring(ZZ, [:a, :b, :c])
+(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[a, b, c])
+
+julia> S, x, y = polynomial_ring(ZZ, :x => (1:2, 1:2), :y => 1:3);
+
+julia> S
+Multivariate polynomial ring in 7 variables x[1, 1], x[2, 1], x[1, 2], x[2, 2], ..., y[3]
+  over integers
+
+julia> x
+2×2 Matrix{AbstractAlgebra.Generic.MPoly{BigInt}}:
+ x[1, 1]  x[1, 2]
+ x[2, 1]  x[2, 2]
+
+julia> y
+3-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:
+ y[1]
+ y[2]
+ y[3]
source
AbstractAlgebra.polynomial_ringMethod
polynomial_ring(R::Ring, varnames...; cached=true, ordering=:lex)
+polynomial_ring(R::Ring, varnames::Tuple; cached=true, ordering=:lex)

Like polynomial_ring(::Ring, ::Vector{Symbol}) with more ways to give varnames as specified in variable_names.

Return a tuple S, generators... with generators[i] corresponding to varnames[i].

Note

In the first method, varnames must not be empty, and if it consists of only one name, the univariate polynomial_ring(R::NCRing, s::VarName) method is called instead.

Examples

julia> S, (a, b, c) = polynomial_ring(ZZ, [:a, :b, :c])
+(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[a, b, c])
+
+julia> S, x, y = polynomial_ring(ZZ, :x => (1:2, 1:2), :y => 1:3);
+
+julia> S
+Multivariate polynomial ring in 7 variables x[1, 1], x[2, 1], x[1, 2], x[2, 2], ..., y[3]
+  over integers
+
+julia> x
+2×2 Matrix{AbstractAlgebra.Generic.MPoly{BigInt}}:
+ x[1, 1]  x[1, 2]
+ x[2, 1]  x[2, 2]
+
+julia> y
+3-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:
+ y[1]
+ y[2]
+ y[3]
source
polynomial_ring(R::Ring, n::Int, s::Symbol=:x; cached=true, ordering=:lex)

Same as polynomial_ring(::Ring, ["s$i" for i in 1:n]).

Example

julia> S, x = polynomial_ring(ZZ, 3)
+(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x1, x2, x3])
source
AbstractAlgebra.@polynomial_ringMacro
@polynomial_ring(R::Ring, varnames...; cached=true, ordering=:lex)

Return polynomial ring from polynomial_ring(::Ring, ::Vararg) and introduce the generators into the current scope.

Examples

julia> S = @polynomial_ring(ZZ, "x#" => (1:2, 1:2), "y#" => 1:3)
+Multivariate polynomial ring in 7 variables x11, x21, x12, x22, ..., y3
+  over integers
+
+julia> x11, x21, x12, x22
+(x11, x21, x12, x22)
+
+julia> y1, y2, y3
+(y1, y2, y3)
+
+julia> (S, [x11 x12; x21 x22], [y1, y2, y3]) == polynomial_ring(ZZ, "x#" => (1:2, 1:2), "y#" => 1:3)
+true
source

Like for univariate polynomials, a shorthand constructor is provided when the number of generators is greater than 1: given a base ring R, we abbreviate the constructor as follows:

R["x", "y", ...]

Here are some examples of creating multivariate polynomial rings and making use of the resulting parent objects to coerce various elements into the polynomial ring.

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"]; ordering=:deglex)
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> T, (z, t) = QQ["z", "t"]
+(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[z, t])
+
+julia> f = R()
+0
+
+julia> g = R(123)
+123
+
+julia> h = R(BigInt(1234))
+1234
+
+julia> k = R(x + 1)
+x + 1
+
+julia> m = R(x + y + 1)
+x + y + 1
+
+julia> derivative(k, 1)
+1
+
+julia> derivative(k, 2)
+0
+
+julia> R, x = polynomial_ring(ZZ, 10); R
+Multivariate polynomial ring in 10 variables x1, x2, x3, x4, ..., x10
+  over integers
+

Polynomial constructors

Multivariate polynomials can be constructed from the generators in the usual way using arithmetic operations.

Also, all of the standard ring element constructors may be used to construct multivariate polynomials.

(R::MPolyRing{T})() where T <: RingElement
+(R::MPolyRing{T})(c::Integer) where T <: RingElement
+(R::MPolyRing{T})(a::elem_type(R)) where T <: RingElement
+(R::MPolyRing{T})(a::T) where T <: RingElement

For more efficient construction of multivariate polynomial, one can use the MPoly build context, where terms (coefficient followed by an exponent vector) are pushed onto a context one at a time and then the polynomial constructed from those terms in one go using the finish function.

AbstractAlgebra.Generic.push_term!Method
push_term!(M::MPolyBuildCtx, c::RingElem, v::Vector{Int})

Add the term with coefficient c and exponent vector v to the polynomial under construction in the build context M.

source
AbstractAlgebra.Generic.finishMethod
finish(M::MPolyBuildCtx)

Finish construction of the polynomial, sort the terms, remove duplicate and zero terms and return the created polynomial.

source

Note that the finish function resets the build context so that it can be used to construct multiple polynomials..

When a multivariate polynomial type has a representation that allows constant time access (e.g. it is represented internally by arrays), the following additional constructor is available. It takes and array of coefficients and and array of exponent vectors.

(S::MPolyRing{T})(A::Vector{T}, m::Vector{Vector{Int}}) where T <: RingElem

Create the polynomial in the given ring with nonzero coefficients specified by the elements of $A$ and corresponding exponent vectors given by the elements of $m$.

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> C = MPolyBuildCtx(R)
+Builder for an element of Multivariate polynomial ring in 2 variables over integers
+
+julia> push_term!(C, ZZ(3), [1, 2]);
+
+
+julia> push_term!(C, ZZ(2), [1, 1]);
+
+
+julia> push_term!(C, ZZ(4), [0, 0]);
+
+
+julia> f = finish(C)
+3*x*y^2 + 2*x*y + 4
+
+julia> push_term!(C, ZZ(4), [1, 1]);
+
+
+julia> f = finish(C)
+4*x*y
+
+julia> S, (x, y) = polynomial_ring(QQ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])
+
+julia> f = S(Rational{BigInt}[2, 3, 1], [[3, 2], [1, 0], [0, 1]])
+2*x^3*y^2 + 3*x + y

Functions for types and parents of multivariate polynomial rings

base_ring(R::MPolyRing)
+base_ring(a::MPolyRingElem)

Return the coefficient ring of the given polynomial ring or polynomial, respectively.

parent(a::MPolyRingElem)

Return the polynomial ring of the given polynomial.

characteristic(R::MPolyRing)

Return the characteristic of the given polynomial ring. If the characteristic is not known, an exception is raised.

Polynomial functions

Basic manipulation

All the standard ring functions are available, including the following.

zero(R::MPolyRing)
+one(R::MPolyRing)
+iszero(a::MPolyRingElem)
+isone(a::MPolyRingElem)
divexact(a::T, b::T) where T <: MPolyRingElem

All basic functions from the Multivariate Polynomial interface are provided.

symbols(S::MPolyRing)
+number_of_variables(f::MPolyRing)
+gens(S::MPolyRing)
+gen(S::MPolyRing, i::Int)
ordering(S::MPolyRing{T})

Note that the currently supported orderings are :lex, :deglex and :degrevlex.

length(f::MPolyRingElem)
+degrees(f::MPolyRingElem)
+total_degree(f::MPolyRingElem)
is_gen(x::MPolyRingElem)
divexact(f::T, g::T) where T <: MPolyRingElem

For multivariate polynomial types that allow constant time access to coefficients, the following are also available, allowing access to the given coefficient, monomial or term. Terms are numbered from the most significant first.

coeff(f::MPolyRingElem, n::Int)
+coeff(a::MPolyRingElem, exps::Vector{Int})

Access a coefficient by term number or exponent vector.

monomial(f::MPolyRingElem, n::Int)
+monomial!(m::T, f::T, n::Int) where T <: MPolyRingElem

The second version writes the result into a preexisting polynomial object to save an allocation.

term(f::MPolyRingElem, n::Int)
exponent(f::MyMPolyRingElem, i::Int, j::Int)

Return the exponent of the $j$-th variable in the $i$-th term of the polynomial $f$.

exponent_vector(a::MPolyRingElem, i::Int)
setcoeff!(a::MPolyRingElem{T}, exps::Vector{Int}, c::T) where T <: RingElement

Although multivariate polynomial rings are not usually Euclidean, the following functions from the Euclidean interface are often provided.

divides(f::T, g::T) where T <: MPolyRingElem
+remove(f::T, g::T) where T <: MPolyRingElem
+valuation(f::T, g::T) where T <: MPolyRingElem
divrem(f::T, g::T) where T <: MPolyRingElem
+div(f::T, g::T) where T <: MPolyRingElem

Compute a tuple $(q, r)$ such that $f = qg + r$, where the coefficients of terms of $r$ whose monomials are divisible by the leading monomial of $g$ are reduced modulo the leading coefficient of $g$ (according to the Euclidean function on the coefficients). The divrem version returns both quotient and remainder whilst the div version only returns the quotient.

Note that the result of these functions depend on the ordering of the polynomial ring.

gcd(f::T, g::T) where T <: MPolyRingElem

The following functionality is also provided for all multivariate polynomials.

AbstractAlgebra.is_univariateMethod
is_univariate(R::MPolyRing)

Returns true if $R$ is a univariate polynomial ring, i.e. has exactly one variable, and false otherwise.

source
AbstractAlgebra.varsMethod
vars(p::MPolyRingElem{T}) where {T <: RingElement}

Return the variables actually occurring in $p$.

source
AbstractAlgebra.var_indexMethod
var_index(p::MPolyRingElem{T}) where {T <: RingElement}

Return the index of the given variable $x$. If $x$ is not a variable in a multivariate polynomial ring, an exception is raised.

source
AbstractAlgebra.degreeMethod
degree(f::MPolyRingElem{T}, i::Int) where T <: RingElement

Return the degree of the polynomial $f$ in terms of the i-th variable.

source
AbstractAlgebra.degreeMethod
degree(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement

Return the degree of the polynomial $f$ in terms of the variable $x$.

source
AbstractAlgebra.degreesMethod
degrees(f::MPolyRingElem{T}) where T <: RingElement

Return an array of the degrees of the polynomial $f$ in terms of each variable.

source
AbstractAlgebra.is_constantMethod
is_constant(x::MPolyRingElem{T}) where T <: RingElement

Return true if x is a degree zero polynomial or the zero polynomial, i.e. a constant polynomial.

source
AbstractAlgebra.is_univariateMethod
is_univariate(p::MPolyRingElem)

Returns true if $p$ is a univariate polynomial, i.e. involves at most one variable (thus constant polynomials are considered univariate), and false otherwise. The result depends on the terms of the polynomial, not simply on the number of variables in the polynomial ring.

source
AbstractAlgebra.coeffMethod
coeff(f::MPolyRingElem{T}, m::MPolyRingElem{T}) where T <: RingElement

Return the coefficient of the monomial $m$ of the polynomial $f$. If there is no such monomial, zero is returned.

source

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = x^2 + 2x + 1
+x^2 + 2*x + 1
+
+julia> V = vars(f)
+1-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:
+ x
+
+julia> var_index(y) == 2
+true
+
+julia> degree(f, x) == 2
+true
+
+julia> degree(f, 2) == 0
+true
+
+julia> d = degrees(f)
+2-element Vector{Int64}:
+ 2
+ 0
+
+julia> is_constant(R(1))
+true
+
+julia> is_term(2x)
+true
+
+julia> is_monomial(y)
+true
+
+julia> is_unit(R(1))
+true
+
+julia> S, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = x^3*y + 3x*y^2 + 1
+x^3*y + 3*x*y^2 + 1
+
+julia> c1 = coeff(f, 1)
+1
+
+julia> c2 = coeff(f, x^3*y)
+1
+
+julia> m = monomial(f, 2)
+x*y^2
+
+julia> e1 = exponent(f, 1, 1)
+3
+
+julia> v1 = exponent_vector(f, 1)
+2-element Vector{Int64}:
+ 3
+ 1
+
+julia> t1 = term(f, 1)
+x^3*y
+
+julia> setcoeff!(f, [3, 1], 12)
+12*x^3*y + 3*x*y^2 + 1
+
+julia> S, (x, y) = polynomial_ring(QQ, ["x", "y"]; ordering=:deglex)
+(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])
+
+julia> V = symbols(S)
+2-element Vector{Symbol}:
+ :x
+ :y
+
+julia> X = gens(S)
+2-element Vector{AbstractAlgebra.Generic.MPoly{Rational{BigInt}}}:
+ x
+ y
+
+julia> ord = ordering(S)
+:deglex
+
+julia> S, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = x^3*y + 3x*y^2 + 1
+x^3*y + 3*x*y^2 + 1
+
+julia> n = length(f)
+3
+
+julia> is_gen(y)
+true
+
+julia> number_of_variables(S) == 2
+true
+
+julia> d = total_degree(f)
+4
+
+julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = 2x^2*y + 2x + y + 1
+2*x^2*y + 2*x + y + 1
+
+julia> g = x^2*y^2 + 1
+x^2*y^2 + 1
+
+julia> flag, q = divides(f*g, f)
+(true, x^2*y^2 + 1)
+
+julia> d = divexact(f*g, f)
+x^2*y^2 + 1
+
+julia> v, q = remove(f*g^3, g)
+(3, 2*x^2*y + 2*x + y + 1)
+
+julia> n = valuation(f*g^3, g)
+3
+
+julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])
+
+julia> f = 3x^2*y^2 + 2x + 1
+3*x^2*y^2 + 2*x + 1
+
+julia> f1 = divexact(f, 5)
+3//5*x^2*y^2 + 2//5*x + 1//5
+
+julia> f2 = divexact(f, QQ(2, 3))
+9//2*x^2*y^2 + 3*x + 3//2

Square root

Over rings for which an exact square root is available, it is possible to take the square root of a polynomial or test whether it is a square.

sqrt(f::MPolyRingElem, check::bool=true)
+is_square(::MPolyRingElem)

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = -4*x^5*y^4 + 5*x^5*y^3 + 4*x^4 - x^3*y^4
+-4*x^5*y^4 + 5*x^5*y^3 + 4*x^4 - x^3*y^4
+
+julia> sqrt(f^2)
+4*x^5*y^4 - 5*x^5*y^3 - 4*x^4 + x^3*y^4
+
+julia> is_square(f)
+false

Iterators

The following iterators are provided for multivariate polynomials.

coefficients(p::MPoly)
+monomials(p::MPoly)
+terms(p::MPoly)
+exponent_vectors(a::MPoly)

Examples

julia> S, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = x^3*y + 3x*y^2 + 1
+x^3*y + 3*x*y^2 + 1
+
+julia> C = collect(coefficients(f))
+3-element Vector{BigInt}:
+ 1
+ 3
+ 1
+
+julia> M = collect(monomials(f))
+3-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:
+ x^3*y
+ x*y^2
+ 1
+
+julia> T = collect(terms(f))
+3-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:
+ x^3*y
+ 3*x*y^2
+ 1
+
+julia> V = collect(exponent_vectors(f))
+3-element Vector{Vector{Int64}}:
+ [3, 1]
+ [1, 2]
+ [0, 0]

Changing base (coefficient) rings

In order to substitute the variables of a polynomial $f$ over a ring $T$ by elements in a $T$-algebra $S$, you first have to change the base ring of $f$ using the following function, where $g$ is a function representing the structure homomorphism of the $T$-algebra $S$.

AbstractAlgebra.change_base_ringMethod
change_base_ring(R::Ring, p::MPolyRingElem{<: RingElement}; parent::MPolyRing, cached::Bool=true)

Return the polynomial obtained by coercing the non-zero coefficients of p into R.

If the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.

source
AbstractAlgebra.change_coefficient_ringMethod
change_coefficient_ring(R::Ring, p::MPolyRingElem{<: RingElement}; parent::MPolyRing, cached::Bool=true)

Return the polynomial obtained by coercing the non-zero coefficients of p into R.

If the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.

source
AbstractAlgebra.map_coefficientsMethod
map_coefficients(f, p::MPolyRingElem{<: RingElement}; parent::MPolyRing)

Transform the polynomial p by applying f on each non-zero coefficient.

If the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.

source

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> fz = x^2*y^2 + x + 1
+x^2*y^2 + x + 1
+
+julia> fq = change_base_ring(QQ, fz)
+x^2*y^2 + x + 1
+
+julia> fq = change_coefficient_ring(QQ, fz)
+x^2*y^2 + x + 1
+

In case a specific parent ring is constructed, it can also be passed to the function.

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> S,  = polynomial_ring(QQ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])
+
+julia> fz = x^5 + y^3 + 1
+x^5 + y^3 + 1
+
+julia> fq = change_base_ring(QQ, fz, parent=S)
+x^5 + y^3 + 1

Multivariate coefficients

In order to return the "coefficient" (as a multivariate polynomial in the same ring), of a given monomial (in which some of the variables may not appear and others may be required to appear to exponent zero), we can use the following function.

AbstractAlgebra.coeffMethod
coeff(a::MPolyRingElem{T}, vars::Vector{Int}, exps::Vector{Int}) where T <: RingElement

Return the "coefficient" of $a$ (as a multivariate polynomial in the same ring) of the monomial consisting of the product of the variables of the given indices raised to the given exponents (note that not all variables need to appear and the exponents can be zero). E.g. coeff(f, [1, 3], [0, 2]) returns the coefficient of $x^0*z^2$ in the polynomial $f$ (assuming variables $x, y, z$ in that order).

source
AbstractAlgebra.coeffMethod
coeff(a::T, vars::Vector{T}, exps::Vector{Int}) where T <: MPolyRingElem

Return the "coefficient" of $a$ (as a multivariate polynomial in the same ring) of the monomial consisting of the product of the given variables to the given exponents (note that not all variables need to appear and the exponents can be zero). E.g. coeff(f, [x, z], [0, 2]) returns the coefficient of $x^0*z^2$ in the polynomial $f$.

source

Examples

julia> R, (x, y, z) = polynomial_ring(ZZ, ["x", "y", "z"])
+(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y, z])
+
+julia> f = x^4*y^2*z^2 - 2x^4*y*z^2 + 4x^4*z^2 + 2x^2*y^2 + x + 1
+x^4*y^2*z^2 - 2*x^4*y*z^2 + 4*x^4*z^2 + 2*x^2*y^2 + x + 1
+
+julia> coeff(f, [1, 3], [4, 2]) == coeff(f, [x, z], [4, 2])
+true
+

Inflation/deflation

AbstractAlgebra.deflationMethod
deflation(f::MPolyRingElem{T}) where T <: RingElement

Compute deflation parameters for the exponents of the polynomial $f$. This is a pair of arrays of integers, the first array of which (the shift) gives the minimum exponent for each variable of the polynomial, and the second of which (the deflation) gives the gcds of all the exponents after subtracting the shift, again per variable. This functionality is used by gcd (and can be used by factorisation algorithms).

source
AbstractAlgebra.deflateMethod
deflate(f::MPolyRingElem{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: RingElement

Return a polynomial with the same coefficients as $f$ but whose exponents have been reduced by the given shifts (supplied as an array of shifts, one for each variable), then deflated (divided) by the given exponents (again supplied as an array of deflation factors, one for each variable). The algorithm automatically replaces a deflation of $0$ by $1$, to avoid division by $0$.

source
AbstractAlgebra.deflateMethod
deflate(f::MPolyRingElem{T}, defl::Vector{Int}) where T <: RingElement

Return a polynomial with the same coefficients as $f$ but whose exponents have been deflated (divided) by the given exponents (supplied as an array of deflation factors, one for each variable).

The algorithm automatically replaces a deflation of $0$ by $1$, to avoid division by $0$.

source
AbstractAlgebra.deflateMethod
deflate(f::MPolyRingElem{T}, defl::Vector{Int}) where T <: RingElement

Return a polynomial with the same coefficients as $f$ but whose exponents have been deflated maximally, i.e. with each exponent divide by the largest integer which divides the degrees of all exponents of that variable in $f$.

source
AbstractAlgebra.deflateMethod
deflate(f::MPolyRingElem, vars::Vector{Int}, shift::Vector{Int}, defl::Vector{Int})

Return a polynomial with the same coefficients as $f$ but where exponents of some variables (supplied as an array of variable indices) have been reduced by the given shifts (supplied as an array of shifts), then deflated (divided) by the given exponents (again supplied as an array of deflation factors). The algorithm automatically replaces a deflation of $0$ by $1$, to avoid division by $0$.

source
AbstractAlgebra.deflateMethod
deflate(f::T, vars::Vector{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: MPolyRingElem

Return a polynomial with the same coefficients as $f$ but where the exponents of the given variables have been reduced by the given shifts (supplied as an array of shifts), then deflated (divided) by the given exponents (again supplied as an array of deflation factors). The algorithm automatically replaces a deflation of $0$ by $1$, to avoid division by $0$.

source
AbstractAlgebra.inflateMethod
inflate(f::MPolyRingElem{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: RingElement

Return a polynomial with the same coefficients as $f$ but whose exponents have been inflated (multiplied) by the given deflation exponents (supplied as an array of inflation factors, one for each variable) and then increased by the given shifts (again supplied as an array of shifts, one for each variable).

source
AbstractAlgebra.inflateMethod
inflate(f::MPolyRingElem{T}, defl::Vector{Int}) where T <: RingElement

Return a polynomial with the same coefficients as $f$ but whose exponents have been inflated (multiplied) by the given deflation exponents (supplied as an array of inflation factors, one for each variable).

source
AbstractAlgebra.inflateMethod
inflate(f::MPolyRingElem, vars::Vector{Int}, shift::Vector{Int}, defl::Vector{Int})

Return a polynomial with the same coefficients as $f$ but where exponents of some variables (supplied as an array of variable indices) have been inflated (multiplied) by the given deflation exponents (supplied as an array of inflation factors) and then increased by the given shifts (again supplied as an array of shifts).

source
AbstractAlgebra.inflateMethod
inflate(f::T, vars::Vector{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: MPolyRingElem

Return a polynomial with the same coefficients as $f$ but where the exponents of the given variables have been inflated (multiplied) by the given deflation exponents (supplied as an array of inflation factors) and then increased by the given shifts (again supplied as an array of shifts).

source

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = x^7*y^8 + 3*x^4*y^8 - x^4*y^2 + 5x*y^5 - x*y^2
+x^7*y^8 + 3*x^4*y^8 - x^4*y^2 + 5*x*y^5 - x*y^2
+
+julia> def, shift = deflation(f)
+([1, 2], [3, 3])
+
+julia> f1 = deflate(f, def, shift)
+x^2*y^2 + 3*x*y^2 - x + 5*y - 1
+
+julia> f2 = inflate(f1, def, shift)
+x^7*y^8 + 3*x^4*y^8 - x^4*y^2 + 5*x*y^5 - x*y^2
+
+julia> f2 == f
+true
+
+julia> g = (x+y+1)^2
+x^2 + 2*x*y + 2*x + y^2 + 2*y + 1
+
+julia> g0 = coeff(g, [y], [0])
+x^2 + 2*x + 1
+
+julia> g1 = deflate(g - g0, [y], [1], [1])
+2*x + y + 2
+
+julia> g == g0 + y * g1
+true
+

Conversions

AbstractAlgebra.to_univariateMethod
to_univariate(R::PolyRing{T}, p::MPolyRingElem{T}) where T <: RingElement

Assuming the polynomial $p$ is actually a univariate polynomial, convert the polynomial to a univariate polynomial in the given univariate polynomial ring $R$. An exception is raised if the polynomial $p$ involves more than one variable.

source

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> S, z = polynomial_ring(ZZ, "z")
+(Univariate polynomial ring in z over integers, z)
+
+julia> f = 2x^5 + 3x^4 - 2x^2 - 1
+2*x^5 + 3*x^4 - 2*x^2 - 1
+
+julia> g = to_univariate(S, f)
+2*z^5 + 3*z^4 - 2*z^2 - 1
+

Evaluation

The following function allows evaluation of a polynomial at all its variables. The result is always in the ring that a product of a coefficient and one of the values belongs to, i.e. if all the values are in the coefficient ring, the result of the evaluation will be too.

AbstractAlgebra.evaluateMethod
evaluate(a::MPolyRingElem{T}, vals::Vector{U}) where {T <: RingElement, U <: RingElement}

Evaluate the polynomial expression by substituting in the array of values for each of the variables. The evaluation will succeed if multiplication is defined between elements of the coefficient ring of $a$ and elements of the supplied vector.

source

The following functions allow evaluation of a polynomial at some of its variables. Note that the result will be a product of values and an element of the polynomial ring, i.e. even if all the values are in the coefficient ring and all variables are given values, the result will be a constant polynomial, not a coefficient.

AbstractAlgebra.evaluateMethod
evaluate(a::MPolyRingElem{T}, vars::Vector{Int}, vals::Vector{U}) where {T <: RingElement, U <: RingElement}

Evaluate the polynomial expression by substituting in the supplied values in the array vals for the corresponding variables with indices given by the array vars. The evaluation will succeed if multiplication is defined between elements of the coefficient ring of $a$ and elements of vals.

source
AbstractAlgebra.evaluateMethod
evaluate(a::S, vars::Vector{S}, vals::Vector{U}) where {S <: MPolyRingElem{T}, U <: RingElement} where T <: RingElement

Evaluate the polynomial expression by substituting in the supplied values in the array vals for the corresponding variables (supplied as polynomials) given by the array vars. The evaluation will succeed if multiplication is defined between elements of the coefficient ring of $a$ and elements of vals.

source

The following function allows evaluation of a polynomial at values in a not necessarily commutative ring, e.g. elements of a matrix algebra.

AbstractAlgebra.evaluateMethod
evaluate(a::MPolyRingElem{T}, vals::Vector{U}) where {T <: RingElement, U <: NCRingElem}

Evaluate the polynomial expression at the supplied values, which may be any ring elements, commutative or non-commutative, but in the same ring. Evaluation always proceeds in the order of the variables as supplied when creating the polynomial ring to which $a$ belongs. The evaluation will succeed if a product of a coefficient of the polynomial by one of the values is defined.

source

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = 2x^2*y^2 + 3x + y + 1
+2*x^2*y^2 + 3*x + y + 1
+
+julia> evaluate(f, BigInt[1, 2])
+14
+
+julia> evaluate(f, [QQ(1), QQ(2)])
+14//1
+
+julia> evaluate(f, [1, 2])
+14
+
+julia> f(1, 2) == 14
+true
+
+julia> evaluate(f, [x + y, 2y - x])
+2*x^4 - 4*x^3*y - 6*x^2*y^2 + 8*x*y^3 + 2*x + 8*y^4 + 5*y + 1
+
+julia> f(x + y, 2y - x)
+2*x^4 - 4*x^3*y - 6*x^2*y^2 + 8*x*y^3 + 2*x + 8*y^4 + 5*y + 1
+
+julia> R, (x, y, z) = polynomial_ring(ZZ, ["x", "y", "z"])
+(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y, z])
+
+julia> f = x^2*y^2 + 2x*z + 3y*z + z + 1
+x^2*y^2 + 2*x*z + 3*y*z + z + 1
+
+julia> evaluate(f, [1, 3], [3, 4])
+9*y^2 + 12*y + 29
+
+julia> evaluate(f, [x, z], [3, 4])
+9*y^2 + 12*y + 29
+
+julia> evaluate(f, [1, 2], [x + z, x - z])
+x^4 - 2*x^2*z^2 + 5*x*z + z^4 - z^2 + z + 1
+
+julia> S = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> M1 = S([1 2; 3 4])
+[1   2]
+[3   4]
+
+julia> M2 = S([2 3; 1 -1])
+[2    3]
+[1   -1]
+
+julia> M3 = S([-1 1; 1 1])
+[-1   1]
+[ 1   1]
+
+julia> evaluate(f, [M1, M2, M3])
+[ 64    83]
+[124   149]

Leading and constant coefficients, leading monomials and leading terms

The leading and trailing coefficient, constant coefficient, leading monomial and leading term of a polynomial p are returned by the following functions:

AbstractAlgebra.trailing_coefficientMethod
trailing_coefficient(p::MPolyRingElem)

Return the trailing coefficient of the polynomial $p$, i.e. the coefficient of the last nonzero term, or zero if the polynomial is zero.

source
AbstractAlgebra.leading_termMethod
leading_term(p::MPolyRingElem)

Return the leading term of the polynomial p. This function throws an ArgumentError if $p$ is zero.

source
AbstractAlgebra.tailMethod
tail(p::MPolyRingElem)

Return the tail of the polynomial $p$, i.e. the polynomial without its leading term (if any).

source

Examples

using AbstractAlgebra
+R,(x,y) = polynomial_ring(ZZ, ["x", "y"], ordering=:deglex)
+p = 2*x*y + 3*y^3 + 1
+leading_term(p)
+leading_monomial(p)
+leading_coefficient(p)
+leading_term(p) == leading_coefficient(p) * leading_monomial(p)
+constant_coefficient(p)
+tail(p)

Least common multiple, greatest common divisor

The greatest common divisor of two polynomials a and b is returned by

Base.gcdMethod
gcd(a::MPoly{T}, a::MPoly{T}) where {T <: RingElement}

Return the greatest common divisor of a and b in parent(a).

source

Note that this functionality is currently only provided for AbstractAlgebra generic polynomials. It is not automatically provided for all multivariate rings that implement the multivariate interface.

However, if such a gcd is provided, the least common multiple of two polynomials a and b is returned by

Base.lcmMethod
lcm(a::AbstractAlgebra.MPolyRingElem{T}, a::AbstractAlgebra.MPolyRingElem{T}) where {T <: RingElement}

Return the least common multiple of a and b in parent(a).

source

Examples

julia> using AbstractAlgebra
+
+julia> R,(x,y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> a = x*y + 2*y
+x*y + 2*y
+
+julia> b = x^3*y + y
+x^3*y + y
+
+julia> gcd(a,b)
+y
+
+julia> lcm(a,b)
+x^4*y + 2*x^3*y + x*y + 2*y
+
+julia> lcm(a,b) == a * b // gcd(a,b)
+true
+

Derivations

AbstractAlgebra.derivativeMethod
derivative(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement

Return the partial derivative of f with respect to x. The value x must be a generator of the polynomial ring of f.

source

Examples

julia> R, (x, y) = AbstractAlgebra.polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = x*y + x + y + 1
+x*y + x + y + 1
+
+julia> derivative(f, x)
+y + 1
+
+julia> derivative(f, y)
+x + 1
+
+julia> derivative(f, 1)
+y + 1
+
+julia> derivative(f, 2)
+x + 1

Homogeneous polynomials

It is possible to test whether a polynomial is homogeneous with respect to the standard grading using the function

Random generation

Random multivariate polynomials in a given ring can be constructed by passing a range of degrees for the variables and a range on the number of terms. Additional parameters are used to generate the coefficients of the polynomial.

Note that zero coefficients may currently be generated, leading to less than the requested number of terms.

rand(R::MPolyRing, exp_range::AbstractUnitRange{Int}, term_range::AbstractUnitRange{Int}, v...)

Examples

julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"])
+(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])
+
+julia> f = rand(R, -1:2, 3:5, -10:10)
+4*x^4*y^4
+
+julia> S, (s, t) = polynomial_ring(GF(7), ["x", "y"])
+(Multivariate polynomial ring in 2 variables over finite field F_7, AbstractAlgebra.Generic.MPoly{AbstractAlgebra.GFElem{Int64}}[x, y])
+
+julia> g = rand(S, -1:2, 3:5)
+4*x^3*y^4
diff --git a/v0.37.6/mseries/index.html b/v0.37.6/mseries/index.html new file mode 100644 index 0000000000..90111a38e8 --- /dev/null +++ b/v0.37.6/mseries/index.html @@ -0,0 +1,78 @@ + +Multivariate series · AbstractAlgebra.jl

Multivariate series

AbstractAlgebra.jl provide multivariate series over a commutative ring.

Series with capped absolute precision are provided with and without weights.

For the unweighted case precision in each variable can be set per series, but is capped at some maximum precision which is set when defining the ring.

For the weighted case, a single precision is set on the ring only. Terms are truncated at that precision (after applying weights).

Generic multivariate series

Generic multivariate series over a commutative ring, AbsMSeries{T} is implemented in src/generic/AbsMSeries.jl.

Such series are capped absolute series and have type Generic.AbsMSeries{T} where T is the type of elements of the coefficient ring.

Internally they consist of a multivariate polynomial. For unweighted series they also contain a vector of precisions, one for each variable.

For weighted series weights and a precision are stored on the ring only. The vector of precisions in the series objects is ignored.

See the file src/generic/GenericTypes.jl for details of the type.

The series are implemented in terms of multivariate polynomials which are used internally to keep track of the coefficients of the series.

Only lex ordering is provided at present both weighted and unweighted, though series print in reverse order to what multivariate polynomials would print, i.e. least significant term first, as would be expected for series.

Parent objects of such series have type Generic.AbsMSeriesRing{T}.

The symbol representation of the variables and the multivariate polynomial ring is stored in the parent object.

Abstract types

Multivariate series element types belong to the abstract type MSeriesElem{T} and the multivariate series ring types belong to the abstract type MSeriesRing{T}. This enables one to write generic functions that can accept any AbstractAlgebra multivariate series type.

Multivariate series ring constructors

In order to construct multivariate series in AbstractAlgebra.jl, one must first construct the series ring itself. This is accomplished with the following constructors.

For the unweighted case:

power_series_ring(R::Ring, prec::Vector{Int}, s::AbstractVector{<:VarName}; cached::Bool = true)

Given a base ring R and a vector of strings s specifying how the generators (variables) should be printed, along with a vector of precisions, one for each variable, return a tuple U, (x, y, ...) representing the new series ring $S$ and the generators $x, y, \ldots$ of the ring as a tuple. By default the parent object S will depend on R, the precision vector and the variable names x, y, ... and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

In the weighted case:

power_series_ring(R::Ring, weights::Vector{Int}, s::AbstractVector{<:VarName}, prec::Int; cached::Bool = true)

Given a base ring R and a vector of strings s specifying how the generators (variables) should be printed, along with a vector of weights, one for each variable and a bound on the (weighted) precision, return a tuple U, (x, y, ...) representing the new series ring $S$ and the generators $x, y, \ldots$ of the ring as a tuple. By default the parent object S will depend on R, the precision, the vector of weights and the variable names x, y, ... and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

Here are some examples of creating multivariate series rings and making use of the resulting parent objects to coerce various elements into the series ring.

Note that one can also use the function call O(x^n) with unweighted series to specify the precision in the variable x of a given series expression should be precision n.

Note

It is not possible to use x^0 in the O() function, since there is no distinction between x^0 and y^0 as far as the system is concerned. If one wishes to set the precision of a variable to precision 0, one must use the set_precision! function described below.

If one wants a series with the same precision in all variables, one can use O(R, n) where R is the series ring and n is the desired precision.

If all the precisions are to be the same, the vector of integers for the precisions can be replaced by a single integer in the constructor.

Examples

julia> R, (x, y) = power_series_ring(ZZ, [2, 3], ["x", "y"])
+(Multivariate power series ring in 2 variables over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(y^3) + O(x^2), y + O(y^3) + O(x^2)])
+
+julia> f = R()
+O(y^3) + O(x^2)
+
+julia> g = R(123)
+123 + O(y^3) + O(x^2)
+
+julia> h = R(BigInt(1234))
+1234 + O(y^3) + O(x^2)
+
+julia> k = R(x + 1)
+1 + x + O(y^3) + O(x^2)
+
+julia> m = x + y + O(y^2)
+y + x + O(y^2) + O(x^2)
+
+julia> R, (x, y) = power_series_ring(ZZ, 3, ["x", "y"])
+(Multivariate power series ring in 2 variables over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(y^3) + O(x^3), y + O(y^3) + O(x^3)])
+
+julia> n = x + y + O(R, 2)
+y + x + O(y^2) + O(x^2)
+
+julia> R, (x, y) = power_series_ring(ZZ, [2, 3], 10, ["x", "y"])
+(Multivariate power series ring in 2 variables over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(10), y + O(10)])
+
+julia> R()
+O(10)
+
+julia> R(x)
+x + O(10)

Basic ring functionality

Once a multivariate series ring is constructed, there are various ways to construct series in that ring.

The easiest way is simply using the generators returned by the power_series_ring constructor and build up the power series using basic arithmetic, as described in the Ring interface.

The power series rings in AbstractAlgebra.jl implement the full Ring interface.

We give some examples of such functionality.

Note

The divexact function can currently only divide by unit series (i.e. whose constant coefficient is invertible).

Examples

julia> R, (x,) = power_series_ring(ZZ, [5], ["x"])
+(Multivariate power series ring in 1 variable over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(x^5)])
+
+julia> f = x^3 + 3x + 21
+21 + 3*x + x^3 + O(x^5)
+
+julia> h = zero(R)
+O(x^5)
+
+julia> k = one(R)
+1 + O(x^5)
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> n = length(f)
+3
+
+julia> U = base_ring(R)
+Integers
+
+julia> v = symbols(R)
+1-element Vector{Symbol}:
+ :x
+
+julia> T = parent(x + 1)
+Multivariate power series ring in 1 variable x
+  over integers
+
+julia> f == deepcopy(f)
+true
+
+julia> t = divexact(f*x, 1 + x)
+21*x - 18*x^2 + 18*x^3 - 17*x^4 + O(x^5)
+
+julia> R, (x, y) = power_series_ring(ZZ, [2, 3], 10, ["x", "y"])
+(Multivariate power series ring in 2 variables over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(10), y + O(10)])
+
+julia> f = 3x^2*y + 1
+1 + 3*y*x^2 + O(10)
+
+julia> one(R)
+1 + O(10)

Power series functionality provided by AbstractAlgebra.jl

The functionality listed below is automatically provided by AbstractAlgebra.jl for absolute series over any commutative ring.

Basic functionality

The following are provided for weighted and unweighted series:

Base.precisionMethod
precision(a::AbsMSeries)

Return a vector of precisions, one for each variable in the series ring. If the ring is weighted the weighted precision is returned instead.

source
AbstractAlgebra.coeffMethod
coeff(a::AbsMSeries, n::Int)

Return the coefficient of the $n$-th nonzero term of the series (or zero if there are fewer than $n$ nonzero terms). Terms are numbered from the least significant term, i.e. the first term displayed when the series is printed.

source
AbstractAlgebra.genMethod
gen(R::AbsMSeriesRing, i::Int)

Return the $i$-th generator (variable) of the series ring $R$. Numbering starts from $1$ for the most significant variable.

source
AbstractAlgebra.gensMethod
gens(R::AbsMSeriesRing)

Return a vector of the generators (variables) of the series ring $R$, starting with the most significant.

source
AbstractAlgebra.is_unitMethod
is_unit(a::AbsMSeries)

Return true if the series is a unit in its series ring, i.e. if its constant term is a unit in the base ring.

source
Base.lengthMethod
length(a::AbsMSeries)

Return the number of nonzero terms in the series $a$.

source

The following are only available for unweighted series.

AbstractAlgebra.max_precisionMethod
max_precision(R::AbsMSeriesRing)

Return a vector of precision caps, one for each variable in the ring. Arithmetic operations will be performed to precisions not exceeding these values.

source

Iteration

AbstractAlgebra.coefficientsMethod
coefficients(a::AbsMSeries)

Return an array of the nonzero coefficients of the series, in the order they would be displayed, i.e. least significant term first.

source
AbstractAlgebra.exponent_vectorsMethod
exponent_vectors(a::AbsMSeries)

Return an array of the exponent vectors of the nonzero terms of the series, in the order they would be displayed, i.e. least significant term first.

source

Truncation

Base.truncateMethod
truncate(a::AbstractAlgebra.AbsMSeries, prec::Vector{Int})

Return $a$ truncated to (absolute) precisions given by the vector prec.

source
Base.truncateMethod
truncate(a::AbstractAlgebra.AbsMSeries, prec::Int)

Return $a$ truncated to precision prec. This either truncates by weight in the weighted cases or truncates each variable to precision prec in the unweighted case.

source

Exact division

AbstractAlgebra.divexactMethod
divexact(x::AbsMSeries{T}, y::AbsMSeries{T}; check::Bool=true) where T <: RingElement

Return the exact quotient of the series $x$ by the series $y$. This function currently assumes $y$ is an invertible series.

source

Evaluation

AbstractAlgebra.evaluateMethod
evaluate(a::U, vars::Vector{Int}, vals::Vector{U}) where {T <: RingElement, U <: AbsMSeries{T}}

Evaluate the series expression by substituting in the supplied values in the array vals for the corresponding variables with indices given by the array vars. The values must be in the same ring as $a$.

source
AbstractAlgebra.evaluateMethod
evaluate(a::U, vars::Vector{U}, vals::Vector{U}) where {T <: RingElement, U <: AbsMSeries{T}}

Evaluate the series expression by substituting in the supplied values in the array vals for the corresponding variables given by the array vars. The values must be in the same ring as $a$.

source
AbstractAlgebra.evaluateMethod
evaluate(a::U, vals::Vector{U}) where {T <: RingElement, U <: AbsMSeries{T}}

Evaluate the series expression by substituting in the supplied values in the array vals for the variables the series ring to which $a$ belongs. The values must be in the same ring as $a$.

source

Random generation

Base.randMethod
rand(S::MSeriesRing, term_range, v...)

Return a random element of the series ring $S$ with number of terms in the range given by term_range and where coefficients of the series are randomly generated in the base ring using the data given by v. The exponents of the variable in the terms will be less than the precision caps for the Ring $S$ when it was created.

source
diff --git a/v0.37.6/ncpolynomial/index.html b/v0.37.6/ncpolynomial/index.html new file mode 100644 index 0000000000..5e5950ba06 --- /dev/null +++ b/v0.37.6/ncpolynomial/index.html @@ -0,0 +1,213 @@ + +Univariate polynomials over a noncommutative ring · AbstractAlgebra.jl

Univariate polynomials over a noncommutative ring

AbstractAlgebra.jl provides a module, implemented in src/NCPoly.jl for univariate polynomials over any noncommutative ring in the AbstractAlgebra type hierarchy.

Generic type for univariate polynomials over a noncommutative ring

AbstractAlgebra.jl implements a generic univariate polynomial type over noncommutative rings in src/generic/NCPoly.jl.

These generic polynomials have type Generic.NCPoly{T} where T is the type of elements of the coefficient ring. Internally they consist of a Julia array of coefficients and some additional fields for length and a parent object, etc. See the file src/generic/GenericTypes.jl for details.

Parent objects of such polynomials have type Generic.NCPolyRing{T}.

The string representation of the variable of the polynomial ring and the base/coefficient ring $R$ is stored in the parent object.

Abstract types

The polynomial element types belong to the abstract type NCPolyRingElem{T} and the polynomial ring types belong to the abstract type NCPolyRing{T}. This enables one to write generic functions that can accept any AbstractAlgebra polynomial type.

Note

Note that both the generic polynomial ring type Generic.NCPolyRing{T} and the abstract type it belongs to, NCPolyRing{T} are both called NCPolyRing. The former is a (parameterised) concrete type for a polynomial ring over a given base ring whose elements have type T. The latter is an abstract type representing all polynomial ring types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).

Polynomial ring constructors

In order to construct polynomials in AbstractAlgebra.jl, one must first construct the polynomial ring itself. This is accomplished with the following constructor.

AbstractAlgebra.polynomial_ringMethod
polynomial_ring(R::NCRing, s::VarName = :x; cached::Bool = true)

Given a base ring R and symbol/string s specifying how the generator (variable) should be printed, return a tuple S, x representing the new polynomial ring $S = R[x]$ and the generator $x$ of the ring.

By default the parent object S depends only on R and x and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

Examples

julia> R, x = polynomial_ring(ZZ, :x)
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, :y)
+(Univariate polynomial ring in y over univariate polynomial ring, y)
source

A shorthand version of this function is provided: given a base ring R, we abbreviate the constructor as follows.

R["x"]

Here are some examples of creating polynomial rings and making use of the resulting parent objects to coerce various elements into the polynomial ring.

Examples

julia> R = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> S, x = polynomial_ring(R, "x")
+(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)
+
+julia> T, y = polynomial_ring(S, "y")
+(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)
+
+julia> U, z = R["z"]
+(Univariate polynomial ring in z over matrix ring of degree 2 over integers, z)
+
+julia> f = S()
+0
+
+julia> g = S(123)
+[123 0; 0 123]
+
+julia> h = T(BigInt(1234))
+[1234 0; 0 1234]
+
+julia> k = T(x + 1)
+x + 1
+
+julia> m = U(z + 1)
+z + 1
+

All of the examples here are generic polynomial rings, but specialised implementations of polynomial rings provided by external modules will also usually provide a polynomial_ring constructor to allow creation of their polynomial rings.

Basic ring functionality

Once a polynomial ring is constructed, there are various ways to construct polynomials in that ring.

The easiest way is simply using the generator returned by the polynomial_ring constructor and build up the polynomial using basic arithmetic, as described in the Ring interface.

The Julia language also has special syntax for the construction of polynomials in terms of a generator, e.g. we can write 2x instead of 2*x.

The polynomial rings in AbstractAlgebra.jl implement the full Ring interface. Of course the entire Univariate Polynomial Ring interface is also implemented.

We give some examples of such functionality.

Examples

julia> R = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> S, x = polynomial_ring(R, "x")
+(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)
+
+julia> T, y = polynomial_ring(S, "y")
+(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)
+
+julia> f = x^3 + 3x + 21
+x^3 + [3 0; 0 3]*x + [21 0; 0 21]
+
+julia> g = (x + 1)*y^2 + 2x + 1
+(x + 1)*y^2 + [2 0; 0 2]*x + 1
+
+julia> h = zero(T)
+0
+
+julia> k = one(S)
+1
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> n = length(g)
+3
+
+julia> U = base_ring(T)
+Univariate polynomial ring in x over matrix ring of degree 2 over integers
+
+julia> V = base_ring(y + 1)
+Univariate polynomial ring in x over matrix ring of degree 2 over integers
+
+julia> v = var(T)
+:y
+
+julia> U = parent(y + 1)
+Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers
+
+julia> g == deepcopy(g)
+true

Polynomial functionality provided by AbstractAlgebra.jl

The functionality listed below is automatically provided by AbstractAlgebra.jl for any polynomial module that implements the full Univariate Polynomial Ring interface over a noncommutative ring. This includes AbstractAlgebra.jl's own generic polynomial rings.

But if a C library provides all the functionality documented in the Univariate Polynomial Ring interface over a noncommutative ring, then all the functions described here will also be automatically supplied by AbstractAlgebra.jl for that polynomial type.

Of course, modules are free to provide specific implementations of the functions described here, that override the generic implementation.

Basic functionality

AbstractAlgebra.leading_coefficientMethod
leading_coefficient(a::PolynomialElem)

Return the leading coefficient of the given polynomial. This will be the nonzero coefficient of the term with highest degree unless the polynomial in the zero polynomial, in which case a zero coefficient is returned.

source
AbstractAlgebra.trailing_coefficientMethod
trailing_coefficient(a::PolynomialElem)

Return the trailing coefficient of the given polynomial. This will be the nonzero coefficient of the term with lowest degree unless the polynomial is the zero polynomial, in which case a zero coefficient is returned.

source
AbstractAlgebra.is_genMethod
is_gen(a::PolynomialElem)

Return true if the given polynomial is the constant generator of its polynomial ring, otherwise return false.

source

Examples

julia> R = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> S, x = polynomial_ring(R, "x")
+(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)
+
+julia> T, y = polynomial_ring(S, "y")
+(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)
+
+julia> a = zero(T)
+0
+
+julia> b = one(T)
+1
+
+julia> c = BigInt(1)*y^2 + BigInt(1)
+y^2 + 1
+
+julia> d = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + [3 0; 0 3]
+
+julia> f = leading_coefficient(d)
+x
+
+julia> y = gen(T)
+y
+
+julia> g = is_gen(y)
+true
+
+julia> m = is_unit(b)
+true
+
+julia> n = degree(d)
+2
+
+julia> is_term(2y^2)
+true
+
+julia> is_monomial(y^2)
+true
+

Truncation

Base.truncateMethod
truncate(a::PolynomialElem, n::Int)

Return $a$ truncated to $n$ terms, i.e. the remainder upon division by $x^n$.

source
AbstractAlgebra.mullowMethod
mullow(a::NCPolyRingElem{T}, b::NCPolyRingElem{T}, n::Int) where T <: NCRingElem

Return $a\times b$ truncated to $n$ terms.

source

Examples

julia> R = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> S, x = polynomial_ring(R, "x")
+(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)
+
+julia> T, y = polynomial_ring(S, "y")
+(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + [3 0; 0 3]
+
+julia> g = (x + 1)*y + (x^3 + 2x + 2)
+(x + 1)*y + x^3 + [2 0; 0 2]*x + [2 0; 0 2]
+
+julia> h = truncate(f, 1)
+[3 0; 0 3]
+
+julia> k = mullow(f, g, 4)
+(x^2 + x)*y^3 + (x^4 + [3 0; 0 3]*x^2 + [4 0; 0 4]*x + 1)*y^2 + (x^4 + x^3 + [2 0; 0 2]*x^2 + [7 0; 0 7]*x + [5 0; 0 5])*y + [3 0; 0 3]*x^3 + [6 0; 0 6]*x + [6 0; 0 6]
+

Reversal

Base.reverseMethod
reverse(x::PolynomialElem, len::Int)

Return the reverse of the polynomial $x$, thought of as a polynomial of the given length (the polynomial will be notionally truncated or padded with zeroes before the leading term if necessary to match the specified length). The resulting polynomial is normalised. If len is negative we throw a DomainError().

source
Base.reverseMethod
reverse(x::PolynomialElem)

Return the reverse of the polynomial $x$, i.e. the leading coefficient of $x$ becomes the constant coefficient of the result, etc. The resulting polynomial is normalised.

source

Examples

julia> R = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> S, x = polynomial_ring(R, "x")
+(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)
+
+julia> T, y = polynomial_ring(S, "y")
+(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + [3 0; 0 3]
+
+julia> g = reverse(f, 7)
+[3 0; 0 3]*y^6 + (x + 1)*y^5 + x*y^4
+
+julia> h = reverse(f)
+[3 0; 0 3]*y^2 + (x + 1)*y + x
+

Shifting

Examples

julia> R = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> S, x = polynomial_ring(R, "x")
+(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)
+
+julia> T, y = polynomial_ring(S, "y")
+(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + [3 0; 0 3]
+
+julia> g = shift_left(f, 7)
+x*y^9 + (x + 1)*y^8 + [3 0; 0 3]*y^7
+
+julia> h = shift_right(f, 2)
+x
+

Evaluation

AbstractAlgebra.evaluateMethod
evaluate(a::NCPolyRingElem, b::T) where T <: NCRingElem

Evaluate the polynomial $a$ at the value $b$ and return the result.

source
AbstractAlgebra.evaluateMethod
evaluate(a::NCPolyRingElem, b::Union{Integer, Rational, AbstractFloat})

Evaluate the polynomial $a$ at the value $b$ and return the result.

source

We also overload the functional notation so that the polynomial $f$ can be evaluated at $a$ by writing $f(a)$.

Examples

julia> R = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> S, x = polynomial_ring(R, "x")
+(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)
+
+julia> T, y = polynomial_ring(S, "y")
+(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)
+
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + [3 0; 0 3]
+
+julia> k = evaluate(f, 3)
+[12 0; 0 12]*x + [6 0; 0 6]
+
+julia> m = evaluate(f, x^2 + 2x + 1)
+x^5 + [4 0; 0 4]*x^4 + [7 0; 0 7]*x^3 + [7 0; 0 7]*x^2 + [4 0; 0 4]*x + [4 0; 0 4]
+
+julia> r = f(23)
+[552 0; 0 552]*x + [26 0; 0 26]
+

Derivative

Examples

julia> R = matrix_ring(ZZ, 2)
+Matrix ring of degree 2
+  over integers
+
+julia> S, x = polynomial_ring(R, "x")
+(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)
+
+julia> T, y = polynomial_ring(S, "y")
+(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + [3 0; 0 3]
+
+julia> h = derivative(f)
+[2 0; 0 2]*x*y + x + 1
+
diff --git a/v0.37.6/ncring_interface/index.html b/v0.37.6/ncring_interface/index.html new file mode 100644 index 0000000000..3443307017 --- /dev/null +++ b/v0.37.6/ncring_interface/index.html @@ -0,0 +1,3 @@ + +Noncommutative ring Interface · AbstractAlgebra.jl

Noncommutative ring Interface

AbstractAlgebra.jl supports commutative rings through its Ring interface. In this section we describe the corresponding interface for noncommutative rings. The two interfaces are very similar in terms of required functionality, and so we mainly document the differences here.

Noncommutative rings can be supported through the abstract types NCRing and NCRingElem. Note that we have Ring <: NCRing, etc., so the interface here should more correctly be called the Not-necessarily-Commutative-ring interface.

However, the fact remains that if one wishes to implement a noncommutative ring, one should make its type belong to NCRing but not to Ring. Therefore it is not too much of a mistake to think of the NCRing interface as being for noncommutative rings.

Types

As for the Ring interface, most noncommutative rings must supply two types:

  • a type for the parent object (representing the ring itself)
  • a type for elements of that ring

The parent type must belong to NCRing and the element type must belong to NCRingElem. Of course, the types may belong to these abstract types transitively via an intermediate abstract type.

Also as for the Ring interface, it is advised to make the types of generic parameterised rings that belong to NCRing and NCRingElem depend on the type of the elements of that parameter ring.

NCRingElement type union

As for the Ring interface, the NCRing interface provides a union type NCRingElement in src/julia/JuliaTypes.jl which is a union of NCRingElem and the Julia types Integer, Rational and AbstractFloat.

Most of the generic code in AbstractAlgebra for general rings makes use of the union type NCRingElement instead of NCRingElem so that the generic functions also accept the Julia Base ring types.

As per usual, one may need to implement one ad hoc binary operation for each concrete type belonging to NCRingElement to avoid ambiguity warnings.

Parent object caches

Parent object caches for the NCRing interface operate as per the Ring interface.

Required functions for all rings

Generic functions may only rely on required functionality for the NCRing interface, which must be implemented by all noncommutative rings.

Most of this required functionality is the same as for the Ring interface, so we refer the reader there for details, with the following modifications.

We give this interface for fictitious types MyParent for the type of the ring parent object R and MyElem for the type of the elements of the ring.

Exact division

divexact_left(f::MyElem, g::MyElem)
+divexact_right(f::MyElem, g::MyElem)

If $f = ga$ for some $a$ in the ring, the function divexact_left(f, g) returns a. If $f = ag$ then divexact_right(f, g) returns a. A DivideError() should be thrown if division is by zero. If no exact quotient exists or an impossible inverse is unavoidably encountered, an error should be thrown.

diff --git a/v0.37.6/perm/index.html b/v0.37.6/perm/index.html new file mode 100644 index 0000000000..2c6869fc71 --- /dev/null +++ b/v0.37.6/perm/index.html @@ -0,0 +1,188 @@ + +Permutations and Symmetric groups · AbstractAlgebra.jl

Permutations and Symmetric groups

AbstractAlgebra.jl provides rudimentary native support for permutation groups (implemented in src/generic/PermGroups.jl). All functionality of permutations is accessible in the Generic submodule.

Permutations are represented internally via vector of integers, wrapped in type Perm{T}, where T<:Integer carries the information on the type of elements of a permutation. Symmetric groups are singleton parent objects of type SymmetricGroup{T} and are used mostly to store the length of a permutation, since it is not included in the permutation type.

Symmetric groups are created using the SymmetricGroup (inner) constructor.

Both SymmetricGroup and Perm and can be parametrized by any type T<:Integer . By default the parameter is the Int-type native to the systems architecture. However, if you are sure that your permutations are small enough to fit into smaller integer type (such as Int32, UInt16, or even Int8), you may choose to change the parametrizing type accordingly. In practice this may result in decreased memory footprint (when storing multiple permutations) and noticeable faster performance, if your workload is heavy in operations on permutations, which e.g. does not fit into cache of your cpu.

All the permutation group types belong to the Group abstract type and the corresponding permutation element types belong to the GroupElem abstract type.

AbstractAlgebra.Generic.setpermstyleFunction
setpermstyle(format::Symbol)

Select the style in which permutations are displayed (in the REPL or in general as strings). This can be either

  • :array - as vector of integers whose $n$-th position represents the value at $n$), or
  • :cycles - as, more familiar for mathematicians, decomposition into disjoint cycles, where the value at $n$ is represented by the entry immediately following $n$ in a cycle (the default).

The difference is purely esthetical.

Examples

julia> setpermstyle(:array)
+:array
+
+julia> Perm([2,3,1,5,4])
+[2, 3, 1, 5, 4]
+
+julia> setpermstyle(:cycles)
+:cycles
+
+julia> Perm([2,3,1,5,4])
+(1,2,3)(4,5)
source

Permutations constructors

There are several methods to construct permutations in AbstractAlgebra.jl.

  • The easiest way is to directly call to the Perm (inner) constructor:
AbstractAlgebra.PermType
Perm{T<:Integer}

The type of permutations. Fieldnames:

  • d::Vector{T} - vector representing the permutation
  • modified::Bool - bit to check the validity of cycle decomposition
  • cycles::CycleDec{T} - (cached) cycle decomposition

A permutation $p$ consists of a vector (p.d) of $n$ integers from $1$ to $n$. If the $i$-th entry of the vector is $j$, this corresponds to $p$ sending $i \to j$. The cycle decomposition (p.cycles) is computed on demand and should never be accessed directly. Use cycles(p) instead.

There are two inner constructors of Perm:

  • Perm(n::T) constructs the trivial Perm{T}-permutation of length $n$.
  • Perm(v::AbstractVector{<:Integer} [,check=true]) constructs a permutation represented by v. By default Perm constructor checks if the vector constitutes a valid permutation. To skip the check call Perm(v, false).

Examples

julia> Perm([1,2,3])
+()
+   
+julia> g = Perm(Int32[2,3,1])
+(1,2,3)
+
+julia> typeof(g)
+Perm{Int32}
source

Since the parent object can be reconstructed from the permutation itself, you can work with permutations without explicitly constructing the parent object.

  • The other way is to first construct the permutation group they belong to. This is accomplished with the inner constructor SymmetricGroup(n::Integer) which constructs the permutation group on $n$ symbols and returns the parent object representing the group.
AbstractAlgebra.Generic.SymmetricGroupType
SymmetricGroup{T<:Integer}

The full symmetric group singleton type. SymmetricGroup(n) constructs the full symmetric group $S_n$ on $n$-symbols. The type of elements of the group is inferred from the type of n.

Examples

julia> G = SymmetricGroup(5)
+Full symmetric group over 5 elements
+
+julia> elem_type(G)
+Perm{Int64}
+
+julia> H = SymmetricGroup(UInt16(5))
+Full symmetric group over 5 elements
+
+julia> elem_type(H)
+Perm{UInt16}
source

A vector of integers can be then coerced to a permutation by calling a parent permutation group on it. The advantage is that the vector is automatically converted to the integer type fixed at the creation of the parent object.

Examples:

julia> G = SymmetricGroup(BigInt(5)); p = G([2,3,1,5,4])
+(1,2,3)(4,5)
+
+julia> typeof(p)
+Perm{BigInt}
+
+julia> H = SymmetricGroup(UInt16(5)); r = H([2,3,1,5,4])
+(1,2,3)(4,5)
+
+julia> typeof(r)
+Perm{UInt16}
+
+julia> one(H)
+()

By default the coercion checks for non-unique values in the vector, but this can be switched off with G([2,3,1,5,4], false).

  • Finally there is a perm"..." string macro to construct a permutation from a string input.
AbstractAlgebra.Generic.@perm_strMacro
perm"..."

String macro to parse disjoint cycles into Perm{Int}.

Strings for the output of GAP could be copied directly into perm"...". Cycles of length $1$ are not necessary, but can be included. A permutation of the minimal support is constructed, i.e. the maximal $n$ in the decomposition determines the parent group $S_n$.

Examples

julia> p = perm"(1,3)(2,4)"
+(1,3)(2,4)
+
+julia> typeof(p)
+Perm{Int64}
+
+julia> parent(p) == SymmetricGroup(4)
+true
+
+julia> p = perm"(1,3)(2,4)(10)"
+(1,3)(2,4)
+
+julia> parent(p) == SymmetricGroup(10)
+true
source

Permutation interface

The following basic functionality is provided by the default permutation group implementation in AbstractAlgebra.jl, to support construction of other generic constructions over permutation groups. Any custom permutation group implementation in AbstractAlgebra.jl should provide the group element arithmetic and comparison.

A custom implementation also needs to implement hash(::Perm, ::UInt) and (possibly) deepcopy_internal(::Perm, ::IdDict).

Note

Permutation group elements are mutable and so returning shallow copies is not sufficient.

getindex(a::Perm, n::Integer)

Allow access to entry $n$ of the given permutation via the syntax a[n]. Note that entries are $1$-indexed.

setindex!(a::Perm, d::Integer, n::Integer)

Set the $n$-th entry of the given permutation to $d$. This allows Julia to provide the syntax a[n] = d for setting entries of a permutation. Entries are $1$-indexed.

Note

Using setindex! invalidates the cycle decomposition cached in a permutation, which will be computed the next time it is needed.

Given the parent object G for a permutation group, the following coercion functions are provided to coerce various arguments into the permutation group. Developers provide these by overloading the permutation group parent objects.

one(G)

Return the identity permutation.

G(A::Vector{<:Integer})

Return the permutation whose entries are given by the elements of the supplied vector.

G(p::Perm)

Take a permutation that is already in the permutation group and simply return it. A copy of the original is not made if not necessary.

Basic manipulation

Numerous functions are provided to manipulate permutation group elements.

AbstractAlgebra.Generic.cyclesMethod
cycles(g::Perm)

Decompose permutation g into disjoint cycles.

Return a CycleDec object which iterates over disjoint cycles of g. The ordering of cycles is not guaranteed, and the order within each cycle is computed up to a cyclic permutation. The cycle decomposition is cached in g and used in future computation of permtype, parity, sign, order and ^ (powering).

Examples

julia> g = Perm([3,4,5,2,1,6])
+(1,3,5)(2,4)
+
+julia> collect(cycles(g))
+3-element Vector{Vector{Int64}}:
+ [1, 3, 5]
+ [2, 4]
+ [6]
source

Cycle structure is cached in a permutation, since once available, it provides a convenient shortcut in many other algorithms.

AbstractAlgebra.Generic.parityMethod
parity(g::Perm)

Return the parity of the given permutation, i.e. the parity of the number of transpositions in any decomposition of g into transpositions.

parity returns $1$ if the number is odd and $0$ otherwise. parity uses cycle decomposition of g if already available, but will not compute it on demand. Since cycle structure is cached in g you may call cycles(g) before calling parity.

Examples

julia> g = Perm([3,4,1,2,5])
+(1,3)(2,4)
+
+julia> parity(g)
+0
+
+julia> g = Perm([3,4,5,2,1,6])
+(1,3,5)(2,4)
+
+julia> parity(g)
+1
source
Base.signMethod
sign(g::Perm)

Return the sign of a permutation.

sign returns $1$ if g is even and $-1$ if g is odd. sign represents the homomorphism from the permutation group to the unit group of $\mathbb{Z}$ whose kernel is the alternating group.

Examples

julia> g = Perm([3,4,1,2,5])
+(1,3)(2,4)
+
+julia> sign(g)
+1
+
+julia> g = Perm([3,4,5,2,1,6])
+(1,3,5)(2,4)
+
+julia> sign(g)
+-1
source
AbstractAlgebra.Generic.permtypeMethod
permtype(g::Perm)

Return the type of permutation g, i.e. lengths of disjoint cycles in cycle decomposition of g.

The lengths are sorted in decreasing order by default. permtype(g) fully determines the conjugacy class of g.

Examples

julia> g = Perm([3,4,5,2,1,6])
+(1,3,5)(2,4)
+
+julia> permtype(g)
+3-element Vector{Int64}:
+ 3
+ 2
+ 1
+
+julia> e = one(g)
+()
+
+julia> permtype(e)
+6-element Vector{Int64}:
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
source

Note that even an Int64 can be easily overflowed when computing with symmetric groups. Thus, by default, order returns (always correct) BigInts. If you are sure that the computation will not overflow, you may use order(::Type{T}, ...) to perform computations with machine integers. Julia's standard promotion rules apply for the returned value.

Since SymmetricGroup implements the iterator protocol, you may iterate over all permutations via a simple loop:

for p in SymmetricGroup(n)
+   ...
+end

Iteration over all permutations in reasonable time, (i.e. in terms of minutes) is possible when $n ≤ 13$.

You may also use the non-allocating Generic.elements! function for $n ≤ 14$ (or even $15$ if you are patient enough), which is an order of magnitude faster.

AbstractAlgebra.Generic.elements!Method
Generic.elements!(G::SymmetricGroup)

Return an unsafe iterator over all permutations in G. Only one permutation is allocated and then modified in-place using the non-recursive Heaps algorithm.

Note: you need to explicitly copy permutations intended to be stored or modified.

Examples

julia> elts = Generic.elements!(SymmetricGroup(5));
+
+
+julia> length(elts)
+120
+
+julia> for p in Generic.elements!(SymmetricGroup(3))
+         println(p)
+       end
+()
+(1,2)
+(1,3,2)
+(2,3)
+(1,2,3)
+(1,3)
+
+julia> A = collect(Generic.elements!(SymmetricGroup(3))); A
+6-element Vector{Perm{Int64}}:
+ (1,3)
+ (1,3)
+ (1,3)
+ (1,3)
+ (1,3)
+ (1,3)
+
+julia> unique(A)
+1-element Vector{Perm{Int64}}:
+ (1,3)
source

However, since all permutations yielded by elements! are aliased (modified "in-place"), collect(Generic.elements!(SymmetricGroup(n))) returns a vector of identical permutations.

Note

If you intend to use or store elements yielded by elements! you need to deepcopy them explicitly.

Arithmetic operators

Base.:*Method
*(g::Perm, h::Perm)

Return the composition $h ∘ g$ of two permutations.

This corresponds to the action of permutation group on the set [1..n] on the right and follows the convention of GAP.

If g and h are parametrized by different types, the result is promoted accordingly.

Examples

julia> Perm([2,3,1,4])*Perm([1,3,4,2]) # (1,2,3)*(2,3,4)
+(1,3)(2,4)
source
Base.:^Method
^(g::Perm, n::Integer)

Return the $n$-th power of a permutation g.

By default g^n is computed by cycle decomposition of g if n > 3. Generic.power_by_squaring provides a different method for powering which may or may not be faster, depending on the particular case. Due to caching of the cycle structure, repeated powering of g will be faster with the default method.

Examples

julia> g = Perm([2,3,4,5,1])
+(1,2,3,4,5)
+
+julia> g^3
+(1,4,2,5,3)
+
+julia> g^5
+()
source
Base.invMethod
Base.inv(g::Perm)

Return the inverse of the given permutation, i.e. the permutation $g^{-1}$ such that $g ∘ g^{-1} = g^{-1} ∘ g$ is the identity permutation.

source

Permutations parametrized by different types can be multiplied, and follow the standard julia integer promotion rules:

g = rand(SymmetricGroup(Int8(5)));
+h = rand(SymmetricGroup(UInt32(5)));
+typeof(g*h)
+
+# output
+Perm{UInt32}

Coercion

The following coercions are available for G::SymmetricGroup parent objects. Each of the methods perform basic sanity checks on the input which can be switched off by the second argument.

Examples

(G::SymmetricGroup)(::AbstractVector{<:Integer}[, check=true])

Turn a vector of integers into a permutation (performing conversion, if necessary).

(G::SymmetricGroup)(::Perm[, check=true])

Coerce a permutation p into group G (performing the conversion, if necessary). If p is already an element of G no copy is performed.

(G::SymmetricGroup)(::String[, check=true])

Parse the string input e.g. copied from the output of GAP. The method uses the same logic as the perm"..." macro. The string is sanitized and checked for disjoint cycles. Both string(p::Perm) (if setpermstyle(:cycles)) and string(cycles(p::Perm)) are valid input for this method.

(G::SymmetricGroup{T})(::CycleDec{T}[, check=true]) where T

Turn a cycle decomposition object into a permutation.

Comparison

Base.:==Method
==(g::Perm, h::Perm)

Return true if permutations are equal, otherwise return false.

Permutations parametrized by different integer types are considered equal if they define the same permutation in the abstract permutation group.

Examples

julia> g = Perm(Int8[2,3,1])
+(1,2,3)
+
+julia> h = perm"(3,1,2)"
+(1,2,3)
+
+julia> g == h
+true
source
Base.:==Method
==(G::SymmetricGroup, H::SymmetricGroup)

Return true if permutation groups are equal, otherwise return false.

Permutation groups on the same number of letters, but parametrized by different integer types are considered different.

Examples

julia> G = SymmetricGroup(UInt(5))
+Permutation group over 5 elements
+
+julia> H = SymmetricGroup(5)
+Permutation group over 5 elements
+
+julia> G == H
+false
source

Misc

Base.randMethod
rand([rng=GLOBAL_RNG,] G::SymmetricGroup)

Return a random permutation from G.

source
AbstractAlgebra.Generic.matrix_reprMethod
matrix_repr(a::Perm)

Return the permutation matrix as a sparse matrix representing a via natural embedding of the permutation group into the general linear group over $\mathbb{Z}$.

Examples

julia> p = Perm([2,3,1])
+(1,2,3)
+
+julia> matrix_repr(p)
+3×3 SparseArrays.SparseMatrixCSC{Int64, Int64} with 3 stored entries:
+ ⋅  1  ⋅
+ ⋅  ⋅  1
+ 1  ⋅  ⋅
+
+julia> Array(ans)
+3×3 Matrix{Int64}:
+ 0  1  0
+ 0  0  1
+ 1  0  0
source
matrix_repr(Y::YoungTableau)

Construct sparse integer matrix representing the tableau.

Examples

julia> y = YoungTableau([4,3,1]);
+
+
+julia> matrix_repr(y)
+3×4 SparseArrays.SparseMatrixCSC{Int64, Int64} with 8 stored entries:
+ 1  2  3  4
+ 5  6  7  ⋅
+ 8  ⋅  ⋅  ⋅
source
AbstractAlgebra.Generic.embMethod
emb(G::SymmetricGroup, V::Vector{Int}, check::Bool=true)

Return the natural embedding of a permutation group into G as the subgroup permuting points indexed by V.

Examples

julia> p = Perm([2,3,1])
+(1,2,3)
+
+julia> f = Generic.emb(SymmetricGroup(5), [3,2,5]);
+
+
+julia> f(p)
+(2,5,3)
source
AbstractAlgebra.Generic.emb!Method
emb!(result::Perm, p::Perm, V)

Embed permutation p into permutation result on the indices given by V.

This corresponds to the natural embedding of $S_k$ into $S_n$ as the subgroup permuting points indexed by V.

Examples

julia> p = Perm([2,1,4,3])
+(1,2)(3,4)
+
+julia> Generic.emb!(Perm(collect(1:5)), p, [3,1,4,5])
+(1,3)(4,5)
source
diff --git a/v0.37.6/poly_interface/index.html b/v0.37.6/poly_interface/index.html new file mode 100644 index 0000000000..dd65b85326 --- /dev/null +++ b/v0.37.6/poly_interface/index.html @@ -0,0 +1,4 @@ + +Univariate Polynomial Ring Interface · AbstractAlgebra.jl

Univariate Polynomial Ring Interface

Univariate polynomial rings are supported in AbstractAlgebra, and in addition to the standard Ring interface, numerous additional functions are required to be present for univariate polynomial rings.

Univariate polynomial rings can be built over both commutative and noncommutative rings.

Univariate polynomial rings over a field are also Euclidean and therefore such rings must implement the Euclidean interface.

Since a sparse distributed multivariate format can generally also handle sparse univariate polynomials, the univariate polynomial interface is designed around the assumption that they are dense. This is not a requirement, but it may be easier to use the multivariate interface for sparse univariate types.

Types and parents

AbstractAlgebra provides two abstract types for polynomial rings and their elements over a commutative ring:

  • PolyRing{T} is the abstract type for univariate polynomial ring parent types
  • PolyRingElem{T} is the abstract type for univariate polynomial types

Similarly there are two abstract types for polynomial rings and their elements over a noncommutative ring:

  • NCPolyRing{T} is the abstract type for univariate polynomial ring parent types
  • NCPolyRingElem{T} is the abstract type for univariate polynomial types

We have that PolyRing{T} <: Ring and PolyRingElem{T} <: RingElem. Similarly we have that NCPolyRing{T} <: NCRing and NCPolyRingElem{T} <: NCRingElem.

Note that the abstract types are parameterised. The type T should usually be the type of elements of the coefficient ring of the polynomial ring. For example, in the case of $\mathbb{Z}[x]$ the type T would be the type of an integer, e.g. BigInt.

If the parent object for such a ring has type MyZX and polynomials in that ring have type MyZXPoly then one would have:

  • MyZX <: PolyRing{BigInt}
  • MyZXPoly <: PolyRingElem{BigInt}

Polynomial rings should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Polynomial rings should at least be distinguished based on their base (coefficient) ring. But if they have the same base ring and symbol (for their variable/generator), they should certainly have the same parent object.

See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).

Required functionality for univariate polynomials

In addition to the required functionality for the Ring/NCRing interface (and in the case of polynomials over a field, the Euclidean Ring interface), the Polynomial Ring interface has the following required functions.

We suppose that R is a fictitious base ring (coefficient ring) and that S is a univariate polynomial ring over R (i.e. $S = R[x]$) with parent object S of type MyPolyRing{T}. We also assume the polynomials in the ring have type MyPoly{T}, where T is the type of elements of the base (coefficient) ring.

Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.

Note that the type T must (transitively) belong to the abstract type RingElem or NCRingElem.

We describe the functionality below for polynomials over commutative rings, i.e. with element type belonging to RingElem, however similar constructors should be available for element types belonging to NCRingElem instead, if the coefficient ring is noncommutative.

Constructors

In addition to the standard constructors, the following constructors, taking an array of coefficients, must be available.

(S::MyPolyRing{T})(A::Vector{T}) where T <: RingElem
+(S::MyPolyRing{T})(A::Vector{U}) where T <: RingElem, U <: RingElem
+(S::MyPolyRing{T})(A::Vector{U}) where T <: RingElem, U <: Integer

Create the polynomial in the given ring whose degree $i$ coefficient is given by A[1 + i]. The elements of the array are assumed to be able to be coerced into the base ring R. If the argument is an empty vector, the zero polynomial shall be returned.

It may be desirable to have a additional version of the function that accepts an array of Julia Int values if this can be done more efficiently.

It is also possible to create polynomials directly without first creating the corresponding polynomial ring.

polynomial(R::Ring, arr::Vector{T}, var::VarName=:x; cached::Bool=true)

Given an array of coefficients construct the polynomial with those coefficients over the given ring and with the given variable.

Note

If cached is set to false then the parent ring of the created polynomial is not cached. However, this means that subsequent polynomials created in the same way will not be compatible. Instead, one should use the parent object of the first polynomial to create subsequent polynomials instead of calling this function repeatedly with cached=false.

Data type and parent object methods

var(S::MyPolyRing{T}) where T <: RingElem

Return a Symbol representing the variable (generator) of the polynomial ring. Note that this is a Symbol not a String, though its string value will usually be used when printing polynomials.

symbols(S::MyPolyRing{T}) where T <: RingElem

Return the array [s] where s is a Symbol representing the variable of the given polynomial ring. This is provided for uniformity with the multivariate interface, where there is more than one variable and hence an array of symbols.

dense_poly_type(::Type{T}) where T <: RingElement

Return the type of a polynomial whose coefficients have the given type. In our example MyPoly{T}.

This function is defined for generic polynomials and only needs to be defined for custom polynomial rings, e.g. ones defined by a C implementation.

The default implementation figures out the appropriate polynomial ring type via dense_poly_type and calls its constructor with R, s, cached as arguments. In our example, this would be

MyPolyRing{T}(R, s, cached)

Accordingly, polynomial_ring_only only needs to be defined, if such a constructor does not exist or other behaviour is wanted.

Basic manipulation of rings and elements

length(f::MyPoly{T}) where T <: RingElem

Return the length of the given polynomial. The length of the zero polynomial is defined to be $0$, otherwise the length is the degree plus $1$. The return value should be of type Int.

set_length!(f::MyPoly{T}, n::Int) where T <: RingElem

This function must zero any coefficients beyond the requested length $n$ and then set the length of the polynomial to $n$. This function does not need to normalise the polynomial and is not useful to the user, but is used extensively by the AbstractAlgebra generic functionality.

This function returns the resulting polynomial.

coeff(f::MyPoly{T}, n::Int) where T <: RingElem

Return the coefficient of the polynomial f of degree n. If n is larger than the degree of the polynomial, it should return zero in the coefficient ring.

setcoeff!(f::MyPoly{T}, n::Int, a::T) where T <: RingElem

Set the degree $n$ coefficient of $f$ to $a$. This mutates the polynomial in-place if possible and returns the mutated polynomial (so that immutable types can also be supported). The function must not assume that the polynomial already has space for $n + 1$ coefficients. The polynomial must be resized if this is not the case.

Note that this function is not required to normalise the polynomial and is not necessarily useful to the user, but is used extensively by the generic functionality in AbstractAlgebra.jl. It is for setting raw coefficients in the representation.

normalise(f::MyPoly{T}, n::Int) where T <: RingElem

Given a polynomial whose length is currently $n$, including any leading zero coefficients, return the length of the normalised polynomial (either zero or the length of the polynomial with nonzero leading coefficient). Note that the function does not actually perform the normalisation.

fit!(f::MyPoly{T}, n::Int) where T <: RingElem

Ensure that the polynomial $f$ internally has space for $n$ coefficients. This function must mutate the function in-place if it is mutable. It does not return the mutated polynomial. Immutable types can still be supported by defining this function to do nothing.

Some interfaces for C polynomial types automatically manage the internal allocation of polynomials in every function that can be called on them. Explicit adjustment by the generic code in AbstractAlgebra.jl is not required. In such cases, this function can also be defined to do nothing.

Optional functionality for polynomial rings

Sometimes parts of the Euclidean Ring interface can and should be implemented for polynomials over a ring that is not necessarily a field.

When divisibility testing can be implemented for a polynomial ring over a field, it should be possible to implement the following functions from the Euclidean Ring interface:

  • divides
  • remove
  • valuation

When the given polynomial ring is a GCD domain, with an effective GCD algorithm, it may be possible to implement the following functions:

  • gcd
  • lcm

Polynomial rings can optionally implement any part of the generic univariate polynomial functionality provided by AbstractAlgebra.jl, using the same interface.

Obviously additional functionality can also be added to that provided by AbstractAlgebra.jl on an ad hoc basis.

Similar

The similar function is available for all univariate polynomial types, but new polynomial rings can define a specialised version of it if required.

similar(x::MyPoly{T}, R::Ring=base_ring(x), var::VarName=var(parent(x))) where T <: RingElem

Construct the zero polynomial with the given variable and coefficients in the given ring, if specified, and with the defaults shown if not.

Custom polynomial rings may choose which polynomial type is best-suited to return for any given arguments. If they don't specialise the function the default polynomial type returned is a Generic.Poly.

diff --git a/v0.37.6/polynomial/index.html b/v0.37.6/polynomial/index.html new file mode 100644 index 0000000000..b1ac73ed16 --- /dev/null +++ b/v0.37.6/polynomial/index.html @@ -0,0 +1,505 @@ + +Univariate polynomial functionality · AbstractAlgebra.jl

Univariate polynomial functionality

AbstractAlgebra.jl provides a module, implemented in src/Poly.jl for polynomials over any commutative ring belonging to the AbstractAlgebra abstract type hierarchy. This functionality will work for any univariate polynomial type which follows the Univariate Polynomial Ring interface.

Generic univariate polynomial types

AbstractAlgebra.jl provides a generic polynomial type based on Julia arrays which is implemented in src/generic/Poly.jl.

These generic polynomials have type Generic.Poly{T} where T is the type of elements of the coefficient ring. Internally they consist of a Julia array of coefficients and some additional fields for length and a parent object, etc. See the file src/generic/GenericTypes.jl for details.

Parent objects of such polynomials have type Generic.PolyRing{T}.

The string representation of the variable of the polynomial ring and the base/coefficient ring $R$ is stored in the parent object.

Abstract types

All univariate polynomial element types belong to the abstract type PolyRingElem{T} and the polynomial ring types belong to the abstract type PolyRing{T}. This enables one to write generic functions that can accept any AbstractAlgebra polynomial type.

Note

Both the generic polynomial ring type Generic.PolyRing{T} and the abstract type it belongs to, PolyRing{T}, are called PolyRing. The former is a (parameterised) concrete type for a polynomial ring over a given base ring whose elements have type T. The latter is an abstract type representing all polynomial ring types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).

Polynomial ring constructors

In order to construct polynomials in AbstractAlgebra.jl, one must first construct the polynomial ring itself. This is accomplished with the following constructor.

AbstractAlgebra.polynomial_ringMethod
polynomial_ring(R::NCRing, s::VarName = :x; cached::Bool = true)

Given a base ring R and symbol/string s specifying how the generator (variable) should be printed, return a tuple S, x representing the new polynomial ring $S = R[x]$ and the generator $x$ of the ring.

By default the parent object S depends only on R and x and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

Examples

julia> R, x = polynomial_ring(ZZ, :x)
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, :y)
+(Univariate polynomial ring in y over univariate polynomial ring, y)
source

A shorthand version of this function is provided: given a base ring R, we abbreviate the constructor as follows.

R[:x]

It is also possible to create a polynomial ring with default symbol as follows. This is a lightweight constructor and should be used in generic algorithms wherever possible when creating polynomial rings where the symbol does not matter.

PolyRing(R::Ring)

Given a base ring R return the polynomial ring $S = R[x]$. Note that unlike the constructors above, the return type is not a tuple. Only the ring is returned and not the generator. The polynomial ring is not cached.

Here are some examples of creating polynomial rings and their associated generators.

Examples

julia> T, z = QQ["z"]
+(Univariate polynomial ring in z over rationals, z)
+
+julia> U = PolyRing(ZZ)
+Univariate polynomial ring in x over integers

All of the examples here are generic polynomial rings, but specialised implementations of polynomial rings provided by external modules will also usually provide a polynomial_ring constructor to allow creation of their polynomial rings.

Polynomial constructors

Once a polynomial ring is constructed, there are various ways to construct polynomials in that ring.

The easiest way is simply using the generator returned by the polynomial_ring constructor and build up the polynomial using basic arithmetic.

The Julia language has special syntax for the construction of polynomials in terms of a generator, e.g. we can write 2x instead of 2*x.

A second way is to use the polynomial ring to construct a polynomial. There are the usual ways of constructing an element of a ring.

(R::PolyRing)() # constructs zero
+(R::PolyRing)(c::Integer)
+(R::PolyRing)(c::elem_type(R))
+(R::PolyRing{T})(a::T) where T <: RingElement

For polynommials there is also the following more general constructor accepting an array of coefficients.

(S::PolyRing{T})(A::Vector{T}) where T <: RingElem
+(S::PolyRing{T})(A::Vector{U}) where T <: RingElem, U <: RingElem
+(S::PolyRing{T})(A::Vector{U}) where T <: RingElem, U <: Integer

Construct the polynomial in the ring S with the given array of coefficients, i.e. where A[1] is the constant coefficient.

A third way of constructing polynomials is to construct them directly without creating the polynomial ring.

polynomial(R::Ring, arr::Vector{T}, var::VarName=:x; cached::Bool=true)

Given an array of coefficients construct the polynomial with those coefficients over the given ring and with the given variable.

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> f = x^3 + 3x + 21
+x^3 + 3*x + 21
+
+julia> g = (x + 1)*y^2 + 2x + 1
+(x + 1)*y^2 + 2*x + 1
+
+julia> R()
+0
+
+julia> S(1)
+1
+
+julia> S(y)
+y
+
+julia> S(x)
+x
+
+julia> S, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> f = S(Rational{BigInt}[2, 3, 1])
+x^2 + 3*x + 2
+
+julia> g = S(BigInt[1, 0, 4])
+4*x^2 + 1
+
+julia> h = S([4, 7, 2, 9])
+9*x^3 + 2*x^2 + 7*x + 4
+
+julia> p = polynomial(ZZ, [1, 2, 3])
+3*x^2 + 2*x + 1
+
+julia> f = polynomial(ZZ, [1, 2, 3], "y")
+3*y^2 + 2*y + 1

Similar and zero

Another way of constructing polynomials is to construct one similar to an existing polynomial using either similar or zero.

similar(x::MyPoly{T}, R::Ring=base_ring(x)) where T <: RingElem
+zero(x::MyPoly{T}, R::Ring=base_ring(x)) where T <: RingElem

Construct the zero polynomial with the same variable as the given polynomial with coefficients in the given ring. Both functions behave the same way for polynomials.

similar(x::MyPoly{T}, R::Ring, var::VarName=var(parent(x))) where T <: RingElem
+similar(x::MyPoly{T}, var::VarName=var(parent(x))) where T <: RingElem
+zero(x::MyPoly{T}, R::Ring, var::VarName=var(parent(x))) where T <: RingElem
+zero(x::MyPoly{T}, var::VarName=var(parent(x))) where T <: RingElem

Construct the zero polynomial with the given variable and coefficients in the given ring, if specified, and in the coefficient ring of the given polynomial otherwise.

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> f = 1 + 2x + 3x^2
+3*x^2 + 2*x + 1
+
+julia> g = similar(f)
+0
+
+julia> h = similar(f, QQ)
+0
+
+julia> k = similar(f, QQ, "y")
+0

Functions for types and parents of polynomial rings

base_ring(R::PolyRing)
+base_ring(a::PolyRingElem)

Return the coefficient ring of the given polynomial ring or polynomial.

parent(a::NCRingElement)

Return the polynomial ring of the given polynomial..

characteristic(R::NCRing)

Return the characteristic of the given polynomial ring. If the characteristic is not known, an exception is raised.

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> U = base_ring(S)
+Univariate polynomial ring in x over integers
+
+julia> V = base_ring(y + 1)
+Univariate polynomial ring in x over integers
+
+julia> T = parent(y + 1)
+Univariate polynomial ring in y over univariate polynomial ring

Euclidean polynomial rings

For polynomials over a field, the Euclidean Ring Interface is implemented.

mod(f::PolyRingElem, g::PolyRingElem)
+divrem(f::PolyRingElem, g::PolyRingElem)
+div(f::PolyRingElem, g::PolyRingElem)
mulmod(f::PolyRingElem, g::PolyRingElem, m::PolyRingElem)
+powermod(f::PolyRingElem, e::Int, m::PolyRingElem)
+invmod(f::PolyRingElem, m::PolyRingElem)
divides(f::PolyRingElem, g::PolyRingElem)
+remove(f::PolyRingElem, p::PolyRingElem)
+valuation(f::PolyRingElem, p::PolyRingElem)
gcd(f::PolyRingElem, g::PolyRingElem)
+lcm(f::PolyRingElem, g::PolyRingElem)
+gcdx(f::PolyRingElem, g::PolyRingElem)
+gcdinv(f::PolyRingElem, g::PolyRingElem)

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S, = residue_ring(R, x^3 + 3x + 1);
+
+julia> T, y = polynomial_ring(S, "y")
+(Univariate polynomial ring in y over residue ring, y)
+
+julia> f = (3*x^2 + x + 2)*y + x^2 + 1
+(3*x^2 + x + 2)*y + x^2 + 1
+
+julia> g = (5*x^2 + 2*x + 1)*y^2 + 2x*y + x + 1
+(5*x^2 + 2*x + 1)*y^2 + 2*x*y + x + 1
+
+julia> h = (3*x^3 + 2*x^2 + x + 7)*y^5 + 2x*y + 1
+(2*x^2 - 8*x + 4)*y^5 + 2*x*y + 1
+
+julia> invmod(f, g)
+(707//3530*x^2 + 2151//1765*x + 123//3530)*y - 178//1765*x^2 - 551//3530*x + 698//1765
+
+julia> mulmod(f, g, h)
+(-30*x^2 - 43*x - 9)*y^3 + (-7*x^2 - 23*x - 7)*y^2 + (4*x^2 - 10*x - 3)*y + x^2 - 2*x
+
+julia> powermod(f, 3, h)
+(69*x^2 + 243*x + 79)*y^3 + (78*x^2 + 180*x + 63)*y^2 + (27*x^2 + 42*x + 18)*y + 3*x^2 + 3*x + 2
+
+julia> h = mod(f, g)
+(3*x^2 + x + 2)*y + x^2 + 1
+
+julia> q, r = divrem(f, g)
+(0, (3*x^2 + x + 2)*y + x^2 + 1)
+
+julia> div(g, f)
+(-5//11*x^2 + 2//11*x + 6//11)*y - 13//121*x^2 - 3//11*x - 78//121
+
+julia> d = gcd(f*h, g*h)
+y + 1//11*x^2 + 6//11
+
+julia> k = gcdinv(f, h)
+(y + 1//11*x^2 + 6//11, 0)
+
+julia> m = lcm(f, h)
+(-14*x^2 - 23*x - 2)*y - 4*x^2 - 5*x + 1
+
+julia> flag, q = divides(g^2, g)
+(true, (5*x^2 + 2*x + 1)*y^2 + 2*x*y + x + 1)
+
+julia> valuation(3g^3, g) == 3
+true
+
+julia> val, q = remove(5g^3, g)
+(3, 5)
+
+julia> r, s, t = gcdx(g, h)
+(1, 311//3530*x^2 - 2419//3530*x + 947//1765, (707//3530*x^2 + 2151//1765*x + 123//3530)*y - 178//1765*x^2 - 551//3530*x + 698//1765)
+

Functions in the Euclidean Ring interface are supported over residue rings that are not fields, except that if an impossible inverse is encountered during the computation an error is thrown.

Polynomial functions

Basic functionality

All basic ring functionality is provided for polynomials. The most important such functions are the following.

zero(R::PolyRing)
+one(R::PolyRing)
+iszero(a::PolyRingElem)
+isone(a::PolyRingElem)
divexact(a::T, b::T) where T <: PolyRingElem

All functions in the polynomial interface are provided. The most important are the following.

var(S::PolyRing)
+symbols(S::PolyRing{T}) where T <: RingElem

Return a symbol or length 1 array of symbols, respectively, specifying the variable of the polynomial ring. This symbol is converted to a string when printing polynomials in that ring.

In addition, the following basic functions are provided.

AbstractAlgebra.modulusMethod
modulus(a::PolyRingElem{T}) where {T <: ResElem}

Return the modulus of the coefficients of the given polynomial.

source
AbstractAlgebra.leading_coefficientMethod
leading_coefficient(a::PolynomialElem)

Return the leading coefficient of the given polynomial. This will be the nonzero coefficient of the term with highest degree unless the polynomial in the zero polynomial, in which case a zero coefficient is returned.

source
leading_coefficient(p::MPolyRingElem)

Return the leading coefficient of the polynomial $p$.

source
AbstractAlgebra.trailing_coefficientMethod
trailing_coefficient(a::PolynomialElem)

Return the trailing coefficient of the given polynomial. This will be the nonzero coefficient of the term with lowest degree unless the polynomial is the zero polynomial, in which case a zero coefficient is returned.

source
trailing_coefficient(p::MPolyRingElem)

Return the trailing coefficient of the polynomial $p$, i.e. the coefficient of the last nonzero term, or zero if the polynomial is zero.

source
AbstractAlgebra.constant_coefficientMethod
constant_coefficient(a::PolynomialElem)

Return the constant coefficient of the given polynomial. If the polynomial is the zero polynomial, the function will return zero.

source
AbstractAlgebra.set_coefficient!Method
set_coefficient!(c::PolynomialElem{T}, n::Int, a::T) where T <: RingElement
+set_coefficient!(c::PolynomialElem{T}, n::Int, a::U) where {T <: RingElement, U <: Integer}

Set the coefficient of degree $n$ to $a$.

source
AbstractAlgebra.tailMethod
tail(a::PolynomialElem)

Return the tail of the given polynomial, i.e. the polynomial without its leading term (if any).

source
AbstractAlgebra.genMethod
gen(a::MPolyRing{T}, i::Int) where {T <: RingElement}

Return the $i$-th generator (variable) of the given polynomial ring.

source
gen(R::AbsPowerSeriesRing{T}) where T <: RingElement

Return the generator of the power series ring, i.e. $x + O(x^n)$ where $n$ is the precision of the power series ring $R$.

source
AbstractAlgebra.is_genMethod
is_gen(a::PolynomialElem)

Return true if the given polynomial is the constant generator of its polynomial ring, otherwise return false.

source
is_gen(x::MPoly{T}) where {T <: RingElement}

Return true if the given polynomial is a generator (variable) of the polynomial ring it belongs to.

source
AbstractAlgebra.is_monicMethod
is_monic(a::PolynomialElem)

Return true if the given polynomial is monic, i.e. has leading coefficient equal to one, otherwise return false.

source
AbstractAlgebra.is_squareMethod
is_square(f::PolyRingElem{T}) where T <: RingElement

Return true if $f$ is a perfect square.

source
is_square(a::FracElem{T}) where T <: RingElem

Return true if $a$ is a square.

source
Base.lengthMethod
length(a::PolynomialElem)

Return the length of the polynomial. The length of a univariate polynomial is defined to be the number of coefficients in its dense representation, including zero coefficients. Thus naturally the zero polynomial has length zero and additionally for nonzero polynomials the length is one more than the degree. (Note that the leading coefficient will always be nonzero.)

source
AbstractAlgebra.degreeMethod
degree(a::PolynomialElem)

Return the degree of the given polynomial. This is defined to be one less than the length, even for constant polynomials.

source
AbstractAlgebra.is_monomialMethod
is_monomial(a::PolynomialElem)

Return true if the given polynomial is a monomial.

source
is_monomial(x::MPolyRingElem)

Return true if the given polynomial has precisely one term whose coefficient is one.

source
AbstractAlgebra.is_termMethod
is_term(a::PolynomialElem)

Return true if the given polynomial has one term.

source
is_term(x::MPolyRingElem)

Return true if the given polynomial has precisely one term.

source
AbstractAlgebra.is_term_recursiveMethod
is_term_recursive(a::PolynomialElem)

Return true if the given polynomial has one term. This function is recursive, with all scalar types returning true.

source
AbstractAlgebra.is_constantMethod
is_constant(a::PolynomialElem)

Return true if a is a degree zero polynomial or the zero polynomial, i.e. a constant polynomial.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> T, z = polynomial_ring(QQ, "z")
+(Univariate polynomial ring in z over rationals, z)
+
+julia> U, = residue_ring(ZZ, 17);
+
+julia> V, w = polynomial_ring(U, "w")
+(Univariate polynomial ring in w over residue ring, w)
+
+julia> var(R)
+:x
+
+julia> symbols(R)
+1-element Vector{Symbol}:
+ :x
+
+julia> a = zero(S)
+0
+
+julia> b = one(S)
+1
+
+julia> isone(b)
+true
+
+julia> c = BigInt(1)//2*z^2 + BigInt(1)//3
+1//2*z^2 + 1//3
+
+julia> d = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + 3
+
+julia> f = leading_coefficient(d)
+x
+
+julia> y = gen(S)
+y
+
+julia> g = is_gen(w)
+true
+
+julia> divexact((2x + 1)*(x + 1), (x + 1))
+2*x + 1
+
+julia> m = is_unit(b)
+true
+
+julia> n = degree(d)
+2
+
+julia> r = modulus(w)
+17
+
+julia> is_term(2y^2)
+true
+
+julia> is_monomial(y^2)
+true
+
+julia> is_monomial_recursive(x*y^2)
+true
+
+julia> is_monomial(x*y^2)
+false
+
+julia> S, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> f = x^3 + 3x + 1
+x^3 + 3*x + 1
+
+julia> g = S(BigInt[1, 2, 0, 1, 0, 0, 0]);
+
+julia> n = length(f)
+4
+
+julia> c = coeff(f, 1)
+3
+
+julia> g = set_coefficient!(g, 2, ZZ(11))
+x^3 + 11*x^2 + 2*x + 1
+
+julia> g = set_coefficient!(g, 7, ZZ(4))
+4*x^7 + x^3 + 11*x^2 + 2*x + 1

Iterators

An iterator is provided to return the coefficients of a univariate polynomial. The iterator is called coefficients and allows iteration over the coefficients, starting with the term of degree zero (if there is one). Note that coefficients of each degree are given, even if they are zero. This is best illustrated by example.

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> f = x^2 + 2
+x^2 + 2
+
+julia> C = collect(coefficients(f))
+3-element Vector{BigInt}:
+ 2
+ 0
+ 1
+
+julia> for c in coefficients(f)
+          println(c)
+       end
+2
+0
+1

Truncation

Base.truncateMethod
truncate(a::PolynomialElem, n::Int)

Return $a$ truncated to $n$ terms, i.e. the remainder upon division by $x^n$.

source
AbstractAlgebra.mullowMethod
mullow(a::PolyRingElem{T}, b::PolyRingElem{T}, n::Int) where T <: RingElement

Return $a\times b$ truncated to $n$ terms.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + 3
+
+julia> g = (x + 1)*y + (x^3 + 2x + 2)
+(x + 1)*y + x^3 + 2*x + 2
+
+julia> h = truncate(f, 1)
+3
+
+julia> k = mullow(f, g, 4)
+(x^2 + x)*y^3 + (x^4 + 3*x^2 + 4*x + 1)*y^2 + (x^4 + x^3 + 2*x^2 + 7*x + 5)*y + 3*x^3 + 6*x + 6
+

Reversal

Base.reverseMethod
reverse(x::PolynomialElem, len::Int)

Return the reverse of the polynomial $x$, thought of as a polynomial of the given length (the polynomial will be notionally truncated or padded with zeroes before the leading term if necessary to match the specified length). The resulting polynomial is normalised. If len is negative we throw a DomainError().

source
Base.reverseMethod
reverse(x::PolynomialElem)

Return the reverse of the polynomial $x$, i.e. the leading coefficient of $x$ becomes the constant coefficient of the result, etc. The resulting polynomial is normalised.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + 3
+
+julia> g = reverse(f, 7)
+3*y^6 + (x + 1)*y^5 + x*y^4
+
+julia> h = reverse(f)
+3*y^2 + (x + 1)*y + x
+

Shifting

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + 3
+
+julia> g = shift_left(f, 7)
+x*y^9 + (x + 1)*y^8 + 3*y^7
+
+julia> h = shift_right(f, 2)
+x
+

Inflation and deflation

AbstractAlgebra.deflationMethod
deflation(p::PolyRingElem)

Return a tuple (shift, defl) where shift is the exponent of the trailing term of $p$ and defl is the gcd of the distance between the exponents of the nonzero terms of $p$. If $p = 0$, both shift and defl will be zero.

source
AbstractAlgebra.inflateMethod
inflate(f::PolyRingElem, shift::Int64, n::Int64) -> PolyRingElem

Given a polynomial $f$ in $x$, return $f(x^n)*x^j$, i.e. multiply all exponents by $n$ and shift $f$ left by $j$.

source
AbstractAlgebra.inflateMethod
inflate(f::PolyRingElem, n::Int64) -> PolyRingElem

Given a polynomial $f$ in $x$, return $f(x^n)$, i.e. multiply all exponents by $n$.

source
AbstractAlgebra.deflateMethod
deflate(f::PolyRingElem, shift::Int64, n::Int64) -> PolyRingElem

Given a polynomial $g$ in $x^n$ such that f = g(x)*x^{shift}, write $f$ as a polynomial in $x$, i.e. divide all exponents of $g$ by $n$.

source
AbstractAlgebra.deflateMethod
deflate(f::PolyRingElem, n::Int64) -> PolyRingElem

Given a polynomial $f$ in $x^n$, write it as a polynomial in $x$, i.e. divide all exponents by $n$.

source
AbstractAlgebra.deflateMethod
deflate(x::PolyRingElem) -> PolyRingElem, Int

Deflate the polynomial $f$ maximally, i.e. find the largest $n$ s.th. $f$ can be deflated by $n$, i.e. $f$ is actually a polynomial in $x^n$. Return $g, n$ where $g$ is the deflation of $f$.

source

Square root

Base.sqrtMethod
Base.sqrt(f::PolyRingElem{T}; check::Bool=true) where T <: RingElement

Return the square root of $f$. By default the function checks the input is square and raises an exception if not. If check=false this check is omitted.

source
sqrt(a::Generic.PuiseuxSeriesElem{T}; check::Bool=true) where T <: RingElement

Return the square root of the given Puiseux series $a$. By default the function will throw an exception if the input is not square. If check=false this test is omitted.

source

Examples

R, x = polynomial_ring(ZZ, "x")
+g = x^2+6*x+1
+sqrt(g^2)

Change of base ring

AbstractAlgebra.change_base_ringMethod
change_base_ring(R::Ring, p::PolyRingElem{<: RingElement}; parent::PolyRing)

Return the polynomial obtained by coercing the non-zero coefficients of p into R.

If the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.

source
AbstractAlgebra.change_coefficient_ringMethod
change_coefficient_ring(R::Ring, p::PolyRingElem{<: RingElement}; parent::PolyRing)

Return the polynomial obtained by coercing the non-zero coefficients of p into R.

If the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.

source
AbstractAlgebra.map_coefficientsMethod
map_coefficients(f, p::PolyRingElem{<: RingElement}; cached::Bool=true, parent::PolyRing)

Transform the polynomial p by applying f on each non-zero coefficient.

If the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.

source

Examples

R, x = polynomial_ring(ZZ, "x")
+g = x^3+6*x + 1
+change_base_ring(GF(2), g)
+change_coefficient_ring(GF(2), g)

Pseudodivision

Given two polynomials $a, b$, pseudodivision computes polynomials $q$ and $r$ with length$(r) <$ length$(b)$ such that $L^d a = bq + r,$ where $d =$ length$(a) -$ length$(b) + 1$ and $L$ is the leading coefficient of $b$.

We call $q$ the pseudoquotient and $r$ the pseudoremainder.

AbstractAlgebra.pseudoremMethod
pseudorem(f::PolyRingElem{T}, g::PolyRingElem{T}) where T <: RingElement

Return the pseudoremainder of $f$ divided by $g$. If $g = 0$ we throw a DivideError().

source
AbstractAlgebra.pseudodivremMethod
pseudodivrem(f::PolyRingElem{T}, g::PolyRingElem{T}) where T <: RingElement

Return a tuple $(q, r)$ consisting of the pseudoquotient and pseudoremainder of $f$ divided by $g$. If $g = 0$ we throw a DivideError().

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + 3
+
+julia> g = (x + 1)*y + (x^3 + 2x + 2)
+(x + 1)*y + x^3 + 2*x + 2
+
+julia> h = pseudorem(f, g)
+x^7 + 3*x^5 + 2*x^4 + x^3 + 5*x^2 + 4*x + 1
+
+julia> q, r = pseudodivrem(f, g)
+((x^2 + x)*y - x^4 - x^2 + 1, x^7 + 3*x^5 + 2*x^4 + x^3 + 5*x^2 + 4*x + 1)
+

Content and primitive part

Examples

R, x = polynomial_ring(ZZ, "x")
+S, y = polynomial_ring(R, "y")
+
+k = x*y^2 + (x + 1)*y + 3
+
+n = content(k)
+p = primpart(k*(x^2 + 1))

Evaluation, composition and substitution

AbstractAlgebra.evaluateMethod
evaluate(a::PolyRingElem, b::T) where T <: RingElement

Evaluate the polynomial expression $a$ at the value $b$ and return the result.

source
AbstractAlgebra.composeMethod
compose(a::PolyRingElem, b::PolyRingElem)

Compose the polynomial $a$ with the polynomial $b$ and return the result, i.e. return $a\circ b$.

source
AbstractAlgebra.substMethod
subst(f::PolyRingElem{T}, a::Any) where T <: RingElement

Evaluate the polynomial $f$ at $a$. Note that $a$ can be anything, whether a ring element or not.

source

We also overload the functional notation so that the polynomial $f$ can be evaluated at $a$ by writing $f(a)$.

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + 3
+
+julia> g = (x + 1)*y + (x^3 + 2x + 2)
+(x + 1)*y + x^3 + 2*x + 2
+
+julia> M = R[x + 1 2x; x - 3 2x - 1]
+[x + 1       2*x]
+[x - 3   2*x - 1]
+
+julia> k = evaluate(f, 3)
+12*x + 6
+
+julia> m = evaluate(f, x^2 + 2x + 1)
+x^5 + 4*x^4 + 7*x^3 + 7*x^2 + 4*x + 4
+
+julia> n = compose(f, g)
+(x^3 + 2*x^2 + x)*y^2 + (2*x^5 + 2*x^4 + 4*x^3 + 9*x^2 + 6*x + 1)*y + x^7 + 4*x^5 + 5*x^4 + 5*x^3 + 10*x^2 + 8*x + 5
+
+julia> p = subst(f, M)
+[3*x^3 - 3*x^2 + 3*x + 4       6*x^3 + 2*x^2 + 2*x]
+[3*x^3 - 8*x^2 - 2*x - 3   6*x^3 - 8*x^2 + 2*x + 2]
+
+julia> q = f(M)
+[3*x^3 - 3*x^2 + 3*x + 4       6*x^3 + 2*x^2 + 2*x]
+[3*x^3 - 8*x^2 - 2*x - 3   6*x^3 - 8*x^2 + 2*x + 2]
+
+julia> r = f(23)
+552*x + 26
+

Derivative and integral

AbstractAlgebra.derivativeMethod
derivative(a::PolynomialElem)

Return the derivative of the polynomial $a$.

source
derivative(f::AbsPowerSeriesRingElem{T})

Return the derivative of the power series $f$.

source
derivative(f::RelPowerSeriesRingElem{T})

Return the derivative of the power series $f$.

julia> R, x = power_series_ring(QQ, 10, "x")
+(Univariate power series ring in x over Rationals, x + O(x^11))
+
+julia> f = 2 + x + 3x^3
+2 + x + 3*x^3 + O(x^10)
+
+julia> derivative(f)
+1 + 9*x^2 + O(x^9)
source
derivative(f::MPolyRingElem{T}, j::Int) where {T <: RingElement}

Return the partial derivative of f with respect to $j$-th variable of the polynomial ring.

source
derivative(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement

Return the partial derivative of f with respect to x. The value x must be a generator of the polynomial ring of f.

source
derivative(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the derivative of the given Puiseux series $a$.

source
AbstractAlgebra.integralMethod
integral(x::PolyRingElem{T}) where {T <: Union{ResElem, FieldElement}}

Return the integral of the polynomial $x$.

source
integral(f::AbsPowerSeriesRingElem{T})

Return the integral of the power series $f$.

source
integral(f::RelPowerSeriesRingElem{T})

Return the integral of the power series $f$.

julia> R, x = power_series_ring(QQ, 10, "x")
+(Univariate power series ring in x over Rationals, x + O(x^11))
+
+julia> f = 2 + x + 3x^3
+2 + x + 3*x^3 + O(x^10)
+
+julia> integral(f)
+2*x + 1//2*x^2 + 3//4*x^4 + O(x^11)
source
integral(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the integral of the given Puiseux series $a$.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> T, z = polynomial_ring(QQ, "z")
+(Univariate polynomial ring in z over rationals, z)
+
+julia> U, = residue_ring(T, z^3 + 3z + 1);
+
+julia> V, w = polynomial_ring(U, "w")
+(Univariate polynomial ring in w over residue ring, w)
+
+julia> f = x*y^2 + (x + 1)*y + 3
+x*y^2 + (x + 1)*y + 3
+
+julia> g = (z^2 + 2z + 1)*w^2 + (z + 1)*w - 2z + 4
+(z^2 + 2*z + 1)*w^2 + (z + 1)*w - 2*z + 4
+
+julia> h = derivative(f)
+2*x*y + x + 1
+
+julia> k = integral(g)
+(1//3*z^2 + 2//3*z + 1//3)*w^3 + (1//2*z + 1//2)*w^2 + (-2*z + 4)*w
+

Resultant and discriminant

AbstractAlgebra.resultantMethod
resultant(p::PolyRingElem{T}, q::PolyRingElem{T}) where T <: RingElement

Return the resultant of the given polynomials.

source
AbstractAlgebra.resxMethod
resx(a::PolyRingElem{T}, b::PolyRingElem{T}) where T <: RingElement

Return a tuple $(r, s, t)$ such that $r$ is the resultant of $a$ and $b$ and such that $r = a\times s + b\times t$.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> f = 3x*y^2 + (x + 1)*y + 3
+3*x*y^2 + (x + 1)*y + 3
+
+julia> g = 6(x + 1)*y + (x^3 + 2x + 2)
+(6*x + 6)*y + x^3 + 2*x + 2
+
+julia> S = sylvester_matrix(f, g)
+[    3*x           x + 1               3]
+[6*x + 6   x^3 + 2*x + 2               0]
+[      0         6*x + 6   x^3 + 2*x + 2]
+
+julia> h = resultant(f, g)
+3*x^7 + 6*x^5 - 6*x^3 + 96*x^2 + 192*x + 96
+
+julia> k = discriminant(f)
+x^2 - 34*x + 1
+

Newton representation

AbstractAlgebra.monomial_to_newton!Method
monomial_to_newton!(P::Vector{T}, roots::Vector{T}) where T <: RingElement

Converts a polynomial $p$, given as an array of coefficients, in-place from its coefficients given in the standard monomial basis to the Newton basis for the roots $r_0, r_1, \ldots, r_{n-2}$. In other words, this determines output coefficients $c_i$ such that $c_0 + c_1(x-r_0) + c_2(x-r_0)(x-r_1) + \ldots + c_{n-1}(x-r_0)(x-r_1)\cdots(x-r_{n-2})$ is equal to the input polynomial.

source
AbstractAlgebra.newton_to_monomial!Method
newton_to_monomial!(P::Vector{T}, roots::Vector{T}) where T <: RingElement

Converts a polynomial $p$, given as an array of coefficients, in-place from its coefficients given in the Newton basis for the roots $r_0, r_1, \ldots, r_{n-2}$ to the standard monomial basis. In other words, this evaluates $c_0 + c_1(x-r_0) + c_2(x-r_0)(x-r_1) + \ldots + c_{n-1}(x-r_0)(x-r_1)\cdots(x-r_{n-2})$ where $c_i$ are the input coefficients given by $p$.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> f = 3x*y^2 + (x + 1)*y + 3
+3*x*y^2 + (x + 1)*y + 3
+
+julia> g = deepcopy(f)
+3*x*y^2 + (x + 1)*y + 3
+
+julia> roots = [R(1), R(2), R(3)]
+3-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:
+ 1
+ 2
+ 3
+
+julia> monomial_to_newton!(g.coeffs, roots)
+
+julia> newton_to_monomial!(g.coeffs, roots)

Roots

Interpolation

AbstractAlgebra.interpolateMethod
interpolate(S::PolyRing, x::Vector{T}, y::Vector{T}) where T <: RingElement

Given two arrays of values $xs$ and $ys$ of the same length $n$, find the polynomial $f$ in the polynomial ring $R$ of length at most $n$ such that $f$ has the value $ys$ at the points $xs$. The values in the arrays $xs$ and $ys$ must belong to the base ring of the polynomial ring $R$. If no such polynomial exists, an exception is raised.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> xs = [R(1), R(2), R(3), R(4)]
+4-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:
+ 1
+ 2
+ 3
+ 4
+
+julia> ys = [R(1), R(4), R(9), R(16)]
+4-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:
+ 1
+ 4
+ 9
+ 16
+
+julia> f = interpolate(S, xs, ys)
+y^2
+

Power sums

AbstractAlgebra.polynomial_to_power_sumsMethod
polynomial_to_power_sums(f::PolyRingElem{T}, n::Int=degree(f)) where T <: RingElement -> Vector{T}

Uses Newton (or Newton-Girard) formulas to compute the first $n$ sums of powers of the roots of $f$ from the coefficients of $f$, starting with the sum of (first powers of) the roots. The input polynomial must be monic, at least degree $1$ and have nonzero constant coefficient.

source
AbstractAlgebra.power_sums_to_polynomialMethod
power_sums_to_polynomial(P::Vector{T};
+                 parent::PolyRing{T}=PolyRing(parent(P[1])) where T <: RingElement -> PolyRingElem{T}

Uses the Newton (or Newton-Girard) identities to obtain the polynomial with given sums of powers of roots. The list must be nonempty and contain degree(f) entries where $f$ is the polynomial to be recovered. The list must start with the sum of first powers of the roots.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> f = x^4 - 2*x^3 + 10*x^2 + 7*x - 5
+x^4 - 2*x^3 + 10*x^2 + 7*x - 5
+
+julia> V = polynomial_to_power_sums(f)
+4-element Vector{BigInt}:
+   2
+ -16
+ -73
+  20
+
+julia> power_sums_to_polynomial(V)
+x^4 - 2*x^3 + 10*x^2 + 7*x - 5

Special functions

The following special functions can be computed for any polynomial ring. Typically one uses the generator $x$ of a polynomial ring to get the respective special polynomials expressed in terms of that generator.

AbstractAlgebra.chebyshev_tMethod
chebyshev_t(n::Int, x::PolyRingElem)

Return the Chebyshev polynomial of the first kind $T_n(x)$, defined by $T_n(x) = \cos(n \cos^{-1}(x))$.

source
AbstractAlgebra.chebyshev_uMethod
chebyshev_u(n::Int, x::PolyRingElem)

Return the Chebyshev polynomial of the first kind $U_n(x)$, defined by $(n+1) U_n(x) = T'_{n+1}(x)$.

source

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S, y = polynomial_ring(R, "y")
+(Univariate polynomial ring in y over univariate polynomial ring, y)
+
+julia> f = chebyshev_t(20, y)
+524288*y^20 - 2621440*y^18 + 5570560*y^16 - 6553600*y^14 + 4659200*y^12 - 2050048*y^10 + 549120*y^8 - 84480*y^6 + 6600*y^4 - 200*y^2 + 1
+
+julia> g = chebyshev_u(15, y)
+32768*y^15 - 114688*y^13 + 159744*y^11 - 112640*y^9 + 42240*y^7 - 8064*y^5 + 672*y^3 - 16*y
+

Random generation

One may generate random polynomials with degrees in a given range. Additional parameters are used to construct coefficients as elements of the coefficient ring.

rand(R::PolyRing, deg_range::AbstractUnitRange{Int}, v...)
+rand(R::PolyRing, deg::Int, v...)

Examples

R, x = polynomial_ring(ZZ, "x")
+f = rand(R, -1:3, -10:10)
+
+S, y = polynomial_ring(GF(7), "y")
+g = rand(S, 2:2)
+
+U, z = polynomial_ring(R, "z")
+h = rand(U, 3:3, -1:2, -10:10)
diff --git a/v0.37.6/puiseux/index.html b/v0.37.6/puiseux/index.html new file mode 100644 index 0000000000..1d756bd8b0 --- /dev/null +++ b/v0.37.6/puiseux/index.html @@ -0,0 +1,157 @@ + +Generic Puiseux series · AbstractAlgebra.jl

Generic Puiseux series

AbstractAlgebra.jl allows the creation of Puiseux series over any computable commutative ring $R$.

Puiseux series are power series of the form $a_jx^{j/m} + a_{j+1}x^{(j+1)/m} + \cdots + a_{k-1}x^{(k-1)/m} + O(x^{k/m})$ for some integer $m > 0$ where $i \geq 0$, $a_i \in R$ and the relative precision $k - j$ is at most equal to some specified precision $n$.

The generic Puiseux series module is implemented in src/generic/PuiseuxSeries.jl.

As well as implementing the Series Ring interface, the Puiseux series module in AbstractAlgebra.jl implements the generic algorithms described below.

All of the generic functionality is part of the Generic submodule of AbstractAlgebra.jl. This is exported by default so that it is not necessary to qualify function names.

Types and parent objects

The types of generic Puiseux series implemented by AbstractAlgebra.jl are Generic.PuiseuxSeriesRingElem{T} and Generic.PuiseuxSeriesFieldElem{T}.

Both series element types belong to the union type Generic.PuiseuxSeriesElem.

Puiseux series elements belong directly to either RingElem or FieldElem since it is more useful to be able to distinguish whether they belong to a ring or field than it is to distinguish that they are Puiseux series.

The parent types for Puiseux series, Generic.PuiseuxSeriesRing{T} and Generic.PuiseuxSeriesField{T} respectively, belong to Ring and Field respectively.

The default precision, string representation of the variable and base ring $R$ of a generic Puiseux series are stored in its parent object.

Puiseux series ring constructors

In order to construct Puiseux series in AbstractAlgebra.jl, one must first construct the ring itself. This is accomplished with any of the following constructors.

puiseux_series_ring(R::Ring, prec_max::Int, s::VarName; cached::Bool = true)
puiseux_series_ring(R::Field, prec_max::Int, s::VarName; cached::Bool = true)
puiseux_series_field(R::Field, prec_max::Int, s::VarName; cached::Bool = true)

Given a base ring R, a maximum relative precision and a string s specifying how the generator (variable) should be printed, return a tuple S, x representing the Puiseux series ring and its generator.

By default, S will depend only on S, x and the maximum precision and will be cached. Setting the optional argument cached to false will prevent this.

Here are some examples of constructing various kinds of Puiseux series rings and coercing various elements into those rings.

Examples

julia> R, x = puiseux_series_ring(ZZ, 10, "x")
+(Puiseux series ring in x over integers, x + O(x^11))
+
+julia> S, y = puiseux_series_field(QQ, 10, "y")
+(Puiseux series field in y over rationals, y + O(y^11))
+
+julia> f = R()
+O(x^10)
+
+julia> g = S(123)
+123 + O(y^10)
+
+julia> h = R(BigInt(1234))
+1234 + O(x^10)
+
+julia> k = S(y + 1)
+1 + y + O(y^10)
+

Big-oh notation

Series elements can be given a precision using the big-oh notation. This is provided by a function of the following form, (or something equivalent for Laurent series):

O(x::SeriesElem)

Examples

julia> R, x = puiseux_series_ring(ZZ, 10, "x")
+(Puiseux series ring in x over integers, x + O(x^11))
+
+julia> f = 1 + 2x + O(x^5)
+1 + 2*x + O(x^5)
+
+julia> g = 2x^(1//3) + 7x^(2//3) + O(x^(7//3))
+2*x^(1//3) + 7*x^(2//3) + O(x^(7//3))

What is happening here in practice is that O(x^n) is creating the series 0 + O(x^n) and the rules for addition of series dictate that if this is added to a series of greater precision, then the lower of the two precisions must be used.

Of course it may be that the precision of the series that O(x^n) is added to is already lower than n, in which case adding O(x^n) has no effect. This is the case if the default precision is too low, since x on its own has the default precision.

Puiseux series implementation

Puiseux series have their maximum relative precision capped at some value prec_max. This refers to the internal Laurent series used to store the Puiseux series, i.e. the series without denominators in the exponents.

The Puiseux series type stores such a Laurent series and a scale or denominator for the exponents. For example, $f(x) = 1 + x^{1/3} + 2x^{2/3} + O(x^{7/3})$ would be stored as a Laurent series $1 + x + 2x^2 + O(x^7)$ and a scale of $3$..

The maximum precision is also used as a default (Laurent) precision in the case of coercing coefficients into the ring and for any computation where the result could mathematically be given to infinite precision.

In all models we say that two Puiseux series are equal if they agree up to the minimum absolute precision of the two power series.

Thus, for example, $x^5 + O(x^{10}) == 0 + O(x^5)$, since the minimum absolute precision is $5$.

Sometimes it is necessary to compare Puiseux series not just for arithmetic equality, as above, but to see if they have precisely the same precision and terms. For this purpose we introduce the isequal function.

For example, if $f = x^2 + O(x^7)$ and $g = x^2 + O(x^8)$ and $h = 0 + O(x^2)$ then $f == g$, $f == h$ and $g == h$, but isequal(f, g), isequal(f, h) and isequal(g, h) would all return false. However, if $k = x^2 + O(x^7)$ then isequal(f, k) would return true.

There are a number of technicalities that must be observed when working with Puiseux series. As these are the same as for the other series rings in AbstractAlgebra.jl, we refer the reader to the documentation of series rings for information about these issues.

Basic ring functionality

All Puiseux series provide the functionality described in the Ring and Series Ring interfaces with the exception of the pol_length and polcoeff functions. Naturally the set_precision!, set_valuation! and coeff functions can take a rational exponent.

Examples

julia> S, x = puiseux_series_ring(ZZ, 10, "x")
+(Puiseux series ring in x over integers, x + O(x^11))
+
+julia> f = 1 + 3x + x^3 + O(x^10)
+1 + 3*x + x^3 + O(x^10)
+
+julia> g = 1 + 2x^(1//3) + x^(2//3) + O(x^(7//3))
+1 + 2*x^(1//3) + x^(2//3) + O(x^(7//3))
+
+julia> h = zero(S)
+O(x^10)
+
+julia> k = one(S)
+1 + O(x^10)
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> coeff(g, 1//3)
+2
+
+julia> U = base_ring(S)
+Integers
+
+julia> v = var(S)
+:x
+
+julia> T = parent(x + 1)
+Puiseux series ring in x over integers
+
+julia> g == deepcopy(g)
+true
+
+julia> t = divexact(2g, 2)
+1 + 2*x^(1//3) + x^(2//3) + O(x^(7//3))
+
+julia> p = precision(f)
+10//1
+

Puiseux series functionality provided by AbstractAlgebra.jl

The functionality below is automatically provided by AbstractAlgebra.jl for any Puiseux series.

Of course, modules are encouraged to provide specific implementations of the functions described here, that override the generic implementation.

Basic functionality

coeff(a::Generic.PuiseuxSeriesElem, n::Int)
coeff(a::Generic.PuiseuxSeriesElem, n::Rational{Int})

Return the coefficient of the term of exponent $n$ of the given power series. If $n$ exceeds the current precision of the power series or does not correspond to a nonzero term of the Puiseux series, the function returns a zero coefficient.

AbstractAlgebra.modulusMethod
modulus(a::Generic.PuiseuxSeriesElem{T}) where {T <: ResElem}

Return the modulus of the coefficients of the given Puiseux series.

source
AbstractAlgebra.is_genMethod
is_gen(a::Generic.PuiseuxSeriesElem)

Return true if the given Puiseux series is arithmetically equal to the generator of its Puiseux series ring to its current precision, otherwise return false.

source

Examples

julia> R, t = puiseux_series_ring(QQ, 10, "t")
+(Puiseux series field in t over rationals, t + O(t^11))
+
+julia> S, x = puiseux_series_ring(R, 30, "x")
+(Puiseux series field in x over puiseux series field, x + O(x^31))
+
+julia> a = O(x^4)
+O(x^4)
+
+julia> b = (t + 3)*x + (t^2 + 1)*x^2 + O(x^4)
+(3 + t + O(t^10))*x + (1 + t^2 + O(t^10))*x^2 + O(x^4)
+
+julia> k = is_gen(gen(R))
+true
+
+julia> m = is_unit(-1 + x^(1//3) + 2x^2)
+true
+
+julia> n = valuation(a)
+4//1
+
+julia> p = valuation(b)
+1//1
+
+julia> c = coeff(b, 2)
+1 + t^2 + O(t^10)
+

Division

Base.invMethod
inv(M::MatrixElem{T}) where {T <: RingElement}

Given a non-singular $n\times n$ matrix over a ring, return an $n\times n$ matrix $X$ such that $MX = I_n$, where $I_n$ is the $n\times n$ identity matrix. If $M$ is not invertible over the base ring an exception is raised.

source
Base.inv(a::PuiseuxSeriesElem{T}) where T <: RingElement

Return the inverse of the power series $a$, i.e. $1/a$, if it exists. Otherwise an exception is raised.

source
 inv(a::LocalizedEuclideanRingElem{T}, checked::Bool = true)  where {T <: RingElem}

Returns the inverse element of $a$ if $a$ is a unit. If 'checked = false' the invertibility of $a$ is not checked and the corresponding inverse element of the Fraction Field is returned.

source

Examples

julia> R, x = puiseux_series_ring(QQ, 30, "x")
+(Puiseux series field in x over rationals, x + O(x^31))
+
+julia> a = 1 + x + 2x^2 + O(x^5)
+1 + x + 2*x^2 + O(x^5)
+
+julia> b = R(-1)
+-1 + O(x^30)
+
+julia> c = inv(a)
+1 - x - x^2 + 3*x^3 - x^4 + O(x^5)
+
+julia> d = inv(b)
+-1 + O(x^30)
+

Derivative and integral

AbstractAlgebra.derivativeMethod
derivative(f::AbsPowerSeriesRingElem{T})

Return the derivative of the power series $f$.

source
derivative(f::RelPowerSeriesRingElem{T})

Return the derivative of the power series $f$.

julia> R, x = power_series_ring(QQ, 10, "x")
+(Univariate power series ring in x over Rationals, x + O(x^11))
+
+julia> f = 2 + x + 3x^3
+2 + x + 3*x^3 + O(x^10)
+
+julia> derivative(f)
+1 + 9*x^2 + O(x^9)
source
derivative(f::MPolyRingElem{T}, j::Int) where {T <: RingElement}

Return the partial derivative of f with respect to $j$-th variable of the polynomial ring.

source
derivative(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement

Return the partial derivative of f with respect to x. The value x must be a generator of the polynomial ring of f.

source
derivative(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the derivative of the given Puiseux series $a$.

source
AbstractAlgebra.integralMethod
integral(f::AbsPowerSeriesRingElem{T})

Return the integral of the power series $f$.

source
integral(f::RelPowerSeriesRingElem{T})

Return the integral of the power series $f$.

julia> R, x = power_series_ring(QQ, 10, "x")
+(Univariate power series ring in x over Rationals, x + O(x^11))
+
+julia> f = 2 + x + 3x^3
+2 + x + 3*x^3 + O(x^10)
+
+julia> integral(f)
+2*x + 1//2*x^2 + 3//4*x^4 + O(x^11)
source
integral(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the integral of the given Puiseux series $a$.

source

Examples

julia> R, x = puiseux_series_ring(QQ, 10, "x")
+(Puiseux series field in x over rationals, x + O(x^11))
+
+julia> f = x^(5//3) + x^(7//3) + x^(11//3)
+x^(5//3) + x^(7//3) + x^(11//3) + O(x^5)
+
+julia> derivative(f)
+5//3*x^(2//3) + 7//3*x^(4//3) + 11//3*x^(8//3) + O(x^4)
+
+julia> derivative(integral(f)) == f
+true

Special functions

Base.logMethod
log(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the logarithm of the given Puiseux series $a$.

source
Base.expMethod
exp(a::AbsPowerSeriesRingElem)

Return the exponential of the power series $a$.

source
exp(a::RelPowerSeriesRingElem)

Return the exponential of the power series $a$.

source
exp(a::Generic.LaurentSeriesElem)

Return the exponential of the power series $a$.

source
exp(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the exponential of the given Puiseux series $a$.

source
Base.sqrtMethod
Base.sqrt(f::PolyRingElem{T}; check::Bool=true) where T <: RingElement

Return the square root of $f$. By default the function checks the input is square and raises an exception if not. If check=false this check is omitted.

source
Base.sqrt(a::FracElem{T}; check::Bool=true) where T <: RingElem

Return the square root of $a$. By default the function will throw an exception if the input is not square. If check=false this test is omitted.

source
sqrt(a::Generic.PuiseuxSeriesElem{T}; check::Bool=true) where T <: RingElement

Return the square root of the given Puiseux series $a$. By default the function will throw an exception if the input is not square. If check=false this test is omitted.

source

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S, x = puiseux_series_ring(R, 30, "x")
+(Puiseux series ring in x over univariate polynomial ring, x + O(x^31))
+
+julia> T, z = puiseux_series_ring(QQ, 30, "z")
+(Puiseux series field in z over rationals, z + O(z^31))
+
+julia> a = 1 + z + 3z^2 + O(z^5)
+1 + z + 3*z^2 + O(z^5)
+
+julia> b = z + 2z^2 + 5z^3 + O(z^5)
+z + 2*z^2 + 5*z^3 + O(z^5)
+
+julia> c = exp(x + O(x^40))
+1 + x + 1//2*x^2 + 1//6*x^3 + 1//24*x^4 + 1//120*x^5 + 1//720*x^6 + 1//5040*x^7 + 1//40320*x^8 + 1//362880*x^9 + 1//3628800*x^10 + 1//39916800*x^11 + 1//479001600*x^12 + 1//6227020800*x^13 + 1//87178291200*x^14 + 1//1307674368000*x^15 + 1//20922789888000*x^16 + 1//355687428096000*x^17 + 1//6402373705728000*x^18 + 1//121645100408832000*x^19 + 1//2432902008176640000*x^20 + 1//51090942171709440000*x^21 + 1//1124000727777607680000*x^22 + 1//25852016738884976640000*x^23 + 1//620448401733239439360000*x^24 + 1//15511210043330985984000000*x^25 + 1//403291461126605635584000000*x^26 + 1//10888869450418352160768000000*x^27 + 1//304888344611713860501504000000*x^28 + 1//8841761993739701954543616000000*x^29 + 1//265252859812191058636308480000000*x^30 + O(x^31)
+
+julia> d = divexact(x, exp(x + O(x^40)) - 1)
+1 - 1//2*x + 1//12*x^2 - 1//720*x^4 + 1//30240*x^6 - 1//1209600*x^8 + 1//47900160*x^10 - 691//1307674368000*x^12 + 1//74724249600*x^14 - 3617//10670622842880000*x^16 + 43867//5109094217170944000*x^18 - 174611//802857662698291200000*x^20 + 77683//14101100039391805440000*x^22 - 236364091//1693824136731743669452800000*x^24 + 657931//186134520519971831808000000*x^26 - 3392780147//37893265687455865519472640000000*x^28 + O(x^29)
+
+julia> f = exp(b)
+1 + z + 5//2*z^2 + 43//6*z^3 + 193//24*z^4 + O(z^5)
+
+julia> h = sqrt(a)
+1 + 1//2*z + 11//8*z^2 - 11//16*z^3 - 77//128*z^4 + O(z^5)
+
diff --git a/v0.37.6/quotient_module/index.html b/v0.37.6/quotient_module/index.html new file mode 100644 index 0000000000..061a30564e --- /dev/null +++ b/v0.37.6/quotient_module/index.html @@ -0,0 +1,69 @@ + +Quotient modules · AbstractAlgebra.jl

Quotient modules

AbstractAlgebra allows the construction of quotient modules/spaces of AbstractAlgebra modules over euclidean domains. These are given as the quotient of a module by a submodule of that module.

We define two quotient modules to be equal if they are quotients of the same module $M$ by two equal submodules.

Generic quotient module type

AbstractAlgebra implements the generic quotient module type Generic.QuotientModule{T} where T is the element type of the base ring, in src/generic/QuotientModule.jl.

Elements of generic quotient modules have type Generic.QuotientModuleElem{T}.

Abstract types

Quotient module types belong to the FPModule{T} abstract type and their elements to FPModuleElem{T}.

Constructors

AbstractAlgebra.quoMethod
quo(m::FPModule{T}, subm::FPModule{T}) where T <: RingElement

Return the quotient M of the module m by the module subm (which must have been (transitively) constructed as a submodule of m or be m itself) along with the canonical quotient map from m to M.

source

Note that a preimage of the canonical projection can be obtained using the preimage function described in the section on module homomorphisms. Note that a preimage element of the canonical projection is not unique and has no special properties.

Examples

julia> M = FreeModule(ZZ, 2)
+Free module of rank 2 over integers
+
+julia> m = M([ZZ(1), ZZ(2)])
+(1, 2)
+
+julia> N, f = sub(M, [m])
+(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 2 over integers)
+
+julia> Q, g = quo(M, N)
+(Quotient module over Integers with 1 generator and no relations, Hom: free module of rank 2 over integers -> quotient module over Integers with 1 generator and no relations)
+
+julia> p = M([ZZ(3), ZZ(1)])
+(3, 1)
+
+julia> v2 = g(p)
+(-5)
+
+julia> V = VectorSpace(QQ, 2)
+Vector space of dimension 2 over rationals
+
+julia> m = V([QQ(1), QQ(2)])
+(1//1, 2//1)
+
+julia> N, f = sub(V, [m])
+(Subspace over Rationals with 1 generator and no relations, Hom: subspace over Rationals with 1 generator and no relations -> vector space of dimension 2 over rationals)
+
+julia> Q, g = quo(V, N)
+(Quotient space over:
+Rationals with 1 generator and no relations, Hom: vector space of dimension 2 over rationals -> quotient space over:
+Rationals with 1 generator and no relations)
+

Functionality for submodules

In addition to the Module interface, AbstractAlgebra submodules implement the following functionality.

Basic manipulation

Examples

julia> M = FreeModule(ZZ, 2)
+Free module of rank 2 over integers
+
+julia> m = M([ZZ(2), ZZ(3)])
+(2, 3)
+
+julia> N, g = sub(M, [m])
+(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 2 over integers)
+
+julia> Q, h = quo(M, N)
+(Quotient module over Integers with 2 generators and relations:
+[2 3], Hom: free module of rank 2 over integers -> quotient module over Integers with 2 generators and relations:
+[2 3])
+
+julia> supermodule(Q) == M
+true
+
+julia> V = VectorSpace(QQ, 2)
+Vector space of dimension 2 over rationals
+
+julia> m = V([QQ(1), QQ(2)])
+(1//1, 2//1)
+
+julia> N, f = sub(V, [m])
+(Subspace over Rationals with 1 generator and no relations, Hom: subspace over Rationals with 1 generator and no relations -> vector space of dimension 2 over rationals)
+
+julia> Q, g = quo(V, N)
+(Quotient space over:
+Rationals with 1 generator and no relations, Hom: vector space of dimension 2 over rationals -> quotient space over:
+Rationals with 1 generator and no relations)
+
+julia> dim(V)
+2
+
+julia> dim(Q)
+1
+
diff --git a/v0.37.6/rand/index.html b/v0.37.6/rand/index.html new file mode 100644 index 0000000000..7a5da3094f --- /dev/null +++ b/v0.37.6/rand/index.html @@ -0,0 +1,53 @@ + +Random interface · AbstractAlgebra.jl

Random interface

AbstractAlgebra makes use of the Julia Random interface for random generation.

In addition we make use of an experimental package RandomExtensions.jl for extending the random interface in Julia.

The latter is required because some of our types require more than one argument to specify how to randomise them.

The usual way of generating random values that Julia and these extensions provide would look as follows:

julia> using AbstractAlgebra
+
+julia> using Random
+
+julia> using RandomExtensions
+
+julia> S, x = polynomial_ring(ZZ, "x")
+(Univariate Polynomial Ring in x over Integers, x)
+
+julia> rand(Random.GLOBAL_RNG, make(S, 1:3, -10:10))
+-5*x + 4

This example generates a polynomial over the integers with degree in the range 1 to 3 and with coefficients in the range -10 to 10.

In addition we implement shortened versions for ease of use which don't require creating a make instance or passing in the standard RNG.

julia> using AbstractAlgebra
+
+julia> S, x = polynomial_ring(ZZ, "x")
+(Univariate Polynomial Ring in x over Integers, x)
+
+julia> rand(S, 1:3, -10:10)
+-5*x + 4

Because rings can be constructed over other rings in a tower, all of this is supported by defining RandomExtensions.make instances that break the various levels of the ring down into separate make instances.

For example, here is the implementation of make for polynomial rings such as the above:

function RandomExtensions.make(S::PolyRing, deg_range::AbstractUnitRange{Int}, vs...)
+   R = base_ring(S)
+   if length(vs) == 1 && elem_type(R) == Random.gentype(vs[1])
+      Make(S, deg_range, vs[1]) # forward to default Make constructor
+   else
+      Make(S, deg_range, make(R, vs...))
+   end
+end

As you can see, it has two cases. The first is where this invocation of make is already at the bottom of the tower of rings, in which case it just forwards to the default Make constructor.

The second case expects that we are higher up in the tower of rings and that make needs to be broken up (recursively) into the part that deals with the ring level we are at and the level that deals with the base ring.

To help make we tell it the type of object we are hoping to randomly generate.

RandomExtensions.maketype(S::PolyRing, dr::AbstractUnitRange{Int}, _) = elem_type(S)

Finally we implement the actual random generation itself.

# define rand for make(S, deg_range, v)
+function rand(rng::AbstractRNG, sp::SamplerTrivial{<:Make3{<:RingElement, <:PolyRing, <:AbstractUnitRange{Int}}})
+   S, deg_range, v = sp[][1:end]
+   R = base_ring(S)
+   f = S()
+   x = gen(S)
+   # degree -1 is zero polynomial
+   deg = rand(rng, deg_range)
+   if deg == -1
+      return f
+   end
+   for i = 0:deg - 1
+      f += rand(rng, v)*x^i
+   end
+   # ensure leading coefficient is nonzero
+   c = R()
+   while iszero(c)
+      c = rand(rng, v)
+   end
+   f += c*x^deg
+   return f
+end

Note that when generating random elements of the base ring for example, one should use the random number generator rng that is passed in.

As mentioned above, we define a simplified random generator that saves the user having to create make instances.

rand(rng::AbstractRNG, S::PolyRing, deg_range::AbstractUnitRange{Int}, v...) =
+   rand(rng, make(S, deg_range, v...))
+
+rand(S::PolyRing, degs, v...) = rand(Random.GLOBAL_RNG, S, degs, v...)

To test whether a random generator is working properly, the test_rand function exists in the AbstractAlgebra test submodule in the file test/runtests.jl. For example, in AbstractAlgebra test code:

using Test
+
+R, x = polynomial_ring(ZZ, "x")
+
+test_rand(R, -1:10, -10:10)

In general, we try to use UnitRange's to specify how 'big' we want the random instance to be, e.g. the range of degrees a polynomial could take, the range random integers could lie in, etc. The objective is to make it easy for the user to control the 'size' of random values in test code.

diff --git a/v0.37.6/rational/index.html b/v0.37.6/rational/index.html new file mode 100644 index 0000000000..9176410f2a --- /dev/null +++ b/v0.37.6/rational/index.html @@ -0,0 +1,58 @@ + +Rational field · AbstractAlgebra.jl

Rational field

AbstractAlgebra.jl provides a module, implemented in src/julia/Rational.jl for making Julia Rational{BigInt}s conform to the AbstractAlgebra.jl Field interface.

In addition to providing a parent object QQ for Julia Rational{BigInt}s, we implement any additional functionality required by AbstractAlgebra.jl.

Because Rational{BigInt} cannot be directly included in the AbstractAlgebra.jl abstract type hierarchy, we achieve integration of Julia Rational{BigInt}s by introducing a type union, called FieldElement, which is a union of FieldElem and a number of Julia types, including Rational{BigInt}. Everywhere that FieldElem is notionally used in AbstractAlgebra.jl, we are in fact using FieldElement, with additional care being taken to avoid ambiguities.

The details of how this is done are technical, and we refer the reader to the implementation for details. For most intents and purposes, one can think of the Julia Rational{BigInt} type as belonging to FieldElem.

One other technicality is that Julia defines certain functions for Rational{BigInt}, such as sqrt and exp differently to what AbstractAlgebra.jl requires. To get around this, we redefine these functions internally to AbstractAlgebra.jl, without redefining them for users of AbstractAlgebra.jl. This allows the internals of AbstractAlgebra.jl to function correctly, without broadcasting pirate definitions of already defined Julia functions to the world.

To access the internal definitions, one can use AbstractAlgebra.sqrt and AbstractAlgebra.exp, etc.

Types and parent objects

Rationals have type Rational{BigInt}, as in Julia itself. We simply supplement the functionality for this type as required for computer algebra.

The parent objects of such integers has type Rationals{BigInt}.

For convenience, we also make Rational{Int} a part of the AbstractAlgebra.jl type hierarchy and its parent object (accessible as qq) has type Rationals{Int}. But we caution that this type is not particularly useful as a model of the rationals and may not function as expected within AbstractAlgebra.jl.

Rational constructors

In order to construct rationals in AbstractAlgebra.jl, one can first construct the rational field itself. This is accomplished using either of the following constructors.

fraction_field(R::Integers{BigInt})
Rationals{BigInt}()

This gives the unique object of type Rationals{BigInt} representing the field of rationals in AbstractAlgebra.jl.

In practice, one simply uses QQ which is assigned to be the return value of the above constructor. There is no need to call the constructor in practice.

Here are some examples of creating the rational field and making use of the resulting parent object to coerce various elements into the field.

Examples

julia> f = QQ()
+0//1
+
+julia> g = QQ(123)
+123//1
+
+julia> h = QQ(BigInt(1234))
+1234//1
+
+julia> k = QQ(BigInt(12), BigInt(7))
+12//7
+
+julia> QQ == fraction_field(ZZ)
+true
+

Basic field functionality

The rational field in AbstractAlgebra.jl implements the full Field and Fraction Field interfaces.

We give some examples of such functionality.

Examples

julia> f = QQ(12, 7)
+12//7
+
+julia> h = zero(QQ)
+0//1
+
+julia> k = one(QQ)
+1//1
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> U = base_ring(QQ)
+Integers
+
+julia> V = base_ring(f)
+Integers
+
+julia> T = parent(f)
+Rationals
+
+julia> f == deepcopy(f)
+true
+
+julia> g = f + 12
+96//7
+
+julia> r = ZZ(12)//ZZ(7)
+12//7
+
+julia> n = numerator(r)
+12
+

Rational functionality provided by AbstractAlgebra.jl

The functionality below supplements that provided by Julia itself for its Rational{BigInt} type.

Square and n-th root

The functions sqrt, is_square, is_square_with_sqrt are all provided, as are root and is_power.

Examples

julia> d = AbstractAlgebra.sqrt(ZZ(36)//ZZ(25))
+6//5
+
+julia> is_square(ZZ(9)//ZZ(16))
+true
+
+julia> root(ZZ(27)//64, 3)
+3//4
diff --git a/v0.37.6/real/index.html b/v0.37.6/real/index.html new file mode 100644 index 0000000000..46706eda45 --- /dev/null +++ b/v0.37.6/real/index.html @@ -0,0 +1,51 @@ + +Real field · AbstractAlgebra.jl

Real field

AbstractAlgebra.jl provides a module, implemented in src/julia/Float.jl for making Julia BigFloats conform to the AbstractAlgebra.jl Field interface.

In addition to providing a parent object RealField for Julia BigFloats, we implement any additional functionality required by AbstractAlgebra.jl.

Because BigFloat cannot be directly included in the AbstractAlgebra.jl abstract type hierarchy, we achieve integration of Julia BigFloats by introducing a type union, called FieldElement, which is a union of FieldElem and a number of Julia types, including BigFloat. Everywhere that FieldElem is notionally used in AbstractAlgebra.jl, we are in fact using FieldElement, with additional care being taken to avoid ambiguities.

The details of how this is done are technical, and we refer the reader to the implementation for details. For most intents and purposes, one can think of the Julia BigFloat type as belonging to FieldElem.

Types and parent objects

Reals have type BigFloat, as in Julia itself. We simply supplement the functionality for this type as required for computer algebra.

The parent objects of such integers has type Floats{BigFloat}.

For convenience, we also make Float64 a part of the AbstractAlgebra.jl type hierarchy and its parent object (accessible as RDF) has type Floats{Float64}.

Rational constructors

In order to construct reals in AbstractAlgebra.jl, one can first construct the real field itself. This is accomplished using the following constructor.

Floats{BigFloat}()

This gives the unique object of type Floats{BigFloat} representing the field of reals in AbstractAlgebra.jl.

In practice, one simply uses RealField which is assigned to be the return value of the above constructor. There is no need to call the constructor in practice.

Here are some examples of creating the real field and making use of the resulting parent object to coerce various elements into the field.

Examples

julia> RR = RealField
+Floats
+
+julia> f = RR()
+0.0
+
+julia> g = RR(123)
+123.0
+
+julia> h = RR(BigInt(1234))
+1234.0
+
+julia> k = RR(12//7)
+1.714285714285714285714285714285714285714285714285714285714285714285714285714291
+
+julia> m = RR(2.3)
+2.29999999999999982236431605997495353221893310546875
+

Basic field functionality

The real field in AbstractAlgebra.jl implements the full Field interface.

We give some examples of such functionality.

Examples

julia> RR = RealField
+Floats
+
+julia> f = RR(12//7)
+1.714285714285714285714285714285714285714285714285714285714285714285714285714291
+
+julia> h = zero(RR)
+0.0
+
+julia> k = one(RR)
+1.0
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> U = base_ring(RR)
+Union{}
+
+julia> T = parent(f)
+Floats
+
+julia> f == deepcopy(f)
+true
+
+julia> g = f + 12
+13.71428571428571428571428571428571428571428571428571428571428571428571428571433
+
+julia> m = inv(g)
+0.07291666666666666666666666666666666666666666666666666666666666666666666666666631
+
diff --git a/v0.37.6/residue/index.html b/v0.37.6/residue/index.html new file mode 100644 index 0000000000..e8272bc295 --- /dev/null +++ b/v0.37.6/residue/index.html @@ -0,0 +1,116 @@ + +Generic residue rings · AbstractAlgebra.jl

Generic residue rings

AbstractAlgebra.jl provides modules, implemented in src/Residue.jl and src/residue_field for residue rings and fields, respectively, over any Euclidean domain (in practice most of the functionality is provided for GCD domains that provide a meaningful GCD function) belonging to the AbstractAlgebra.jl abstract type hierarchy.

Generic residue types

AbstractAlgebra.jl implements generic residue rings of Euclidean rings with type EuclideanRingResidueRingElem{T} or in the case of residue rings that are known to be fields, EuclideanRingResidueFieldElem{T}, where T is the type of elements of the base ring. See the file src/generic/GenericTypes.jl for details.

Parent objects of generic residue ring elements have type EuclideanRingResidueRing{T} and those of residue fields have type EuclideanRingResidueField{T}.

The defining modulus of the residue ring is stored in the parent object.

Abstract types

All residue element types belong to the abstract type ResElem{T} or ResFieldElem{T} in the case of residue fields, and the residue ring types belong to the abstract type ResidueRing{T} or ResidueField{T} respectively. This enables one to write generic functions that can accept any AbstractAlgebra residue type.

Residue ring constructors

In order to construct residues in AbstractAlgebra.jl, one must first construct the residue ring itself. This is accomplished with one of the following constructors.

residue_ring(R::Ring, m::RingElem; cached::Bool = true)
residue_field(R::Ring, m::RingElem; cached::Bool = true)

Given a base ring R and residue $m$ contained in this ring, return the parent object of the residue ring $R/(m)$ together with the canonical projection. By default the parent object S will depend only on R and m and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

The residue_field constructor does the same thing as the residue_ring constructor, but the resulting object has type belonging to Field rather than Ring, so it can be used anywhere a field is expected in AbstractAlgebra.jl. No check is made for maximality of the ideal generated by $m$.

There are also the following for constructing residue rings and fields.

AbstractAlgebra.quoMethod
quo(R::Ring, a::RingElement; cached::Bool = true)

Returns S, f where S = residue_ring(R, a) and f is the projection map from R to S. This map is supplied as a map with section where the section is the lift of an element of the residue field back to the ring R.

source
AbstractAlgebra.quoMethod
quo(::Type{Field}, R::Ring, a::RingElement; cached::Bool = true)

Returns S, f where S = residue_field(R, a) and f is the projection map from R to S. This map is supplied as a map with section where the section is the lift of an element of the residue field back to the ring R.

source

Here are some examples of creating residue rings and making use of the resulting parent objects to coerce various elements into the residue ring.

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S, = residue_ring(R, x^3 + 3x + 1);
+
+julia> f = S()
+0
+
+julia> g = S(123)
+123
+
+julia> h = S(BigInt(1234))
+1234
+
+julia> k = S(x + 1)
+x + 1
+
+julia> U, f = quo(R, x^3 + 3x + 1)
+(Residue ring of univariate polynomial ring modulo x^3 + 3*x + 1, Map: univariate polynomial ring -> residue ring)
+
+julia> U === S
+true

All of the examples here are generic residue rings, but specialised implementations of residue rings provided by external modules will also usually provide a residue_ring constructor to allow creation of their residue rings.

Residue constructors

One can use the parent objects of a residue ring to construct residues, as per any ring.

(R::ResidueRing)() # constructs zero
+(R::ResidueRing)(c::Integer)
+(R::ResidueRing)(c::elem_type(R))
+(R::ResidueRing{T})(a::T) where T <: RingElement

Functions for types and parents of residue rings

base_ring(R::ResidueRing)
+base_ring(a::ResElem)

Return the base ring over which the ring was constructed.

parent(a::ResElem)

Return the parent of the given residue.

characteristic(R::ResidueRing)

Return the characteristic of the given residue ring. If the characteristic is not known, an exception is raised.

Residue ring functions

Basic functionality

Residue rings implement the Ring interface.

zero(R::NCRing)
+one(R::NCRing)
+iszero(a::NCRingElement)
+isone(a::NCRingElement)
divexact(a::T, b::T) where T <: RingElement
+inv(a::T)

The Residue Ring interface is also implemented.

modulus(S::ResidueRing)
data(f::ResElem)
+lift(f::ResElem)

Return a lift of the residue to the base ring.

The following functions are also provided for residues.

AbstractAlgebra.modulusMethod
modulus(R::ResElem)

Return the modulus $a$ of the residue ring $S = R/(a)$ that the supplied residue $r$ belongs to.

source

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S, = residue_ring(R, x^3 + 3x + 1);
+
+julia> f = S(x + 1)
+x + 1
+
+julia> h = zero(S)
+0
+
+julia> k = one(S)
+1
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> is_unit(f)
+true
+
+julia> m = modulus(S)
+x^3 + 3*x + 1
+
+julia> d = data(f)
+x + 1
+
+julia> U = base_ring(S)
+Univariate polynomial ring in x over rationals
+
+julia> V = base_ring(f)
+Univariate polynomial ring in x over rationals
+
+julia> T = parent(f)
+Residue ring of univariate polynomial ring modulo x^3 + 3*x + 1
+
+julia> f == deepcopy(f)
+true
+
+julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)

Inversion

Base.invMethod
Base.inv(a::ResElem)

Return the inverse of the element $a$ in the residue ring. If an impossible inverse is encountered, an exception is raised.

source

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S, = residue_ring(R, x^3 + 3x + 1);
+
+julia> f = S(x + 1)
+x + 1
+
+julia> g = inv(f)
+1//3*x^2 - 1//3*x + 4//3
+

Greatest common divisor

Base.gcdMethod
gcd(a::ResElem{T}, b::ResElem{T}) where {T <: RingElement}

Return a greatest common divisor of $a$ and $b$ if one exists. This is done by taking the greatest common divisor of the data associated with the supplied residues and taking its greatest common divisor with the modulus.

source

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S, = residue_ring(R, x^3 + 3x + 1);
+
+julia> f = S(x + 1)
+x + 1
+
+julia> g = S(x^2 + 2x + 1)
+x^2 + 2*x + 1
+
+julia> h = gcd(f, g)
+1
+

Square Root

Base.sqrtMethod
sqrt(a::ResFieldElem{T}; check::Bool=true) where T <: Integer

Return the square root of $a$. By default the function will throw an exception if the input is not square. If check=false this test is omitted.

source

Examples

julia> R = residue_field(ZZ, 733)
+Residue field of Integers modulo 733
+
+julia> a = R(86)
+86
+
+julia> is_square(a)
+true
+
+julia> sqrt(a)
+532

Random generation

Random residues can be generated using rand. The parameters after the residue ring are used to generate elements of the base ring.

rand(R::ResidueRing, v...)

Examples

julia> R, = residue_ring(ZZ, 7);
+
+julia> f = rand(R, 0:6)
+4
+
+julia> S, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> g = rand(S, 2:2, -10:10)
+-1//4*x^2 - 2//7*x + 1
diff --git a/v0.37.6/residue_interface/index.html b/v0.37.6/residue_interface/index.html new file mode 100644 index 0000000000..3b6634a6e2 --- /dev/null +++ b/v0.37.6/residue_interface/index.html @@ -0,0 +1,3 @@ + +Residue Ring Interface · AbstractAlgebra.jl

Residue Ring Interface

Residue rings (currently a quotient ring modulo a principal ideal) are supported in AbstractAlgebra.jl, at least for Euclidean base rings. There is also partial support for residue rings of polynomial rings where the modulus has invertible leading coefficient.

In addition to the standard Ring interface, some additional functions are required to be present for residue rings.

Types and parents

AbstractAlgebra provides four abstract types for residue rings and their elements:

  • ResidueRing{T} is the abstract type for residue ring parent types
  • ResidueField{T} is the abstract type for residue rings known to be fields
  • ResElem{T} is the abstract type for types of elements of residue rings (residues)
  • ResFieldElem{T} is the abstract type for types of elements of residue fields

We have that ResidueRing{T} <: AbstractAlgebra.Ring and ResElem{T} <: AbstractAlgebra.RingElem.

Note that these abstract types are parameterised. The type T should usually be the type of elements of the base ring of the residue ring/field.

If the parent object for a residue ring has type MyResRing and residues in that ring have type MyRes then one would have:

  • MyResRing <: ResidueRing{BigInt}
  • MyRes <: ResElem{BigInt}

Residue rings should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Residue rings should at least be distinguished based on their base ring and modulus (the principal ideal one is taking a quotient of the base ring by).

See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).

Required functionality for residue rings

In addition to the required functionality for the Ring interface the Residue Ring interface has the following required functions.

We suppose that R is a fictitious base ring, $m$ is an element of that ring, and that S is the residue ring (quotient ring) $R/(m)$ with parent object S of type MyResRing{T}. We also assume the residues $r \pmod{m}$ in the residue ring have type MyRes{T}, where T is the type of elements of the base ring.

Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.

Note that the type T must (transitively) belong to the abstract type RingElem.

Data type and parent object methods

modulus(S::MyResRing{T}) where T <: AbstractAlgebra.RingElem

Return the modulus of the given residue ring, i.e. if the residue ring $S$ was specified to be $R/(m)$, return $m$.

Basic manipulation of rings and elements

data(f::MyRes{T}) where T <: RingElem
+lift(f::MyRes{T}) where T <: RingElem

Given a residue $r \pmod{m}$, represented as such, return $r$. In the special case where machine integers are used to represent the residue, data will return the machine integer, whereas lift will return a multiprecision integer. Otherwise lift falls back to data by default.

diff --git a/v0.37.6/ring/index.html b/v0.37.6/ring/index.html new file mode 100644 index 0000000000..04bcddbebc --- /dev/null +++ b/v0.37.6/ring/index.html @@ -0,0 +1,26 @@ + +Ring functionality · AbstractAlgebra.jl

Ring functionality

AbstractAlgebra has both commutative and noncommutative rings. Together we refer to them below as rings.

Abstract types for rings

All commutative ring types in AbstractAlgebra belong to the Ring abstract type and commutative ring elements belong to the RingElem abstract type.

Noncommutative ring types belong to the NCRing abstract type and their elements to NCRingElem.

As Julia types cannot belong to our RingElem type hierarchy, we also provide the union type RingElement which includes RingElem in union with the Julia types Integer, Rational and AbstractFloat.

Similarly NCRingElement includes the Julia types just mentioned in union with NCRingElem.

Note that

Ring <: NCRing
+RingElem <: NCRingElem
+RingElement <: NCRingElement

Functions for types and parents of rings

parent_type(::Type{T}) where T <: NCRingElement
+elem_type(::Type{T}) where T <: NCRing

Return the type of the parent (resp. element) type corresponding to the given ring element (resp. parent) type.

base_ring(R::NCRing)
+base_ring(a::NCRingElement)

For generic ring constructions over a base ring (e.g. polynomials over a coefficient ring), return the parent object of that base ring.

parent(a::NCRingElement)

Return the parent of the given ring element.

is_domain_type(::Type{T}) where T <: NCRingElement
+is_exact_type(::Type{T}) where T <: NCRingElement

Return true if the given ring element type can only belong to elements of an integral domain or exact ring respectively. (An exact ring is one whose elements are represented exactly in the system without approximation.)

The following function is implemented where mathematically and algorithmically possible.

characteristic(R::NCRing)

Constructors

If R is a parent object of a ring in AbstractAlgebra, it can always be used to construct certain objects in that ring.

(R::NCRing)() # constructs zero
+(R::NCRing)(c::Integer)
+(R::NCRing)(c::elem_type(R))
+(R::NCRing{T})(a::T) where T <: RingElement

Basic functions

All rings in AbstractAlgebra are expected to implement basic ring operations, unary minus, binary addition, subtraction and multiplication, equality testing, powering.

In addition, the following are implemented for parents/elements just as they would be in Julia for types/objects.

zero(R::NCRing)
+one(R::NCRing)
+iszero(a::NCRingElement)
+isone(a::NCRingElement)

In addition, the following are implemented where it is mathematically/algorithmically viable to do so.

is_unit(a::NCRingElement)
+is_zero_divisor(a::NCRingElement)
+is_zero_divisor_with_annihilator(a::NCRingElement)

The following standard Julia functions are also implemented for all ring elements.

hash(f::RingElement, h::UInt)
+deepcopy_internal(a::RingElement, dict::IdDict)
+show(io::IO, R::NCRing)
+show(io::IO, a::NCRingElement)

Basic functionality for inexact rings only

By default, inexact ring elements in AbstractAlgebra compare equal if they are the same to the minimum precision of the two elements. However, we also provide the following more strict notion of equality, which also requires the precisions to be the same.

isequal(a::T, b::T) where T <: NCRingElement

For floating point and ball arithmetic it is sometimes useful to be able to check if two elements are approximately equal, e.g. to suppress numerical noise in comparisons. For this, the following are provided.

isapprox(a::T, b::T; atol::Real=sqrt(eps())) where T <: RingElement

Similarly, for a parameterised ring with type MyElem{T} over such an inexact ring we have the following.

isapprox(a::MyElem{T}, b::T; atol::Real=sqrt(eps())) where T <: RingElement
+isapprox(a::T, b::MyElem{T}; atol::Real=sqrt(eps())) where T <: RingElement

These notionally perform a coercion into the parameterised ring before doing the approximate equality test.

Basic functionality for commutative rings only

divexact(a::T, b::T) where T <: RingElement
+inv(a::T)

Return a/b or 1/a respectively, where the slash here refers to the mathematical notion of division in the ring, not Julia's floating point division operator.

Basic functionality for noncommutative rings only

divexact_left(a::T, b::T) where T <: NCRingElement
+divexact_right(a::T, b::T) where T <: NCRingElement

As per divexact above, except that division by b happens on the left or right, respectively, of a.

Unsafe ring operators

To speed up polynomial arithmetic, various unsafe operators are provided, which mutate the output rather than create a new object.

zero!(a::NCRingElement)
+mul!(a::T, b::T, c::T) where T <: NCRingElement
+add!(a::T, b::T, c::T) where T <: NCRingElement
+addeq!(a::T, b::T) where T <: NCRingElement
+addmul!(a::T, b::T, c::T, t::T) where T <: NCRingElement

In each case the mutated object is the leftmost parameter.

The addeq!(a, b) operation does the same thing as add!(a, a, b). The optional addmul!(a, b, c, t) operation does the same thing as mul!(t, b, c); addeq!(a, t) where t is a temporary which can be mutated so that an addition allocation is not needed.

Random generation

The Julia random interface is implemented for all ring parents (instead of for types). The exact interface differs depending on the ring, but the parameters supplied are usually ranges, e.g. -1:10 for the range of allowed degrees for a univariate polynomial.

rand(R::NCRing, v...)

Factorization

For commutative rings supporting factorization and irreducibility testing, the following optional functions may be implemented.

AbstractAlgebra.is_irreducibleMethod
is_irreducible(a::RingElement)

Return true if $a$ is irreducible, else return false. Zero and units are by definition never irreducible.

source
AbstractAlgebra.is_squarefreeMethod
is_squarefree(a::RingElement)

Return true if $a$ is squarefree, else return false. An element is squarefree if it it is not divisible by any squares except the squares of units.

source
factor(a::T) where T <: RingElement
+factor_squarefree(a::T) where T <: RingElement

Return a factorization into irreducible or squarefree elements, respectively. The return is an object of type Fac{T}.

Base.getindexMethod
getindex(a::Fac, b) -> Int

If $b$ is a factor of $a$, the corresponding exponent is returned. Otherwise an error is thrown.

source
Base.setindex!Method
setindex!(a::Fac{T}, c::Int, b::T)

If $b$ is a factor of $a$, the corresponding entry is set to $c$.

source
diff --git a/v0.37.6/ring_interface/index.html b/v0.37.6/ring_interface/index.html new file mode 100644 index 0000000000..7ff15b8f63 --- /dev/null +++ b/v0.37.6/ring_interface/index.html @@ -0,0 +1,275 @@ + +Ring Interface · AbstractAlgebra.jl

Ring Interface

AbstractAlgebra.jl generic code makes use of a standardised set of functions which it expects to be implemented for all rings. Here we document this interface. All libraries which want to make use of the generic capabilities of AbstractAlgebra.jl must supply all of the required functionality for their rings.

In addition to the required functions, there are also optional functions which can be provided for certain types of rings, e.g. GCD domains or fields, etc. If implemented, these allow the generic code to provide additional functionality for those rings, or in some cases, to select more efficient algorithms.

Types

Most rings must supply two types:

  • a type for the parent object (representing the ring itself)
  • a type for elements of that ring

For example, the generic univariate polynomial type in AbstractAlgebra.jl provides two types in generic/GenericTypes.jl:

  • Generic.PolyRing{T} for the parent objects
  • Generic.Poly{T} for the actual polynomials

The parent type must belong to Ring and the element type must belong to RingElem. Of course, the types may belong to these abstract types transitively, e.g. Poly{T} actually belongs to PolyRingElem{T} which in turn belongs to RingElem.

For parameterised rings, we advise that the types of both the parent objects and element objects to be parameterised by the types of the elements of the base ring (see the function base_ring below for a definition).

There can be variations on this theme: e.g. in some areas of mathematics there is a notion of a coefficient domain, in which case it may make sense to parameterise all types by the type of elements of this coefficient domain. But note that this may have implications for the ad hoc operators one might like to explicitly implement.

RingElement type union

Because of its lack of multiple inheritance, Julia does not allow Julia Base types to belong to RingElem. To allow us to work equally with AbstractAlgebra and Julia types that represent elements of rings we define a union type RingElement in src/julia/JuliaTypes.

So far, in addition to RingElem the union type RingElement includes the Julia types Integer, Rational and AbstractFloat.

Most of the generic code in AbstractAlgebra makes use of the union type RingElement instead of RingElem so that the generic functions also accept the Julia Base ring types.

Note

One must be careful when defining ad hoc binary operations for ring element types. It is often necessary to define separate versions of the functions for RingElem then for each of the Julia types separately in order to avoid ambiguity warnings.

Note that even though RingElement is a union type we still have the following inclusion

RingElement <: NCRingElement

Parent object caches

In many cases, it is desirable to have only one object in the system to represent each ring. This means that if the same ring is constructed twice, elements of the two rings will be compatible as far as arithmetic is concerned.

In order to facilitate this, global caches of rings are stored in AbstractAlgebra.jl, usually implemented using dictionaries. For example, the Generic.PolyRing parent objects are looked up in a dictionary PolyID to see if they have been previously defined.

Whether these global caches are provided or not, depends on both mathematical and algorithmic considerations. E.g. in the case of number fields, it isn't desirable to identify all number fields with the same defining polynomial, as they may be considered with distinct embeddings into one another. In other cases, identifying whether two rings are the same may be prohibitively expensive. Generally, it may only make sense algorithmically to identify two rings if they were constructed from identical data.

If a global cache is provided, it must be optionally possible to construct the parent objects without caching. This is done by passing a boolean value cached to the inner constructor of the parent object. See src/generic/GenericTypes.jl for examples of how to construct and handle such caches.

Required functions for all rings

In the following, we list all the functions that are required to be provided for rings in AbstractAlgebra.jl or by external libraries wanting to use AbstractAlgebra.jl.

We give this interface for fictitious types MyParent for the type of the ring parent object R and MyElem for the type of the elements of the ring.

Note

Generic functions in AbstractAlgebra.jl may not rely on the existence of functions that are not documented here. If they do, those functions will only be available for rings that implement that additional functionality, and should be documented as such.

Data type and parent object methods

parent_type(::Type{MyElem})

Return the type of the corresponding parent object for the given element type. For example, parent_type(Generic.Poly{T}) will return Generic.PolyRing{T}.

elem_type(::Type{MyParent})

Return the type of the elements of the ring whose parent object has the given type. This is the inverse of the parent_type function, i.e. elem_type(Generic.PolyRing{T}) will return Generic.Poly{T}.

base_ring(R::MyParent)

Given a parent object R, representing a ring, this function returns the parent object of any base ring that parameterises this ring. For example, the base ring of the ring of polynomials over the integers would be the integer ring.

If the ring is not parameterised by another ring, this function must return Union{}.

Note

There is a distinction between a base ring and other kinds of parameters. For example, in the ring $\mathbb{Z}/n\mathbb{Z}$, the modulus $n$ is a parameter, but the only base ring is $\mathbb{Z}$. We consider the ring $\mathbb{Z}/n\mathbb{Z}$ to have been constructed from the base ring $\mathbb{Z}$ by taking its quotient by a (principal) ideal.

parent(f::MyElem)

Return the parent object of the given element, i.e. return the ring to which the given element belongs.

This is usually stored in a field parent in each ring element. (If the parent objects have mutable struct types, the internal overhead here is just an additional machine pointer stored in each element of the ring.)

For some element types it isn't necessary to append the parent object as a field of every element. This is the case when the parent object can be reconstructed just given the type of the elements. For example, this is the case for the ring of integers and in fact for any ring element type that isn't parameterised or generic in any way.

is_domain_type(::Type{MyElem})

Return true if every element of the given element type (which may be parameterised or an abstract type) necessarily has a parent that is an integral domain, otherwise if this cannot be guaranteed, the function returns false.

For example, if MyElem was the type of elements of generic residue rings of a polynomial ring, the answer to the question would depend on the modulus of the residue ring. Therefore is_domain_type would have to return false, since we cannot guarantee that we are dealing with elements of an integral domain in general. But if the given element type was for rational integers, the answer would be true, since every rational integer has as parent the ring of rational integers, which is an integral domain.

Note that this function depends only on the type of an element and cannot access information about the object itself, or its parent.

is_exact_type(::Type{MyElem})

Return true if every element of the given type is represented exactly. For example, $p$-adic numbers, real and complex floating point numbers and power series are not exact, as we can only represent them in general with finite truncations. Similarly polynomials and matrices over inexact element types are themselves inexact.

Integers, rationals, finite fields and polynomials and matrices over them are always exact.

Note that MyElem may be parameterised or an abstract type, in which case every element of every type represented by MyElem must be exact, otherwise the function must return false.

Base.hash(f::MyElem, h::UInt)

Return a hash for the object $f$ of type UInt. This is used as a hopefully cheap way to distinguish objects that differ arithmetically.

If the object has components, e.g. the coefficients of a polynomial or elements of a matrix, these should be hashed recursively, passing the same parameter h to all levels. Each component should then be xor'd with h before combining the individual component hashes to give the final hash.

The hash functions in AbstractAlgebra.jl usually start from some fixed 64 bit hexadecimal value that has been picked at random by the library author for that type. That is then truncated to fit a UInt (in case the latter is not 64 bits). This ensures that objects that are the same arithmetically (or that have the same components), but have different types (or structures), are unlikely to hash to the same value.

deepcopy_internal(f::MyElem, dict::IdDict)

Return a copy of the given element, recursively copying all components of the object.

Obviously the parent, if it is stored in the element, should not be copied. The new element should have precisely the same parent as the old object.

For types that cannot self-reference themselves anywhere internally, the dict argument may be ignored.

In the case that internal self-references are possible, please consult the Julia documentation on how to implement deepcopy_internal.

Constructors

Outer constructors for most AbstractAlgebra types are provided by overloading the call syntax for parent objects.

If R is a parent object for a given ring we require the following constructors.

(R::MyParent)()

Return the zero object of the given ring.

(R::MyParent)(a::Integer)

Coerce the given integer into the given ring.

(R::MyParent)(a::MyElem)

If $a$ belongs to the given ring, the function returns it (without making a copy). Otherwise an error is thrown.

For parameterised rings we also require a function to coerce from the base ring into the parent ring.

(R::MyParent{T})(a::T) where T <: RingElem

Coerce $a$ into the ring $R$ if $a$ belongs to the base ring of $R$.

Basic manipulation of rings and elements

zero(R::MyParent)

Return the zero element of the given ring.

one(R::MyParent)

Return the multiplicative identity of the given ring.

iszero(f::MyElem)

Return true if the given element is the zero element of the ring it belongs to.

isone(f::MyElem)

Return true if the given element is the multiplicative identity of the ring it belongs to.

Canonicalisation

canonical_unit(f::MyElem)

When fractions are created with two elements of the given type, it is nice to be able to represent them in some kind of canonical form. This is of course not always possible. But for example, fractions of integers can be canonicalised by first removing any common factors of the numerator and denominator, then making the denominator positive.

In AbstractAlgebra.jl, the denominator would be made positive by dividing both the numerator and denominator by the canonical unit of the denominator. For a negative denominator, this would be $-1$.

For elements of a field, canonical_unit simply returns the element itself. In general, canonical_unit of an invertible element should be that element. Finally, if $a = ub$ we should have the identity canonical_unit(a) = canonical_unit(u)*canonical_unit(b).

For some rings, it is completely impractical to implement this function, in which case it may return $1$ in the given ring. The function must however always exist, and always return an element of the ring.

String I/O

show(io::IO, R::MyParent)

This should print an English description of the parent ring (to the given IO object). If the ring is parameterised, it can call the corresponding show function for any rings it depends on.

show(io::IO, f::MyElem)

This should print a human readable, textual representation of the object (to the given IO object). It can recursively call the corresponding show functions for any of its components.

Expressions

To obtain best results when printing composed types derived from other types, e.g., polynomials, the following method should be implemented.

expressify(f::MyElem; context = nothing)

which must return either Expr, Symbol, Integer or String.

For a type which implements expressify, one can automatically derive show methods supporting output as plain text, LaTeX and html by using the following:

@enable_all_show_via_expressify MyElem

This defines the following show methods for the specified type MyElem:

function Base.show(io::IO, a::MyElem)
+  show_via_expressify(io, a)
+end
+
+function Base.show(io::IO, mi::MIME"text/plain", a::MyElem)
+  show_via_expressify(io, mi, a)
+end
+
+function Base.show(io::IO, mi::MIME"text/latex", a::MyElem)
+  show_via_expressify(io, mi, a)
+end
+
+function Base.show(io::IO, mi::MIME"text/html", a::MyElem)
+  show_via_expressify(io, mi, a)
+end

As an example, assume that an object f of type MyElem has two components f.a and f.b of integer type, which should be printed as a^b, this can be implemented as

expressify(f::MyElem; context = nothing) = Expr(:call, :^, f.a, f.b)

If f.a and f.b themselves are objects that can be expressified, this can be implemented as

function expressify(f::MyElem; context = nothing)
+  return Expr(:call, :^, expressify(f.a, context = context),
+                         expressify(f.b, context = context))
+end

As noted above, expressify should return an Expr, Symbol, Integer or String. The rendering of such expressions with a particular MIME type to an output context is controlled by the following rules which are subject to change slightly in future versions of AbstracAlgebra.

Integer: The printing of integers is straightforward and automatically includes transformations such as 1 + (-2)*x => 1 - 2*x as this is cumbersome to implement per-type.

Symbol: Since variable names are stored as mere symbols in AbstractAlgebra, some transformations related to subscripts are applied to symbols automatically in latex output. The \operatorname{ in the following table is actually replaced with the more portable \mathop{\mathrm{.

expressifylatex output
Symbol("a")a
Symbol("α"){\alpha}
Symbol("x1")\operatorname{x1}
Symbol("xy_1")\operatorname{xy}_{1}
Symbol("sin")\operatorname{sin}
Symbol("sin_cos")\operatorname{sin\_cos}
Symbol("sin_1")\operatorname{sin}_{1}
Symbol("sin_cos_1")\operatorname{sin\_cos}_{1}
Symbol("αaβb_1_2")\operatorname{{\alpha}a{\beta}b}_{1,2}

Expr: These are the most versatile as the Expr objects themselves contain a symbolic head and any number of arguments. What looks like f(a,b) in textual output is Expr(:call, :f, :a, :b) under the hood. AbstractAlgebra currently contains the following printing rules for such expressions.

expressifyoutputlatex notes
Expr(:call, :+, a, b)a + b
Expr(:call, :*, a, b)a*bone space for implied multiplication
Expr(:call, :cdot, a, b)a * ba real \cdot is used
Expr(:call, :^, a, b)a^bmay include some courtesy parentheses
Expr(:call, ://, a, b)a//bwill create a fraction box
Expr(:call, :/, a, b)a/bwill not create a fraction box
Expr(:call, a, b, c)a(b, c)
Expr(:ref, a, b, c)a[b, c]
Expr(:vcat, a, b)[a; b]actually vertical
Expr(:vect, a, b)[a, b]
Expr(:tuple, a, b)(a, b)
Expr(:list, a, b){a, b}
Expr(:series, a, b)a, b
Expr(:sequence, a, b)ab
Expr(:row, a, b)a bcombine with :vcat to make matrices
Expr(:hcat, a, b)a b

String: Strings are printed verbatim and should only be used as a last resort as they provide absolutely no precedence information on their contents.

Unary operations

-(f::MyElem)

Return $-f$.

Binary operations

+(f::MyElem, g::MyElem)
+-(f::MyElem, g::MyElem)
+*(f::MyElem, g::MyElem)

Return $f + g$, $f - g$ or $fg$, respectively.

Comparison

==(f::MyElem, g::MyElem)

Return true if $f$ and $g$ are arithmetically equal. In the case where the two elements are inexact, the function returns true if they agree to the minimum precision of the two.

isequal(f::MyElem, g::MyElem)

For exact rings, this should return the same thing as == above. For inexact rings, this returns true only if the two elements are arithmetically equal and have the same precision.

Powering

^(f::MyElem, e::Int)

Return $f^e$. The function should throw a DomainError() if negative exponents don't make sense but are passed to the function.

Exact division

divexact(f::MyElem, g::MyElem; check::Bool=true)

Return $f/g$, though note that Julia uses / for floating point division. Here we mean exact division in the ring, i.e. return $q$ such that $f = gq$. A DivideError() should be thrown if $g$ is zero.

If check=true the function should check that the division is exact and throw an exception if not.

If check=false the check may be omitted for performance reasons. The behaviour is then undefined if a division is performed that is not exact. This may include throwing an exception, returning meaningless results, hanging or crashing. The function should only be called with check=false if it is already known that the division will be exact.

Inverse

inv(f::MyElem)

Return the inverse of $f$, i.e. $1/f$, though note that Julia uses / for floating point division. Here we mean exact division in the ring.

A fallback for this function is provided in terms of divexact so an implementation can be omitted if preferred.

Unsafe operators

To speed up polynomial and matrix arithmetic, it sometimes makes sense to mutate values in place rather than replace them with a newly created object every time they are modified.

For this purpose, certain mutating operators are required. In order to support immutable types (struct in Julia) and systems that don't have in-place operators, all unsafe operators must return the (ostensibly) mutated value. Only the returned value is used in computations, so this lifts the requirement that the unsafe operators actually mutate the value.

Note the exclamation point is a convention, which indicates that the object may be mutated in-place.

To make use of these functions, one must be certain that no other references are held to the object being mutated, otherwise those values will also be changed!

The results of deepcopy and all arithmetic operations, including powering and division can be assumed to be new objects without other references being held, as can objects returned from constructors.

Note

It is important to recognise that R(a) where R is the ring a belongs to, does not create a new value. For this case, use deepcopy(a).

zero!(f::MyElem)

Set the value $f$ to zero in place. Return the mutated value.

mul!(c::MyElem, a::MyElem, b::MyElem)

Set $c$ to the value $ab$ in place. Return the mutated value. Aliasing is permitted.

add!(c::MyElem, a::MyElem, b::MyElem)

Set $c$ to the value $a + b$ in place. Return the mutated value. Aliasing is permitted.

addeq!(a::MyElem, b::MyElem)

Set $a$ to $a + b$ in place. Return the mutated value. Aliasing is permitted.

Random generation

The random functions are only used for test code to generate test data. They therefore don't need to provide any guarantees on uniformity, and in fact, test values that are known to be a good source of corner cases can be supplied.

rand(R::MyParent, v...)

Return a random element in the given ring of the specified size.

There can be as many arguments as is necessary to specify the size of the test example which is being produced.

Promotion rules

AbstractAlgebra currently has a very simple coercion model. With few exceptions only simple coercions are supported. For example if $x \in \mathbb{Z}$ and $y \in \mathbb{Z}[x]$ then $x + y$ can be computed by coercing $x$ into the same ring as $y$ and then adding in that ring.

Complex coercions such as adding elements of $\mathbb{Q}$ and $\mathbb{Z}[x]$ are not supported, as this would require finding and creating a common overring in which the elements could be added.

AbstractAlgebra supports simple coercions by overloading parent object call syntax R(x) to coerce the object x into the ring R. However, to coerce elements up a tower of rings, one needs to also have a promotion system similar to Julia's type promotion system.

As for Julia, AbstractAlgebra's promotion system only specifies what happens to types. It is the coercions themselves that must deal with the mathematical situation at the level of rings, including checking that the object can even be coerced into the given ring.

We now describe the required AbstractAlgebra type promotion rules.

For every ring, one wants to be able to coerce integers into the ring. And for any ring constructed over a base ring, one would like to be able to coerce from the base ring into the ring.

The required promotion rules to support this look a bit different depending on whether the element type is parameterised or not and whether it is built on a base ring.

For ring element types MyElem that are neither parameterised nor built over a base ring, the promotion rules can be defined as follows:

promote_rule(::Type{MyElem}, ::Type{T}) where {T <: Integer} = MyElem

For ring element types MyElem that aren't parameterised, but which have a base ring with concrete element type T the promotion rules can be defined as follows:

promote_rule(::Type{MyElem}, ::Type{U}) where U <: Integer = MyElem
promote_rule(::Type{MyElem}, ::Type{T}) = MyElem

For ring element types MyElem{T} that are parameterised by the type of elements of the base ring, the promotion rules can be defined as follows:

promote_rule(::Type{MyElem{T}}, ::Type{MyElem{T}}) where T <: RingElement = MyElem{T}
function promote_rule(::Type{MyElem{T}}, ::Type{U}) where {T <: RingElement, U <: RingElement}
+   promote_rule(T, U) == T ? MyElem{T} : Union{}
+end

Required functionality for inexact rings

Approximation (floating point and ball arithmetic only)

isapprox(f::MyElem, g::MyElem; atol::Real=sqrt(eps()))

This is used by test code that uses rings involving floating point or ball arithmetic. The function should return true if all components of $f$ and $g$ are equal to within the square root of the Julia epsilon, since numerical noise may make an exact comparison impossible.

For parameterised rings over an inexact ring, we also require the following ad hoc approximation functionality.

isapprox(f::MyElem{T}, g::T; atol::Real=sqrt(eps())) where T <: RingElem
isapprox(f::T, g::MyElem{T}; atol::Real=sqrt(eps())) where T <: RingElem

These notionally coerce the element of the base ring into the parameterised ring and do a full comparison.

Optional functionality

Some functionality is difficult or impossible to implement for all rings in the system. If it is provided, additional functionality or performance may become available. Here is a list of all functions that are considered optional and can't be relied on by generic functions in the AbstractAlgebra Ring interface.

It may be that no algorithm, or no efficient algorithm is known to implement these functions. As these functions are optional, they do not need to exist. Julia will already inform the user that the function has not been implemented if it is called but doesn't exist.

Optional basic manipulation functionality

is_unit(f::MyElem)

Return true if the given element is a unit in the ring it belongs to.

is_zero_divisor(f::MyElem)

Return true if the given element is a zero divisor in the ring it belongs to. When this function does not exist for a given ring then the total ring of fractions may not be usable over that ring. All fields in the system have a fallback defined for this function.

characteristic(R::MyParent)

Return the characteristic of the ring. The function should not be defined if it is not possible to unconditionally give the characteristic. AbstractAlgebra will raise an exception is such cases.

Optional binary ad hoc operators

By default, ad hoc operations are handled by AbstractAlgebra.jl if they are not defined explicitly, by coercing both operands into the same ring and then performing the required operation.

In some cases, e.g. for matrices, this leads to very inefficient behaviour. In such cases, it is advised to implement some of these operators explicitly.

It can occasionally be worth adding a separate set of ad hoc binary operators for the type Int, if this can be done more efficiently than for arbitrary Julia Integer types.

+(f::MyElem, c::Integer)
+-(f::MyElem, c::Integer)
+*(f::MyElem, c::Integer)
+(c::Integer, f::MyElem)
+-(c::Integer, f::MyElem)
+*(c::Integer, f::MyElem)

For parameterised types, it is also sometimes more performant to provide explicit ad hoc operators with elements of the base ring.

+(f::MyElem{T}, c::T) where T <: RingElem
+-(f::MyElem{T}, c::T) where T <: RingElem
+*(f::MyElem{T}, c::T) where T <: RingElem
+(c::T, f::MyElem{T}) where T <: RingElem
+-(c::T, f::MyElem{T}) where T <: RingElem
+*(c::T, f::MyElem{T}) where T <: RingElem

Optional ad hoc comparisons

==(f::MyElem, c::Integer)
==(c::Integer, f::MyElem)
==(f::MyElem{T}, c:T) where T <: RingElem
==(c::T, f::MyElem{T}) where T <: RingElem

Optional ad hoc exact division functions

divexact(a::MyElem{T}, b::T) where T <: RingElem
divexact(a::MyElem, b::Integer)

Optional powering functions

^(f::MyElem, e::BigInt)

In case $f$ cannot explode in size when powered by a very large integer, and it is practical to do so, one may provide this function to support powering with BigInt exponents (or for external modules, any other big integer type).

Optional unsafe operators

addmul!(c::MyElem, a::MyElem, b::MyElem, t::MyElem)

Set $c = c + ab$ in-place. Return the mutated value. The value $t$ should be a temporary of the same type as $a$, $b$ and $c$, which can be used arbitrarily by the implementation to speed up the computation. Aliasing between $a$, $b$ and $c$ is permitted.

Minimal example of ring implementation

Here is a minimal example of implementing the Ring Interface for a constant polynomial type (i.e. polynomials of degree less than one).

# ConstPoly.jl : Implements constant polynomials
+
+using AbstractAlgebra
+
+using Random: Random, SamplerTrivial, GLOBAL_RNG
+using RandomExtensions: RandomExtensions, Make2, AbstractRNG
+
+import AbstractAlgebra: parent_type, elem_type, base_ring, parent, is_domain_type,
+       is_exact_type, canonical_unit, isequal, divexact, zero!, mul!, add!, addeq!,
+       get_cached!, is_unit, characteristic, Ring, RingElem, expressify
+
+import Base: show, +, -, *, ^, ==, inv, isone, iszero, one, zero, rand,
+             deepcopy_internal, hash
+
+mutable struct ConstPolyRing{T <: RingElement} <: Ring
+   base_ring::Ring
+
+   function ConstPolyRing{T}(R::Ring, cached::Bool) where T <: RingElement
+      return get_cached!(ConstPolyID, R, cached) do
+         new{T}(R)
+      end::ConstPolyRing{T}
+   end
+end
+
+const ConstPolyID = AbstractAlgebra.CacheDictType{Ring, ConstPolyRing}()
+   
+mutable struct ConstPoly{T <: RingElement} <: RingElem
+   c::T
+   parent::ConstPolyRing{T}
+
+   function ConstPoly{T}(c::T) where T <: RingElement
+      return new(c)
+   end
+end
+
+# Data type and parent object methods
+
+parent_type(::Type{ConstPoly{T}}) where T <: RingElement = ConstPolyRing{T}
+
+elem_type(::Type{ConstPolyRing{T}}) where T <: RingElement = ConstPoly{T}
+
+base_ring(R::ConstPolyRing) = R.base_ring
+
+parent(f::ConstPoly) = f.parent
+
+is_domain_type(::Type{ConstPoly{T}}) where T <: RingElement = is_domain_type(T)
+
+is_exact_type(::Type{ConstPoly{T}}) where T <: RingElement = is_exact_type(T)
+
+function hash(f::ConstPoly, h::UInt)
+   r = 0x65125ab8e0cd44ca
+   return xor(r, hash(f.c, h))
+end
+
+function deepcopy_internal(f::ConstPoly{T}, dict::IdDict) where T <: RingElement
+   r = ConstPoly{T}(deepcopy_internal(f.c, dict))
+   r.parent = f.parent # parent should not be deepcopied
+   return r
+end
+
+# Basic manipulation
+
+zero(R::ConstPolyRing) = R()
+
+one(R::ConstPolyRing) = R(1)
+
+iszero(f::ConstPoly) = iszero(f.c)
+
+isone(f::ConstPoly) = isone(f.c)
+
+is_unit(f::ConstPoly) = is_unit(f.c)
+
+characteristic(R::ConstPolyRing) = characteristic(base_ring(R))
+
+# Canonical unit
+
+canonical_unit(f::ConstPoly) = canonical_unit(f.c)
+
+# String I/O
+
+function show(io::IO, R::ConstPolyRing)
+   print(io, "Constant polynomials over ")
+   show(io, base_ring(R))
+end
+
+function show(io::IO, f::ConstPoly)
+   print(io, f.c)
+end
+
+# Expressification (optional)
+
+function expressify(R::ConstPolyRing; context = nothing)
+   return Expr(:sequence, Expr(:text, "Constant polynomials over "),
+                          expressify(base_ring(R), context = context))
+end
+
+function expressify(f::ConstPoly; context = nothing)
+   return expressify(f.c, context = context)
+end
+
+# Unary operations
+
+function -(f::ConstPoly)
+   R = parent(f)
+   return R(-f.c)
+end
+
+# Binary operations
+
+function +(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement
+   parent(f) != parent(g) && error("Incompatible rings")
+   R = parent(f)
+   return R(f.c + g.c)
+end
+
+function -(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement
+   parent(f) != parent(g) && error("Incompatible rings")
+   R = parent(f)
+   return R(f.c - g.c)
+end
+
+function *(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement
+   parent(f) != parent(g) && error("Incompatible rings")
+   R = parent(f)
+   return R(f.c*g.c)
+end
+
+# Comparison
+
+function ==(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement
+   parent(f) != parent(g) && error("Incompatible rings")
+   return f.c == g.c
+end
+
+function isequal(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement
+   parent(f) != parent(g) && error("Incompatible rings")
+   return isequal(f.c, g.c)
+end
+
+# Powering need not be implemented if * is
+
+# Exact division
+
+function divexact(f::ConstPoly{T}, g::ConstPoly{T}; check::Bool = true) where T <: RingElement
+   parent(f) != parent(g) && error("Incompatible rings")
+   R = parent(f)
+   return R(divexact(f.c, g.c, check = check))
+end
+
+# Inverse
+
+function inv(f::ConstPoly)
+   R = parent(f)
+   return R(AbstractAlgebra.inv(f.c))
+end
+
+# Unsafe operators
+
+function zero!(f::ConstPoly)
+   f.c = zero(base_ring(parent(f)))
+   return f
+end
+
+function mul!(f::ConstPoly{T}, g::ConstPoly{T}, h::ConstPoly{T}) where T <: RingElement
+   f.c = g.c*h.c
+   return f
+end
+
+function add!(f::ConstPoly{T}, g::ConstPoly{T}, h::ConstPoly{T}) where T <: RingElement
+   f.c = g.c + h.c
+   return f
+end
+
+function addeq!(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement
+   f.c += g.c
+   return f
+end
+
+# Random generation
+
+RandomExtensions.maketype(R::ConstPolyRing, _) = elem_type(R)
+
+rand(rng::AbstractRNG, sp::SamplerTrivial{<:Make2{ConstPoly,ConstPolyRing}}) =
+        sp[][1](rand(rng, sp[][2]))
+
+rand(rng::AbstractRNG, R::ConstPolyRing, n::AbstractUnitRange{Int}) = R(rand(rng, n))
+
+rand(R::ConstPolyRing, n::AbstractUnitRange{Int}) = rand(Random.GLOBAL_RNG, R, n)
+
+# Promotion rules
+
+promote_rule(::Type{ConstPoly{T}}, ::Type{ConstPoly{T}}) where T <: RingElement = ConstPoly{T}
+
+function promote_rule(::Type{ConstPoly{T}}, ::Type{U}) where {T <: RingElement, U <: RingElement}
+   promote_rule(T, U) == T ? ConstPoly{T} : Union{}
+end
+
+# Constructors
+
+function (R::ConstPolyRing{T})() where T <: RingElement
+   r = ConstPoly{T}(base_ring(R)(0))
+   r.parent = R
+   return r
+end
+
+function (R::ConstPolyRing{T})(c::Integer) where T <: RingElement
+   r = ConstPoly{T}(base_ring(R)(c))
+   r.parent = R
+   return r
+end
+
+# Needed to prevent ambiguity
+function (R::ConstPolyRing{T})(c::T) where T <: Integer
+   r = ConstPoly{T}(base_ring(R)(c))
+   r.parent = R
+   return r
+end
+
+function (R::ConstPolyRing{T})(c::T) where T <: RingElement
+   base_ring(R) != parent(c) && error("Unable to coerce element")
+   r = ConstPoly{T}(c)
+   r.parent = R
+   return r
+end
+
+function (R::ConstPolyRing{T})(f::ConstPoly{T}) where T <: RingElement
+   R != parent(f) && error("Unable to coerce element")
+   return f
+end
+
+# Parent constructor
+
+function ConstantPolynomialRing(R::Ring, cached::Bool=true)
+   T = elem_type(R)
+   return ConstPolyRing{T}(R, cached)
+end

The above implementation of ConstantPolynomialRing may be tested as follows.

using Test
+include(joinpath(pathof(AbstractAlgebra), "..", "..", "test", "Rings-conformance-tests.jl"))
+
+S, _ = polynomial_ring(QQ, "x")
+
+function test_elem(R::ConstPolyRing{elem_type(S)})
+   return R(rand(base_ring(R), 1:6, -999:999))
+end
+
+test_Ring_interface(ConstantPolynomialRing(S))
diff --git a/v0.37.6/ring_introduction/index.html b/v0.37.6/ring_introduction/index.html new file mode 100644 index 0000000000..1c7191e5dc --- /dev/null +++ b/v0.37.6/ring_introduction/index.html @@ -0,0 +1,2 @@ + +Introduction · AbstractAlgebra.jl

Introduction

A rich ring hierarchy is provided, supporting both commutative and noncommutative rings.

A number of basic rings are provided, such as the integers, integers mod n and numerous fields.

A recursive rings implementation is then built on top of the basic rings via a number of generic ring constructions. These include univariate and multivariate polynomials and power series, univariate Laurent and Puiseux series, residue rings, matrix algebras, etc.

Where possible, these constructions can be built on top of one another in generic towers.

The ring hierarchy can be extended by implementing new rings to follow one or more ring interfaces. Generic functionality provided by the system is then automatically available for the new rings. These implementations can either be generic or can be specialised implementations provided by, for example, a C library.

In most cases, the interfaces consist of a set of constructors and functions that must be implemented to satisfy the interface. These are the functions that the generic code relies on being available.

diff --git a/v0.37.6/search_index.js b/v0.37.6/search_index.js new file mode 100644 index 0000000000..5efbe09fdb --- /dev/null +++ b/v0.37.6/search_index.js @@ -0,0 +1,3 @@ +var documenterSearchIndex = {"docs": +[{"location":"field_introduction/#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"field_introduction/","page":"Introduction","title":"Introduction","text":"A number of basic fields are provided, such as the rationals, finite fields, the real field, etc.","category":"page"},{"location":"field_introduction/","page":"Introduction","title":"Introduction","text":"Various generic field constructions can then be made recursively on top of these basic fields. For example, fraction fields, residue fields, function fields, etc.","category":"page"},{"location":"field_introduction/","page":"Introduction","title":"Introduction","text":"From the point of view of the system, all fields are rings and whether an object is a ring/field or an element thereof can be determined at the type level. There are abstract types for all field and for all field element types.","category":"page"},{"location":"field_introduction/","page":"Introduction","title":"Introduction","text":"The field hierarchy can be extended by implementing new fields to follow one or more field interfaces, including the interface that all fields must follow. Once an interface is satisfied, all the corresponding generic functionality will work over the new field.","category":"page"},{"location":"field_introduction/","page":"Introduction","title":"Introduction","text":"Implementations of new fields can either be generic or can be specialised implementations provided by, for example, a C library.","category":"page"},{"location":"map_introduction/#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"map_introduction/","page":"Introduction","title":"Introduction","text":"Maps in AbstractAlgebra model maps on sets f D to C for some domain D and codomain C, which have no real limitations except that elements of the codomain and domain be represented by element objects in the system.","category":"page"},{"location":"map_introduction/","page":"Introduction","title":"Introduction","text":"Maps f D to C in AbstractAlgebra are modeled by Julia objects that are able to be called on a single element d in D of the domain to yield an element f(d) in C of the codomain. We say that the map is being applied.","category":"page"},{"location":"map_introduction/","page":"Introduction","title":"Introduction","text":"Maps can be constructed from Julia functions, or they can be represented by some other kind of data, e.g. a matrix, or built up from other maps.","category":"page"},{"location":"map_introduction/","page":"Introduction","title":"Introduction","text":"Maps in AbstractAlgebra have a domain and codomain, can be applied, composed with other maps. Various special kinds of map provide more functionality.","category":"page"},{"location":"map_introduction/","page":"Introduction","title":"Introduction","text":"For details please refer to the Map Interface documentation.","category":"page"},{"location":"map_introduction/","page":"Introduction","title":"Introduction","text":"For example, there are functional maps which wrap a Julia function, cached maps which cache values so they do not have to be recomputed each time they are applied to the same inputs and various kinds of maps with inverses, e.g. maps with sections, retractions and full inverses.","category":"page"},{"location":"map_introduction/","page":"Introduction","title":"Introduction","text":"The map system uses a complex four parameter Map type, however various helper functions are provided to make it easier to work with.","category":"page"},{"location":"visualizing_types/#Visualization-of-the-types-of-AbstractAlgebra.jl","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"","category":"section"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"AbstractAlgebra.jl implements a couple of abstract types which can be extended.","category":"page"},{"location":"visualizing_types/#Abstract-parents","page":"Visualization of the types of AbstractAlgebra.jl","title":"Abstract parents","text":"","category":"section"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"The following diagram shows a complete list of all abstract types in AbstractAlgebra.jl.","category":"page"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"(Image: Diagram of parent types)","category":"page"},{"location":"visualizing_types/#Abstract-elements","page":"Visualization of the types of AbstractAlgebra.jl","title":"Abstract elements","text":"","category":"section"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"Similarly the following diagram shows a complete list of all abstract types in AbstractAlgebra.jl.","category":"page"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"(Image: Diagram of element types)","category":"page"},{"location":"visualizing_types/#Concrete-types-in-AbstractAlgebra.jl","page":"Visualization of the types of AbstractAlgebra.jl","title":"Concrete types in AbstractAlgebra.jl","text":"","category":"section"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"Until now we have discussed the abstract types of AbstractAlgebra.jl. Under this subsection we will instead give some examples of concrete types in AbstractAlgebra.jl.","category":"page"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"In parentheses we put the types of the corresponding parent objects.","category":"page"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"Perm{<:Integer} (SymmetricGroup{<:Integer})\nGFElem{<:Integer} (GFField{<:Integer})","category":"page"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"We also think of various Julia types as though they were AbstractAlgebra.jl types:","category":"page"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"BigInt (Integers{BigInt})\nRational{BigInt} (Rationals{BigInt})","category":"page"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"Then there are various types for generic constructions over a base ring. They are all parameterised by a type T which is the type of the elements of the base ring they are defined over.","category":"page"},{"location":"visualizing_types/","page":"Visualization of the types of AbstractAlgebra.jl","title":"Visualization of the types of AbstractAlgebra.jl","text":"Generic.Poly{T} (Generic.PolyRing{T})\nGeneric.MPoly{T} (Generic.MPolyRing{T})\nGeneric.RelSeries{T} (Generic.RelPowerSeriesRing{T})\nGeneric.AbsSeries{T} (Generic.AbsPowerSeriesRing{T})\nGeneric.LaurentSeriesRingElem{T} (Generic.LaurentSeriesRing{T})\nGeneric.LaurentSeriesFieldElem{T} (Generic.LaurentSeriesField{T})\nGeneric.ResidueRingElem{T} (Generic.ResidueRing{T})\nGeneric.FracFieldElem{T} (Generic.FracField{T})\nGeneric.Mat{T} (Generic.MatSpace{T})","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend\nDocTestFilters = r\"[0-9\\.]+ seconds \\(.*\\)\"","category":"page"},{"location":"ytabs/#Partitions-and-Young-tableaux","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"AbstractAlgebra.jl provides basic support for computations with Young tableaux, skew diagrams and the characters of permutation groups (implemented src/generic/YoungTabs.jl). All functionality of permutations is accessible in the Generic submodule.","category":"page"},{"location":"ytabs/#Partitions","page":"Partitions and Young tableaux","title":"Partitions","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"The basic underlying object for those concepts is Partition of a number n, i.e. a sequence of positive integers n_1 ldots n_k which sum to n. Partitions in AbstractAlgebra.jl are represented internally by non-increasing Vectors of Ints. Partitions are printed using the standard notation, i.e. 9 = 4 + 2 + 1 + 1 + 1 is shown as 4_1 2_1 1_3 with the subscript indicating the count of a summand in the partition.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Generic.Partition","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.Partition","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.Partition","text":"Partition(part::Vector{<:Integer}[, check::Bool=true]) <: AbstractVector{Int}\n\nRepresent integer partition in the non-increasing order.\n\npart will be sorted, if necessary. Checks for validity of input can be skipped by calling the (inner) constructor with false as the second argument.\n\nFunctionally Partition is a thin wrapper over Vector{Int}.\n\nFieldnames:\n\nn::Int - the partitioned number\npart::Vector{Int} - a non-increasing sequence of summands of n.\n\nExamples\n\njulia> p = Partition([4,2,1,1,1])\n4₁2₁1₃\n\njulia> p.n == sum(p.part)\ntrue\n\n\n\n\n\n","category":"type"},{"location":"ytabs/#Array-interface","page":"Partitions and Young tableaux","title":"Array interface","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Partition is a concrete (immutable) subtype of AbstractVector{Integer} and implements the standard Array interface.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"size(::Generic.Partition)\ngetindex(::Generic.Partition, i::Integer)","category":"page"},{"location":"ytabs/#Base.size-Tuple{AbstractAlgebra.Generic.Partition}","page":"Partitions and Young tableaux","title":"Base.size","text":"size(p::Partition)\n\nReturn the size of the vector which represents the partition.\n\nExamples\n\njulia> p = Partition([4,3,1]); size(p)\n(3,)\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#Base.getindex-Tuple{AbstractAlgebra.Generic.Partition, Integer}","page":"Partitions and Young tableaux","title":"Base.getindex","text":"getindex(p::Partition, i::Integer)\n\nReturn the i-th part (in non-increasing order) of the partition.\n\n\n\n\n\n","category":"method"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"These functions work on the level of p.part vector.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"One can easily iterate over all partitions of n using the Generic.partitions function.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Generic.partitions","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.partitions","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.partitions","text":"partitions(n::Integer)\n\nReturn the vector of all permutations of n. For an unsafe generator version see partitions!.\n\nExamples\n\njulia> Generic.partitions(5)\n7-element Vector{AbstractAlgebra.Generic.Partition{Int64}}:\n 1₅\n 2₁1₃\n 3₁1₂\n 2₂1₁\n 4₁1₁\n 3₁2₁\n 5₁\n\n\n\n\n\n","category":"function"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"You may also have a look at JuLie.jl package for more utilities related to partitions.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"The number of all partitions can be computed by the hidden function _numpart. Much faster implementation is available in Nemo.jl.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Generic._numpart","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic._numpart","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic._numpart","text":"_numpart(n::Integer)\n\nReturn the number of all distinct integer partitions of n. The function uses Euler pentagonal number theorem for recursive formula. For more details see OEIS sequence A000041. Note that _numpart(0) = 1 by convention.\n\n\n\n\n\n","category":"function"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Since Partition is a subtype of AbstractVector generic functions which operate on vectors should work in general. However the meaning of conj has been changed to agree with the traditional understanding of conjugation of Partitions:","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"conj(::Generic.Partition)\nconj(::Generic.Partition, v::Vector)","category":"page"},{"location":"ytabs/#Base.conj-Tuple{AbstractAlgebra.Generic.Partition}","page":"Partitions and Young tableaux","title":"Base.conj","text":"conj(part::Partition)\n\nReturn the conjugated partition of part, i.e. the partition corresponding to the Young diagram of part reflected through the main diagonal.\n\nExamples\n\njulia> p = Partition([4,2,1,1,1])\n4₁2₁1₃\n\njulia> conj(p)\n5₁2₁1₂\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#Base.conj-Tuple{AbstractAlgebra.Generic.Partition, Vector}","page":"Partitions and Young tableaux","title":"Base.conj","text":"conj(part::Partition, v::Vector)\n\nReturn the conjugated partition of part together with permuted vector v.\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#Young-Diagrams-and-Young-Tableaux","page":"Partitions and Young tableaux","title":"Young Diagrams and Young Tableaux","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Mathematically speaking Young diagram is a diagram which consists of rows of square boxes such that the number of boxes in each row is no less than the number of boxes in the previous row. For example partition 4_1 3_2 1 represents the following diagram.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"┌───┬───┬───┬───┐\n│ │ │ │ │\n├───┼───┼───┼───┘\n│ │ │ │\n├───┼───┼───┤\n│ │ │ │\n├───┼───┴───┘\n│ │\n└───┘","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Young Tableau is formally a bijection between the set of boxes of a Young Diagram and the set 1 ldots n. If a bijection is increasing along rows and columns of the diagram it is referred to as standard. For example","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┼───┤\n│ 8 │ 9 │10 │\n├───┼───┴───┘\n│11 │\n└───┘","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"is a standard Young tableau of 4_1 3_2 1 where the bijection assigns consecutive natural numbers to consecutive (row-major) cells.","category":"page"},{"location":"ytabs/#Constructors","page":"Partitions and Young tableaux","title":"Constructors","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"In AbstractAlgebra.jl Young tableau are implemented as essentially row-major sparse matrices, i.e. YoungTableau <: AbstractMatrix{Int} but only the defining Partition and the (row-major) fill-vector is stored.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Generic.YoungTableau","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.YoungTableau","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.YoungTableau","text":"YoungTableau(part::Partition[, fill::Vector{Int}=collect(1:sum(part))]) <: AbstractMatrix{Int}\n\nReturn the Young tableaux of partition part, filled linearly by fill vector. Note that fill vector is in row-major format.\n\nFields:\n\npart - the partition defining Young diagram\nfill - the row-major fill vector: the entries of the diagram.\n\nExamples\n\njulia> p = Partition([4,3,1]); y = YoungTableau(p)\n┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┴───┘\n│ 8 │\n└───┘\n\njulia> y.part\n4₁3₁1₁\n\njulia> y.fill\n8-element Vector{Int64}:\n 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n\n\n\n\n\n","category":"type"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"For convenience there exists an alternative constructor of YoungTableau, which accepts a vector of integers and constructs Partition internally.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"YoungTableau(p::Vector{Integer}[, fill=collect(1:sum(p))])","category":"page"},{"location":"ytabs/#Array-interface-2","page":"Partitions and Young tableaux","title":"Array interface","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"To make YoungTableaux array-like we implement the following functions:","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"size(::Generic.YoungTableau)\ngetindex(::Generic.YoungTableau, n::Integer)","category":"page"},{"location":"ytabs/#Base.size-Tuple{AbstractAlgebra.Generic.YoungTableau}","page":"Partitions and Young tableaux","title":"Base.size","text":"size(Y::YoungTableau)\n\nReturn size of the smallest array containing Y, i.e. the tuple of the number of rows and the number of columns of Y.\n\nExamples\n\njulia> y = YoungTableau([4,3,1]); size(y)\n(3, 4)\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#Base.getindex-Tuple{AbstractAlgebra.Generic.YoungTableau, Integer}","page":"Partitions and Young tableaux","title":"Base.getindex","text":"getindex(Y::YoungTableau, n::Integer)\n\nReturn the column-major linear index into the size(Y)-array. If a box is outside of the array return 0.\n\nExamples\n\njulia> y = YoungTableau([4,3,1])\n┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┴───┘\n│ 8 │\n└───┘\n\njulia> y[1]\n1\n\njulia> y[2]\n5\n\njulia> y[4]\n2\n\njulia> y[6]\n0\n\n\n\n\n\n","category":"method"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Also the double-indexing corresponds to (row, column) access to an abstract array.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"julia> y = YoungTableau([4,3,1])\n┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┴───┘\n│ 8 │\n└───┘\n\njulia> y[1,2]\n2\n\njulia> y[2,3]\n7\n\njulia> y[3,2]\n0","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Functions defined for AbstractArray type based on those (e.g. length) should work. Again, as in the case of Partition the meaning of conj is altered to reflect the usual meaning for Young tableaux:","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"conj(::Generic.YoungTableau)","category":"page"},{"location":"ytabs/#Base.conj-Tuple{AbstractAlgebra.Generic.YoungTableau}","page":"Partitions and Young tableaux","title":"Base.conj","text":"conj(Y::YoungTableau)\n\nReturn the conjugated tableau, i.e. the tableau reflected through the main diagonal.\n\nExamples\n\njulia> y = YoungTableau([4,3,1])\n┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┴───┘\n│ 8 │\n└───┘\n\njulia> conj(y)\n┌───┬───┬───┐\n│ 1 │ 5 │ 8 │\n├───┼───┼───┘\n│ 2 │ 6 │\n├───┼───┤\n│ 3 │ 7 │\n├───┼───┘\n│ 4 │\n└───┘\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#Pretty-printing","page":"Partitions and Young tableaux","title":"Pretty-printing","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Similarly to permutations we have two methods of displaying Young Diagrams:","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Generic.setyoungtabstyle","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.setyoungtabstyle","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.setyoungtabstyle","text":"setyoungtabstyle(format::Symbol)\n\nSelect the style in which Young tableaux are displayed (in REPL or in general as string). This can be either\n\n:array - as matrices of integers, or\n:diagram - as filled Young diagrams (the default).\n\nThe difference is purely esthetical.\n\nExamples\n\njulia> Generic.setyoungtabstyle(:array)\n:array\n\njulia> p = Partition([4,3,1]); YoungTableau(p)\n 1 2 3 4\n 5 6 7\n 8\n\njulia> Generic.setyoungtabstyle(:diagram)\n:diagram\n\njulia> YoungTableau(p)\n┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┴───┘\n│ 8 │\n└───┘\n\n\n\n\n\n","category":"function"},{"location":"ytabs/#Ulitility-functions","page":"Partitions and Young tableaux","title":"Ulitility functions","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"matrix_repr(::Generic.YoungTableau)\nfill!(::Generic.YoungTableau, ::AbstractVector{<:Integer})","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.matrix_repr-Tuple{AbstractAlgebra.Generic.YoungTableau}","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.matrix_repr","text":"matrix_repr(a::Perm)\n\nReturn the permutation matrix as a sparse matrix representing a via natural embedding of the permutation group into the general linear group over mathbbZ.\n\nExamples\n\njulia> p = Perm([2,3,1])\n(1,2,3)\n\njulia> matrix_repr(p)\n3×3 SparseArrays.SparseMatrixCSC{Int64, Int64} with 3 stored entries:\n ⋅ 1 ⋅\n ⋅ ⋅ 1\n 1 ⋅ ⋅\n\njulia> Array(ans)\n3×3 Matrix{Int64}:\n 0 1 0\n 0 0 1\n 1 0 0\n\n\n\n\n\nmatrix_repr(Y::YoungTableau)\n\nConstruct sparse integer matrix representing the tableau.\n\nExamples\n\njulia> y = YoungTableau([4,3,1]);\n\n\njulia> matrix_repr(y)\n3×4 SparseArrays.SparseMatrixCSC{Int64, Int64} with 8 stored entries:\n 1 2 3 4\n 5 6 7 ⋅\n 8 ⋅ ⋅ ⋅\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#Base.fill!-Tuple{AbstractAlgebra.Generic.YoungTableau, AbstractVector{<:Integer}}","page":"Partitions and Young tableaux","title":"Base.fill!","text":"fill!(Y::YoungTableaux, V::Vector{<:Integer})\n\nReplace the fill vector Y.fill by V. No check if the resulting tableau is standard (i.e. increasing along rows and columns) is performed.\n\nExamples\n\njulia> y = YoungTableau([4,3,1])\n┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┴───┘\n│ 8 │\n└───┘\n\njulia> fill!(y, [2:9...])\n┌───┬───┬───┬───┐\n│ 2 │ 3 │ 4 │ 5 │\n├───┼───┼───┼───┘\n│ 6 │ 7 │ 8 │\n├───┼───┴───┘\n│ 9 │\n└───┘\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#Characters-of-permutation-groups","page":"Partitions and Young tableaux","title":"Characters of permutation groups","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Irreducible characters (at least over field of characteristic 0) of the full group of permutations S_n correspond via Specht modules to partitions of n.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"character(::Generic.Partition)\ncharacter(lambda::Generic.Partition, p::Generic.Perm)\ncharacter(lambda::Generic.Partition, mu::Generic.Partition)","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.character-Tuple{AbstractAlgebra.Generic.Partition}","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.character","text":"character(lambda::Partition)\n\nReturn the lambda-th irreducible character of permutation group on sum(lambda) symbols. The returned character function is of the following signature:\n\nchi(p::Perm[, check::Bool=true]) -> BigInt\n\nThe function checks (if p belongs to the appropriate group) can be switched off by calling chi(p, false). The values computed by chi are cached in look-up table.\n\nThe computation follows the Murnaghan-Nakayama formula: chi_lambda(sigma) = sum_textrimhook xisubset lambda(-1)^ll(lambdabackslashxi) chi_lambda backslashxi(tildesigma) where lambdabackslashxi denotes the skew diagram of lambda with xi removed, ll denotes the leg-length (i.e. number of rows - 1) and tildesigma is permutation obtained from sigma by the removal of the longest cycle.\n\nFor more details see e.g. Chapter 2.8 of Group Theory and Physics by S.Sternberg.\n\nExamples\n\njulia> G = SymmetricGroup(4)\nFull symmetric group over 4 elements\n\njulia> chi = character(Partition([3,1])); # character of the regular representation\n\n\njulia> chi(one(G))\n3\n\njulia> chi(perm\"(1,3)(2,4)\")\n-1\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#AbstractAlgebra.Generic.character-Tuple{AbstractAlgebra.Generic.Partition, Perm}","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.character","text":"character(lambda::Partition, p::Perm, check::Bool=true) -> BigInt\n\nReturn the value of lambda-th irreducible character of the permutation group on permutation p.\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#AbstractAlgebra.Generic.character-Tuple{AbstractAlgebra.Generic.Partition, AbstractAlgebra.Generic.Partition}","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.character","text":"character(lambda::Partition, mu::Partition, check::Bool=true) -> BigInt\n\nReturn the value of lambda-th irreducible character on the conjugacy class represented by partition mu.\n\n\n\n\n\n","category":"method"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"The values computed by characters are cached in an internal dictionary Dict{Tuple{BitVector,Vector{Int}}, BigInt}. Note that all of the above functions return BigInts. If you are sure that the computations do not overflow, variants of the last two functions using Int are available:","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"character(::Type{Int}, lambda::Partition, p::Perm[, check::Bool=true])\ncharacter(::Type{Int}, lambda::Partition, mu::Partition[, check::Bool=true])","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"The dimension dim lambda of the irreducible module corresponding to partition lambda can be computed using Hook length formula","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Generic.rowlength\nGeneric.collength\nhooklength\ndim(::Generic.YoungTableau)","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.rowlength","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.rowlength","text":"rowlength(Y::YoungTableau, i, j)\n\nReturn the row length of Y at box (i,j), i.e. the number of boxes in the i-th row of the diagram of Y located to the right of the (i,j)-th box.\n\nExamples\n\njulia> y = YoungTableau([4,3,1])\n┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┴───┘\n│ 8 │\n└───┘\n\njulia> Generic.rowlength(y, 1,2)\n2\n\njulia> Generic.rowlength(y, 2,3)\n0\n\njulia> Generic.rowlength(y, 3,3)\n0\n\n\n\n\n\n","category":"function"},{"location":"ytabs/#AbstractAlgebra.Generic.collength","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.collength","text":"collength(Y::YoungTableau, i, j)\n\nReturn the column length of Y at box (i,j), i.e. the number of boxes in the j-th column of the diagram of Y located below of the (i,j)-th box.\n\nExamples\n\njulia> y = YoungTableau([4,3,1])\n┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┴───┘\n│ 8 │\n└───┘\n\njulia> Generic.collength(y, 1,1)\n2\n\njulia> Generic.collength(y, 1,3)\n1\n\njulia> Generic.collength(y, 2,4)\n0\n\n\n\n\n\n","category":"function"},{"location":"ytabs/#AbstractAlgebra.Generic.hooklength","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.hooklength","text":"hooklength(Y::YoungTableau, i, j)\n\nReturn the hook-length of an element in Y at position (i,j), i.e the number of cells in the i-th row to the right of (i,j)-th box, plus the number of cells in the j-th column below the (i,j)-th box, plus 1.\n\nReturn 0 for (i,j) not in the tableau Y.\n\nExamples\n\njulia> y = YoungTableau([4,3,1])\n┌───┬───┬───┬───┐\n│ 1 │ 2 │ 3 │ 4 │\n├───┼───┼───┼───┘\n│ 5 │ 6 │ 7 │\n├───┼───┴───┘\n│ 8 │\n└───┘\n\njulia> hooklength(y, 1,1)\n6\n\njulia> hooklength(y, 1,3)\n3\n\njulia> hooklength(y, 2,4)\n0\n\n\n\n\n\n","category":"function"},{"location":"ytabs/#AbstractAlgebra.Generic.dim-Tuple{AbstractAlgebra.Generic.YoungTableau}","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.dim","text":"dim(Y::YoungTableau) -> BigInt\n\nReturn the dimension (using hook-length formula) of the irreducible representation of permutation group S_n associated the partition Y.part.\n\nSince the computation overflows easily BigInt is returned. You may perform the computation of the dimension in different type by calling dim(Int, Y).\n\nExamples\n\njulia> dim(YoungTableau([4,3,1]))\n70\n\njulia> dim(YoungTableau([3,1])) # the regular representation of S_4\n3\n\n\n\n\n\n","category":"method"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"The character associated with Y.part can also be used to compute the dimension, but as it is expected the Murnaghan-Nakayama is much slower even though (due to caching) consecutive calls are fast:","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"julia> λ = Partition(collect(12:-1:1))\n12₁11₁10₁9₁8₁7₁6₁5₁4₁3₁2₁1₁\n\njulia> @time dim(YoungTableau(λ))\n 0.224430 seconds (155.77 k allocations: 7.990 MiB)\n9079590132732747656880081324531330222983622187548672000\n\njulia> @time dim(YoungTableau(λ))\n 0.000038 seconds (335 allocations: 10.734 KiB)\n9079590132732747656880081324531330222983622187548672000\n\njulia> G = SymmetricGroup(sum(λ))\nFull symmetric group over 78 elements\n\njulia> @time character(λ, one(G))\n 0.000046 seconds (115 allocations: 16.391 KiB)\n9079590132732747656880081324531330222983622187548672000\n\njulia> @time character(λ, one(G))\n 0.001439 seconds (195 allocations: 24.453 KiB)\n9079590132732747656880081324531330222983622187548672000","category":"page"},{"location":"ytabs/#Low-level-functions-and-characters","page":"Partitions and Young tableaux","title":"Low-level functions and characters","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"As mentioned above character functions use the Murnaghan-Nakayama rule for evaluation. The implementation follows","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Dan Bernstein, The computational complexity of rules for the character table of S_n Journal of Symbolic Computation, 37 (6), 2004, p. 727-748,","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"implementing the following functions. For precise definitions and meaning please consult the paper cited.","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Generic.partitionseq\nis_rimhook(::BitVector, ::Int, ::Int)\nGeneric.MN1inner","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.partitionseq","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.partitionseq","text":"partitionseq(lambda::Partition)\n\nReturn a sequence (as BitVector) of falses and trues constructed from lambda: tracing the lower contour of the Young Diagram associated to lambda from left to right a true is inserted for every horizontal and false for every vertical step. The sequence always starts with true and ends with false.\n\n\n\n\n\npartitionseq(seq::BitVector)\n\nReturn the essential part of the sequence seq, i.e. a subsequence starting at first true and ending at last false.\n\n\n\n\n\n","category":"function"},{"location":"ytabs/#AbstractAlgebra.Generic.is_rimhook-Tuple{BitVector, Int64, Int64}","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.is_rimhook","text":"is_rimhook(R::BitVector, idx::Integer, len::Integer)\n\nR[idx:idx+len] forms a rim hook in the Young Diagram of partition corresponding to R iff R[idx] == true and R[idx+len] == false.\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#AbstractAlgebra.Generic.MN1inner","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.MN1inner","text":"MN1inner(R::BitVector, mu::Partition, t::Integer, charvals)\n\nReturn the value of lambda-th irreducible character on conjugacy class of permutations represented by partition mu, where R is the (binary) partition sequence representing lambda. Values already computed are stored in charvals::Dict{Tuple{BitVector,Vector{Int}}, Int}. This is an implementation (with slight modifications) of the Murnaghan-Nakayama formula as described in\n\nDan Bernstein,\n\"The computational complexity of rules for the character table of Sn\"\n_Journal of Symbolic Computation_, 37(6), 2004, p. 727-748.\n\n\n\n\n\n","category":"function"},{"location":"ytabs/#Skew-Diagrams","page":"Partitions and Young tableaux","title":"Skew Diagrams","text":"","category":"section"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Skew diagrams are formally differences of two Young diagrams. Given lambda and mu, two partitions of n+m and m (respectively). Suppose that each of cells of mu is a cell of lambda (i.e. parts of mu are no greater than the corresponding parts of lambda). Then the skew diagram denoted by lambdamu is the set theoretic difference the of sets of boxes, i.e. is a diagram with exactly n boxes:","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"Generic.SkewDiagram","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.SkewDiagram","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.SkewDiagram","text":"SkewDiagram(lambda::Partition, mu::Partition) <: AbstractMatrix{Int}\n\nImplements a skew diagram, i.e. a difference of two Young diagrams represented by partitions lambda and mu. (below dots symbolise the removed entries)\n\nExamples\n\njulia> l = Partition([4,3,2])\n4₁3₁2₁\n\njulia> m = Partition([3,1,1])\n3₁1₂\n\njulia> xi = SkewDiagram(l,m)\n3×4 AbstractAlgebra.Generic.SkewDiagram{Int64}:\n ⋅ ⋅ ⋅ 1\n ⋅ 1 1\n ⋅ 1\n\n\n\n\n\n\n","category":"type"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"SkewDiagram implements array interface with the following functions:","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"size(xi::Generic.SkewDiagram)\nin(t::Tuple{Integer,Integer}, xi::Generic.SkewDiagram)\ngetindex(xi::Generic.SkewDiagram, n::Integer)","category":"page"},{"location":"ytabs/#Base.size-Tuple{AbstractAlgebra.Generic.SkewDiagram}","page":"Partitions and Young tableaux","title":"Base.size","text":"size(xi::SkewDiagram)\n\nReturn the size of array where xi is minimally contained. See size(Y::YoungTableau) for more details.\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#Base.in-Tuple{Tuple{Integer, Integer}, AbstractAlgebra.Generic.SkewDiagram}","page":"Partitions and Young tableaux","title":"Base.in","text":"in(t::Tuple{Integer,Integer}, xi::SkewDiagram)\n\nCheck if box at position (i,j) belongs to the skew diagram xi.\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#Base.getindex-Tuple{AbstractAlgebra.Generic.SkewDiagram, Integer}","page":"Partitions and Young tableaux","title":"Base.getindex","text":"getindex(xi::SkewDiagram, n::Integer)\n\nReturn 1 if linear index n corresponds to (column-major) entry in xi.lam which is not contained in xi.mu. Otherwise return 0.\n\n\n\n\n\n","category":"method"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"The support for skew diagrams is very rudimentary. The following functions are available:","category":"page"},{"location":"ytabs/","page":"Partitions and Young tableaux","title":"Partitions and Young tableaux","text":"is_rimhook(::Generic.SkewDiagram)\nleglength\nmatrix_repr(::Generic.SkewDiagram)","category":"page"},{"location":"ytabs/#AbstractAlgebra.Generic.is_rimhook-Tuple{AbstractAlgebra.Generic.SkewDiagram}","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.is_rimhook","text":"is_rimhook(xi::SkewDiagram)\n\nCheck if xi represents a rim-hook diagram, i.e. its diagram is edge-connected and contains no 2times 2 squares.\n\n\n\n\n\n","category":"method"},{"location":"ytabs/#AbstractAlgebra.Generic.leglength","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.leglength","text":"leglength(xi::SkewDiagram[, check::Bool=true])\n\nCompute the leglength of a rim-hook xi, i.e. the number of rows with non-zero entries minus one. If check is false function will not check whether xi is actually a rim-hook.\n\n\n\n\n\n","category":"function"},{"location":"ytabs/#AbstractAlgebra.Generic.matrix_repr-Tuple{AbstractAlgebra.Generic.SkewDiagram}","page":"Partitions and Young tableaux","title":"AbstractAlgebra.Generic.matrix_repr","text":"matrix_repr(xi::SkewDiagram)\n\nReturn a sparse representation of the diagram xi, i.e. a sparse array A where A[i,j] == 1 if and only if (i,j) is in xi.lam but not in xi.mu.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"ncpolynomial/#Univariate-polynomials-over-a-noncommutative-ring","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"AbstractAlgebra.jl provides a module, implemented in src/NCPoly.jl for univariate polynomials over any noncommutative ring in the AbstractAlgebra type hierarchy.","category":"page"},{"location":"ncpolynomial/#Generic-type-for-univariate-polynomials-over-a-noncommutative-ring","page":"Univariate polynomials over a noncommutative ring","title":"Generic type for univariate polynomials over a noncommutative ring","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"AbstractAlgebra.jl implements a generic univariate polynomial type over noncommutative rings in src/generic/NCPoly.jl.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"These generic polynomials have type Generic.NCPoly{T} where T is the type of elements of the coefficient ring. Internally they consist of a Julia array of coefficients and some additional fields for length and a parent object, etc. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Parent objects of such polynomials have type Generic.NCPolyRing{T}.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"The string representation of the variable of the polynomial ring and the base/coefficient ring R is stored in the parent object.","category":"page"},{"location":"ncpolynomial/#Abstract-types","page":"Univariate polynomials over a noncommutative ring","title":"Abstract types","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"The polynomial element types belong to the abstract type NCPolyRingElem{T} and the polynomial ring types belong to the abstract type NCPolyRing{T}. This enables one to write generic functions that can accept any AbstractAlgebra polynomial type.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"note: Note\nNote that both the generic polynomial ring type Generic.NCPolyRing{T} and the abstract type it belongs to, NCPolyRing{T} are both called NCPolyRing. The former is a (parameterised) concrete type for a polynomial ring over a given base ring whose elements have type T. The latter is an abstract type representing all polynomial ring types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).","category":"page"},{"location":"ncpolynomial/#Polynomial-ring-constructors","page":"Univariate polynomials over a noncommutative ring","title":"Polynomial ring constructors","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"In order to construct polynomials in AbstractAlgebra.jl, one must first construct the polynomial ring itself. This is accomplished with the following constructor.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"polynomial_ring(R::NCRing, s::VarName; cached::Bool = true)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.polynomial_ring-Tuple{NCRing, Union{Char, AbstractString, Symbol}}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.polynomial_ring","text":"polynomial_ring(R::NCRing, s::VarName = :x; cached::Bool = true)\n\nGiven a base ring R and symbol/string s specifying how the generator (variable) should be printed, return a tuple S, x representing the new polynomial ring S = Rx and the generator x of the ring.\n\nBy default the parent object S depends only on R and x and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.\n\nExamples\n\njulia> R, x = polynomial_ring(ZZ, :x)\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, :y)\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"A shorthand version of this function is provided: given a base ring R, we abbreviate the constructor as follows.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"R[\"x\"]","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Here are some examples of creating polynomial rings and making use of the resulting parent objects to coerce various elements into the polynomial ring.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Examples","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"julia> R = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> S, x = polynomial_ring(R, \"x\")\n(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)\n\njulia> T, y = polynomial_ring(S, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)\n\njulia> U, z = R[\"z\"]\n(Univariate polynomial ring in z over matrix ring of degree 2 over integers, z)\n\njulia> f = S()\n0\n\njulia> g = S(123)\n[123 0; 0 123]\n\njulia> h = T(BigInt(1234))\n[1234 0; 0 1234]\n\njulia> k = T(x + 1)\nx + 1\n\njulia> m = U(z + 1)\nz + 1\n","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"All of the examples here are generic polynomial rings, but specialised implementations of polynomial rings provided by external modules will also usually provide a polynomial_ring constructor to allow creation of their polynomial rings.","category":"page"},{"location":"ncpolynomial/#Basic-ring-functionality","page":"Univariate polynomials over a noncommutative ring","title":"Basic ring functionality","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Once a polynomial ring is constructed, there are various ways to construct polynomials in that ring.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"The easiest way is simply using the generator returned by the polynomial_ring constructor and build up the polynomial using basic arithmetic, as described in the Ring interface. ","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"The Julia language also has special syntax for the construction of polynomials in terms of a generator, e.g. we can write 2x instead of 2*x.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"The polynomial rings in AbstractAlgebra.jl implement the full Ring interface. Of course the entire Univariate Polynomial Ring interface is also implemented.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"We give some examples of such functionality.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Examples","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"julia> R = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> S, x = polynomial_ring(R, \"x\")\n(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)\n\njulia> T, y = polynomial_ring(S, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)\n\njulia> f = x^3 + 3x + 21\nx^3 + [3 0; 0 3]*x + [21 0; 0 21]\n\njulia> g = (x + 1)*y^2 + 2x + 1\n(x + 1)*y^2 + [2 0; 0 2]*x + 1\n\njulia> h = zero(T)\n0\n\njulia> k = one(S)\n1\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> n = length(g)\n3\n\njulia> U = base_ring(T)\nUnivariate polynomial ring in x over matrix ring of degree 2 over integers\n\njulia> V = base_ring(y + 1)\nUnivariate polynomial ring in x over matrix ring of degree 2 over integers\n\njulia> v = var(T)\n:y\n\njulia> U = parent(y + 1)\nUnivariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers\n\njulia> g == deepcopy(g)\ntrue","category":"page"},{"location":"ncpolynomial/#Polynomial-functionality-provided-by-AbstractAlgebra.jl","page":"Univariate polynomials over a noncommutative ring","title":"Polynomial functionality provided by AbstractAlgebra.jl","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"The functionality listed below is automatically provided by AbstractAlgebra.jl for any polynomial module that implements the full Univariate Polynomial Ring interface over a noncommutative ring. This includes AbstractAlgebra.jl's own generic polynomial rings.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"But if a C library provides all the functionality documented in the Univariate Polynomial Ring interface over a noncommutative ring, then all the functions described here will also be automatically supplied by AbstractAlgebra.jl for that polynomial type.","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Of course, modules are free to provide specific implementations of the functions described here, that override the generic implementation.","category":"page"},{"location":"ncpolynomial/#Basic-functionality","page":"Univariate polynomials over a noncommutative ring","title":"Basic functionality","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"leading_coefficient(::NCPolyRingElem)\ntrailing_coefficient(::NCPolyRingElem)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.leading_coefficient-Tuple{NCPolyRingElem}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.leading_coefficient","text":"leading_coefficient(a::PolynomialElem)\n\nReturn the leading coefficient of the given polynomial. This will be the nonzero coefficient of the term with highest degree unless the polynomial in the zero polynomial, in which case a zero coefficient is returned.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/#AbstractAlgebra.trailing_coefficient-Tuple{NCPolyRingElem}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.trailing_coefficient","text":"trailing_coefficient(a::PolynomialElem)\n\nReturn the trailing coefficient of the given polynomial. This will be the nonzero coefficient of the term with lowest degree unless the polynomial is the zero polynomial, in which case a zero coefficient is returned.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"gen(::NCPolyRing)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.gen-Tuple{AbstractAlgebra.NCPolyRing}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.gen","text":"gen(R::NCPolyRing)\n\nReturn the generator of the given polynomial ring.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"is_gen(::NCPolyRingElem)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.is_gen-Tuple{NCPolyRingElem}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.is_gen","text":"is_gen(a::PolynomialElem)\n\nReturn true if the given polynomial is the constant generator of its polynomial ring, otherwise return false.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"is_monomial(::NCPolyRingElem)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.is_monomial-Tuple{NCPolyRingElem}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.is_monomial","text":"is_monomial(a::PolynomialElem)\n\nReturn true if the given polynomial is a monomial.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"is_term(::NCPolyRingElem)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.is_term-Tuple{NCPolyRingElem}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.is_term","text":"is_term(a::PolynomialElem)\n\nReturn true if the given polynomial has one term.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Examples","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"julia> R = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> S, x = polynomial_ring(R, \"x\")\n(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)\n\njulia> T, y = polynomial_ring(S, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)\n\njulia> a = zero(T)\n0\n\njulia> b = one(T)\n1\n\njulia> c = BigInt(1)*y^2 + BigInt(1)\ny^2 + 1\n\njulia> d = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + [3 0; 0 3]\n\njulia> f = leading_coefficient(d)\nx\n\njulia> y = gen(T)\ny\n\njulia> g = is_gen(y)\ntrue\n\njulia> m = is_unit(b)\ntrue\n\njulia> n = degree(d)\n2\n\njulia> is_term(2y^2)\ntrue\n\njulia> is_monomial(y^2)\ntrue\n","category":"page"},{"location":"ncpolynomial/#Truncation","page":"Univariate polynomials over a noncommutative ring","title":"Truncation","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"truncate(::NCPolyRingElem, ::Int)","category":"page"},{"location":"ncpolynomial/#Base.truncate-Tuple{NCPolyRingElem, Int64}","page":"Univariate polynomials over a noncommutative ring","title":"Base.truncate","text":"truncate(a::PolynomialElem, n::Int)\n\nReturn a truncated to n terms, i.e. the remainder upon division by x^n.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"mullow(::NCPolyRingElem{T}, ::NCPolyRingElem{T}, ::Int) where T <: NCRingElem","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.mullow-Union{Tuple{T}, Tuple{NCPolyRingElem{T}, NCPolyRingElem{T}, Int64}} where T<:NCRingElem","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.mullow","text":"mullow(a::NCPolyRingElem{T}, b::NCPolyRingElem{T}, n::Int) where T <: NCRingElem\n\nReturn atimes b truncated to n terms.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Examples","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"julia> R = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> S, x = polynomial_ring(R, \"x\")\n(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)\n\njulia> T, y = polynomial_ring(S, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + [3 0; 0 3]\n\njulia> g = (x + 1)*y + (x^3 + 2x + 2)\n(x + 1)*y + x^3 + [2 0; 0 2]*x + [2 0; 0 2]\n\njulia> h = truncate(f, 1)\n[3 0; 0 3]\n\njulia> k = mullow(f, g, 4)\n(x^2 + x)*y^3 + (x^4 + [3 0; 0 3]*x^2 + [4 0; 0 4]*x + 1)*y^2 + (x^4 + x^3 + [2 0; 0 2]*x^2 + [7 0; 0 7]*x + [5 0; 0 5])*y + [3 0; 0 3]*x^3 + [6 0; 0 6]*x + [6 0; 0 6]\n","category":"page"},{"location":"ncpolynomial/#Reversal","page":"Univariate polynomials over a noncommutative ring","title":"Reversal","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"reverse(::NCPolyRingElem, ::Int)\nreverse(::NCPolyRingElem)","category":"page"},{"location":"ncpolynomial/#Base.reverse-Tuple{NCPolyRingElem, Int64}","page":"Univariate polynomials over a noncommutative ring","title":"Base.reverse","text":"reverse(x::PolynomialElem, len::Int)\n\nReturn the reverse of the polynomial x, thought of as a polynomial of the given length (the polynomial will be notionally truncated or padded with zeroes before the leading term if necessary to match the specified length). The resulting polynomial is normalised. If len is negative we throw a DomainError().\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/#Base.reverse-Tuple{NCPolyRingElem}","page":"Univariate polynomials over a noncommutative ring","title":"Base.reverse","text":"reverse(x::PolynomialElem)\n\nReturn the reverse of the polynomial x, i.e. the leading coefficient of x becomes the constant coefficient of the result, etc. The resulting polynomial is normalised.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Examples","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"julia> R = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> S, x = polynomial_ring(R, \"x\")\n(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)\n\njulia> T, y = polynomial_ring(S, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + [3 0; 0 3]\n\njulia> g = reverse(f, 7)\n[3 0; 0 3]*y^6 + (x + 1)*y^5 + x*y^4\n\njulia> h = reverse(f)\n[3 0; 0 3]*y^2 + (x + 1)*y + x\n","category":"page"},{"location":"ncpolynomial/#Shifting","page":"Univariate polynomials over a noncommutative ring","title":"Shifting","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"shift_left(::NCPolyRingElem, ::Int)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.shift_left-Tuple{NCPolyRingElem, Int64}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.shift_left","text":"shift_left(f::PolynomialElem, n::Int)\n\nReturn the polynomial f shifted left by n terms, i.e. multiplied by x^n.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"shift_right(::NCPolyRingElem, ::Int)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.shift_right-Tuple{NCPolyRingElem, Int64}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.shift_right","text":"shift_right(f::PolynomialElem, n::Int)\n\nReturn the polynomial f shifted right by n terms, i.e. divided by x^n.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Examples","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"julia> R = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> S, x = polynomial_ring(R, \"x\")\n(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)\n\njulia> T, y = polynomial_ring(S, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + [3 0; 0 3]\n\njulia> g = shift_left(f, 7)\nx*y^9 + (x + 1)*y^8 + [3 0; 0 3]*y^7\n\njulia> h = shift_right(f, 2)\nx\n","category":"page"},{"location":"ncpolynomial/#Evaluation","page":"Univariate polynomials over a noncommutative ring","title":"Evaluation","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"evaluate{T <: NCRingElem}(::NCPolyRingElem{T}, ::T)\nevaluate(::NCPolyRingElem, ::Integer)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.evaluate-Union{Tuple{T}, Tuple{NCPolyRingElem{T}, T}} where T<:NCRingElem","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.evaluate","text":"evaluate(a::NCPolyRingElem, b::T) where T <: NCRingElem\n\nEvaluate the polynomial a at the value b and return the result.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/#AbstractAlgebra.evaluate-Tuple{NCPolyRingElem, Integer}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.evaluate","text":"evaluate(a::NCPolyRingElem, b::Union{Integer, Rational, AbstractFloat})\n\nEvaluate the polynomial a at the value b and return the result.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"We also overload the functional notation so that the polynomial f can be evaluated at a by writing f(a). ","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Examples","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"julia> R = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> S, x = polynomial_ring(R, \"x\")\n(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)\n\njulia> T, y = polynomial_ring(S, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)\n\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + [3 0; 0 3]\n\njulia> k = evaluate(f, 3)\n[12 0; 0 12]*x + [6 0; 0 6]\n\njulia> m = evaluate(f, x^2 + 2x + 1)\nx^5 + [4 0; 0 4]*x^4 + [7 0; 0 7]*x^3 + [7 0; 0 7]*x^2 + [4 0; 0 4]*x + [4 0; 0 4]\n\njulia> r = f(23)\n[552 0; 0 552]*x + [26 0; 0 26]\n","category":"page"},{"location":"ncpolynomial/#Derivative","page":"Univariate polynomials over a noncommutative ring","title":"Derivative","text":"","category":"section"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"derivative(::NCPolyRingElem)","category":"page"},{"location":"ncpolynomial/#AbstractAlgebra.derivative-Tuple{NCPolyRingElem}","page":"Univariate polynomials over a noncommutative ring","title":"AbstractAlgebra.derivative","text":"derivative(a::PolynomialElem)\n\nReturn the derivative of the polynomial a.\n\n\n\n\n\n","category":"method"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"Examples","category":"page"},{"location":"ncpolynomial/","page":"Univariate polynomials over a noncommutative ring","title":"Univariate polynomials over a noncommutative ring","text":"julia> R = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> S, x = polynomial_ring(R, \"x\")\n(Univariate polynomial ring in x over matrix ring of degree 2 over integers, x)\n\njulia> T, y = polynomial_ring(S, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring in x over matrix ring of degree 2 over integers, y)\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + [3 0; 0 3]\n\njulia> h = derivative(f)\n[2 0; 0 2]*x*y + x + 1\n","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"CurrentModule = AbstractAlgebra.Generic\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"free_associative_algebra/#Free-algebras","page":"Free algebras","title":"Free algebras","text":"","category":"section"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"AbstractAlgebra.jl provides a module, implemented in src/FreeAssAlgebra.jl for free associative algebras over any commutative ring belonging to the AbstractAlgebra abstract type hierarchy.","category":"page"},{"location":"free_associative_algebra/#Generic-free-algebra-types","page":"Free algebras","title":"Generic free algebra types","text":"","category":"section"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"AbstractAlgebra provides a generic type Generic.FreeAssAlgElem{T} where T is the type of elements of the coefficient ring. The elements are implemented using a Julia array of coefficients and a vector of vectors of Ints for the monomial words. Parent objects of such elements have type Generic.FreeAssAlgebra{T}.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"The element types belong to the abstract type NCRingElem, and the algebra types belong to the abstract type NCRing.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"The following basic functions are implemented.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"base_ring(R::FreeAssAlgebra)\nbase_ring(a::FreeAssAlgElem)\nparent(a::FreeAssAlgElem)\ncharacteristic(R::FreeAssAlgebra)","category":"page"},{"location":"free_associative_algebra/#Free-algebra-constructors","page":"Free algebras","title":"Free algebra constructors","text":"","category":"section"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"free_associative_algebra(R::Ring, s::AbstractVector{<:VarName}; cached::Bool = true)\nfree_associative_algebra(R::Ring, n::Int, s::VarName; cached::Bool = false)","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"The first constructor, given a base ring R and an array s of variables, will return a tuple S, (x, ...) representing the new algebra S = R leftx ldots right and a tuple of generators (x ).","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"The second constructor given a string s and a number of variables n will do the same as the first constructor except that the variables will be automatically numbered as, s1, s2, ..., sn.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"By default the parent object S will depend only on R and (x, ...) and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"Examples","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"julia> R, (x, y) = free_associative_algebra(ZZ, [\"x\", \"y\"])\n(Free associative algebra on 2 indeterminates over integers, AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}[x, y])\n\njulia> (x + y + 1)^2\nx^2 + x*y + y*x + y^2 + 2*x + 2*y + 1\n\n\njulia> (x*y*x*x)^4\nx*y*x^3*y*x^3*y*x^3*y*x^2","category":"page"},{"location":"free_associative_algebra/#Free-algebra-element-constructors","page":"Free algebras","title":"Free algebra element constructors","text":"","category":"section"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"Elements of a free algebra can be constructed from the generators in the usual way using arithmetic operations. Also, all of the standard ring element constructors may be used. Finally, the MPolyBuildCtx is overloaded to work with coefficients and monomial words and not exponent vectors.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"Examples","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"julia> R, (x, y, z) = free_associative_algebra(ZZ, [\"x\", \"y\", \"z\"])\n(Free associative algebra on 3 indeterminates over integers, AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}[x, y, z])\n\njulia> B = MPolyBuildCtx(R)\nBuilder for an element of Free associative algebra on 3 indeterminates over integers\n\njulia> push_term!(B, ZZ(1), [1,2,3,1]); push_term!(B, ZZ(2), [3,3,1]); finish(B)\nx*y*z*x + 2*z^2*x\n\njulia> push_term!(B, ZZ(3), [3,3,3]); push_term!(B, ZZ(4), Int[]); finish(B)\n3*z^3 + 4\n\njulia> [gen(R, 2), R(9)]\n2-element Vector{AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}}:\n y\n 9","category":"page"},{"location":"free_associative_algebra/#Element-functions","page":"Free algebras","title":"Element functions","text":"","category":"section"},{"location":"free_associative_algebra/#Basic-manipulation","page":"Free algebras","title":"Basic manipulation","text":"","category":"section"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"The standard ring functions are available. The following functions from the multivariate polynomial interface are provided.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"symbols(S::FreeAssAlgebra)\nnumber_of_variables(f::FreeAssAlgebra)\ngens(S::FreeAssAlgebra)\ngen(S::FreeAssAlgebra, i::Int)\nis_gen(x::FreeAssAlgElem)\ntotal_degree(a::FreeAssAlgElem)\nlength(f::FreeAssAlgElem)","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"As with multivariate polynomials, an implementation must provide access to the elements as a sum of individual terms in some order. The length function provides the number of such terms, and the following functions provide the first such term.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"leading_coefficient(a::FreeAssAlgElem)\nleading_monomial(a::FreeAssAlgElem)\nleading_term(a::FreeAssAlgElem)\nleading_exponent_word(a::FreeAssAlgElem)","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"For types that allow constant time access to coefficients, the following are also available, allowing access to the given coefficient, monomial or term. Terms are numbered from the most significant first.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"coeff(f::FreeAssAlgElem, n::Int)\nmonomial(f::FreeAssAlgElem, n::Int)\nterm(f::FreeAssAlgElem, n::Int)","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"In contrast with the interface for multivariable polynomials, the function exponent_vector is replaced by exponent_word","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"exponent_word(a::Generic.FreeAssAlgElem{T}, i::Int) where T <: RingElement","category":"page"},{"location":"free_associative_algebra/#AbstractAlgebra.Generic.exponent_word-Union{Tuple{T}, Tuple{AbstractAlgebra.Generic.FreeAssAlgElem{T}, Int64}} where T<:RingElement","page":"Free algebras","title":"AbstractAlgebra.Generic.exponent_word","text":"exponent_word(a::FreeAssAlgElem{T}, i::Int) where T <: RingElement\n\nReturn a vector of variable indices corresponding to the monomial of the i-th term of a. Term numbering begins at 1, and the variable indices are given in the order of the variables for the ring.\n\n\n\n\n\n","category":"method"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"Examples","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"julia> R, (x, y, z) = free_associative_algebra(ZZ, [\"x\", \"y\", \"z\"])\n(Free associative algebra on 3 indeterminates over integers, AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}[x, y, z])\n\njulia> map(total_degree, (R(0), R(1), -x^2*y^2*z^2*x + z*y))\n(-1, 0, 7)\n\njulia> leading_term(-x^2*y^2*z^2*x + z*y)\n-x^2*y^2*z^2*x\n\njulia> leading_monomial(-x^2*y^2*z^2*x + z*y)\nx^2*y^2*z^2*x\n\njulia> leading_coefficient(-x^2*y^2*z^2*x + z*y)\n-1\n\njulia> exponent_word(-x^2*y^2*z^2*x + z*y, 1)\n7-element Vector{Int64}:\n 1\n 1\n 2\n 2\n 3\n 3\n 1","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"evaluate(a::AbstractAlgebra.FreeAssAlgElem{T}, vals::Vector{U}) where {T <: RingElement, U <: NCRingElem}","category":"page"},{"location":"free_associative_algebra/#AbstractAlgebra.evaluate-Union{Tuple{U}, Tuple{T}, Tuple{FreeAssAlgElem{T}, Vector{U}}} where {T<:RingElement, U<:NCRingElem}","page":"Free algebras","title":"AbstractAlgebra.evaluate","text":"evaluate(a::FreeAssAlgElem{T}, vals::Vector{U}) where {T <: RingElement, U <: NCRingElem}\n\nEvaluate a by substituting in the array of values for each of the variables. The evaluation will succeed if multiplication is defined between elements of the coefficient ring of a and elements of vals.\n\nThe syntax a(vals...) is also supported.\n\nExamples\n\njulia> R, (x, y) = free_associative_algebra(ZZ, [\"x\", \"y\"]);\n\njulia> f = x*y - y*x\nx*y - y*x\n\njulia> S = matrix_ring(ZZ, 2);\n\njulia> m1 = S([1 2; 3 4])\n[1 2]\n[3 4]\n\njulia> m2 = S([0 1; 1 0])\n[0 1]\n[1 0]\n\njulia> evaluate(f, [m1, m2])\n[-1 -3]\n[ 3 1]\n\njulia> m1*m2 - m2*m1 == evaluate(f, [m1, m2])\ntrue\n\njulia> m1*m2 - m2*m1 == f(m1, m2)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"free_associative_algebra/#Iterators","page":"Free algebras","title":"Iterators","text":"","category":"section"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"The following iterators are provided for elements of a free associative algebra, with exponent_words providing the analogous functionality that exponent_vectors provides for multivariate polynomials.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"terms(p::FreeAssAlgElem)\ncoefficients(p::FreeAssAlgElem)\nmonomials(p::FreeAssAlgElem)","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"exponent_words(a::FreeAssAlgElem{T}) where T <: RingElement","category":"page"},{"location":"free_associative_algebra/#AbstractAlgebra.exponent_words-Union{Tuple{AbstractAlgebra.Generic.FreeAssAlgElem{T}}, Tuple{T}} where T<:RingElement","page":"Free algebras","title":"AbstractAlgebra.exponent_words","text":"exponent_words(a::FreeAssAlgElem{T}) where T <: RingElement\n\nReturn an iterator for the exponent words of the given polynomial. To retrieve an array of the exponent words, use collect(exponent_words(a)).\n\n\n\n\n\n","category":"method"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"Examples","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"julia> R, (a, b, c) = free_associative_algebra(ZZ, [\"a\", \"b\", \"c\"])\n(Free associative algebra on 3 indeterminates over integers, AbstractAlgebra.Generic.FreeAssAlgElem{BigInt}[a, b, c])\n\njulia> collect(terms(3*b*a*c - b + c + 2))\n4-element Vector{Any}:\n 3*b*a*c\n -b\n c\n 2\n\njulia> collect(coefficients(3*b*a*c - b + c + 2))\n4-element Vector{Any}:\n 3\n -1\n 1\n 2\n\njulia> collect(monomials(3*b*a*c - b + c + 2))\n4-element Vector{Any}:\n b*a*c\n b\n c\n 1\n\njulia> collect(exponent_words(3*b*a*c - b + c + 2))\n4-element Vector{Vector{Int64}}:\n [2, 1, 3]\n [2]\n [3]\n []","category":"page"},{"location":"free_associative_algebra/#Groebner-bases","page":"Free algebras","title":"Groebner bases","text":"","category":"section"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"The function groebner_basis provides the computation of a Groebner basis of an ideal, given a set of generators of that ideal. Since such a Groebner basis is not necessarily finite, one can additionally pass a reduction_bound to the function, to only compute a partial Groebner basis.","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"Examples","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"julia> R, (x, y, u, v, t, s) = free_associative_algebra(GF(2), [\"x\", \"y\", \"u\", \"v\", \"t\", \"s\"])\n(Free associative algebra on 6 indeterminates over finite field F_2, AbstractAlgebra.Generic.FreeAssAlgElem{AbstractAlgebra.GFElem{Int64}}[x, y, u, v, t, s])\n\njulia> g = Generic.groebner_basis([u*(x*y)^3 + u*(x*y)^2 + u + v, (y*x)^3*t + (y*x)^2*t + t + s])\n5-element Vector{AbstractAlgebra.Generic.FreeAssAlgElem{AbstractAlgebra.GFElem{Int64}}}:\n u*x*y*x*y*x*y + u*x*y*x*y + u + v\n y*x*y*x*y*x*t + y*x*y*x*t + t + s\n u*x*s + v*x*t\n u*x*y*x*s + v*x*y*x*t\n u*x*y*x*y*x*s + v*x*y*x*y*x*t","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"In order to check whether a given element of the algebra is in the ideal generated by a Groebner basis g, one can compute its normal form. ```jldoctest; setup = :(using AbstractAlgebra) julia> R, (x, y, u, v, t, s) = freeassociativealgebra(GF(2), [\"x\", \"y\", \"u\", \"v\", \"t\", \"s\"]);","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"julia> g = Generic.groebner_basis([u(xy)^3 + u(xy)^2 + u + v, (yx)^3t + (yx)^2t + t + s]);","category":"page"},{"location":"free_associative_algebra/","page":"Free algebras","title":"Free algebras","text":"julia> normal_form(u(xy)^3st + u(xy)^2st +ust + vst, g) 0 ```","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"rational/#Rational-field","page":"Rational field","title":"Rational field","text":"","category":"section"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"AbstractAlgebra.jl provides a module, implemented in src/julia/Rational.jl for making Julia Rational{BigInt}s conform to the AbstractAlgebra.jl Field interface.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"In addition to providing a parent object QQ for Julia Rational{BigInt}s, we implement any additional functionality required by AbstractAlgebra.jl.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"Because Rational{BigInt} cannot be directly included in the AbstractAlgebra.jl abstract type hierarchy, we achieve integration of Julia Rational{BigInt}s by introducing a type union, called FieldElement, which is a union of FieldElem and a number of Julia types, including Rational{BigInt}. Everywhere that FieldElem is notionally used in AbstractAlgebra.jl, we are in fact using FieldElement, with additional care being taken to avoid ambiguities.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"The details of how this is done are technical, and we refer the reader to the implementation for details. For most intents and purposes, one can think of the Julia Rational{BigInt} type as belonging to FieldElem.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"One other technicality is that Julia defines certain functions for Rational{BigInt}, such as sqrt and exp differently to what AbstractAlgebra.jl requires. To get around this, we redefine these functions internally to AbstractAlgebra.jl, without redefining them for users of AbstractAlgebra.jl. This allows the internals of AbstractAlgebra.jl to function correctly, without broadcasting pirate definitions of already defined Julia functions to the world.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"To access the internal definitions, one can use AbstractAlgebra.sqrt and AbstractAlgebra.exp, etc.","category":"page"},{"location":"rational/#Types-and-parent-objects","page":"Rational field","title":"Types and parent objects","text":"","category":"section"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"Rationals have type Rational{BigInt}, as in Julia itself. We simply supplement the functionality for this type as required for computer algebra.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"The parent objects of such integers has type Rationals{BigInt}.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"For convenience, we also make Rational{Int} a part of the AbstractAlgebra.jl type hierarchy and its parent object (accessible as qq) has type Rationals{Int}. But we caution that this type is not particularly useful as a model of the rationals and may not function as expected within AbstractAlgebra.jl.","category":"page"},{"location":"rational/#Rational-constructors","page":"Rational field","title":"Rational constructors","text":"","category":"section"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"In order to construct rationals in AbstractAlgebra.jl, one can first construct the rational field itself. This is accomplished using either of the following constructors.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"fraction_field(R::Integers{BigInt})","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"Rationals{BigInt}()","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"This gives the unique object of type Rationals{BigInt} representing the field of rationals in AbstractAlgebra.jl.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"In practice, one simply uses QQ which is assigned to be the return value of the above constructor. There is no need to call the constructor in practice.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"Here are some examples of creating the rational field and making use of the resulting parent object to coerce various elements into the field.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"Examples","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"julia> f = QQ()\n0//1\n\njulia> g = QQ(123)\n123//1\n\njulia> h = QQ(BigInt(1234))\n1234//1\n\njulia> k = QQ(BigInt(12), BigInt(7))\n12//7\n\njulia> QQ == fraction_field(ZZ)\ntrue\n","category":"page"},{"location":"rational/#Basic-field-functionality","page":"Rational field","title":"Basic field functionality","text":"","category":"section"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"The rational field in AbstractAlgebra.jl implements the full Field and Fraction Field interfaces.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"We give some examples of such functionality.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"Examples","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"julia> f = QQ(12, 7)\n12//7\n\njulia> h = zero(QQ)\n0//1\n\njulia> k = one(QQ)\n1//1\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> U = base_ring(QQ)\nIntegers\n\njulia> V = base_ring(f)\nIntegers\n\njulia> T = parent(f)\nRationals\n\njulia> f == deepcopy(f)\ntrue\n\njulia> g = f + 12\n96//7\n\njulia> r = ZZ(12)//ZZ(7)\n12//7\n\njulia> n = numerator(r)\n12\n","category":"page"},{"location":"rational/#Rational-functionality-provided-by-AbstractAlgebra.jl","page":"Rational field","title":"Rational functionality provided by AbstractAlgebra.jl","text":"","category":"section"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"The functionality below supplements that provided by Julia itself for its Rational{BigInt} type.","category":"page"},{"location":"rational/#Square-and-n-th-root","page":"Rational field","title":"Square and n-th root","text":"","category":"section"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"The functions sqrt, is_square, is_square_with_sqrt are all provided, as are root and is_power.","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"Examples","category":"page"},{"location":"rational/","page":"Rational field","title":"Rational field","text":"julia> d = AbstractAlgebra.sqrt(ZZ(36)//ZZ(25))\n6//5\n\njulia> is_square(ZZ(9)//ZZ(16))\ntrue\n\njulia> root(ZZ(27)//64, 3)\n3//4","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"matrix/#Matrix-functionality","page":"Matrix functionality","title":"Matrix functionality","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"AbstractAlgebra.jl provides a module, implemented in src/Matrix.jl for matrices over any ring belonging to the AbstractAlgebra abstract type hierarchy. This functionality will work for any matrix type which follows the Matrix interface.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Similarly, AbstractAlgebra.jl provides a module in src/MatRing.jl for matrix algebras over a ring.","category":"page"},{"location":"matrix/#Generic-matrix-types","page":"Matrix functionality","title":"Generic matrix types","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"AbstractAlgebra.jl allows the creation of dense matrices over any computable ring R. Generic matrices over a ring are implemented in src/generic/Matrix.jl.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Generic matrix rings of mtimes m matrices are implemented in src/generic/MatRing.jl.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Generic matrices in AbstractAlgebra.jl have type Generic.MatSpaceElem{T} for matrices in a matrix space, or Generic.MatRingElem{T} for matrices in a matrix algebra, where T is the type of elements of the matrix. Internally, generic matrices are implemented using an object wrapping a Julia two dimensional array, though they are not themselves Julia arrays. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"For the most part, one doesn't want to work directly with the MatSpaceElem type though, but with an abstract type called Generic.Mat which includes MatSpaceElem and views thereof.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Parents of generic matrices (matrix spaces) have type Generic.MatSpace{T}. Parents of matrices in a matrix algebra have type Generic.MatRing{T}.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"The dimensions and base ring R of a generic matrix are stored in its parent object, however to allow creation of matrices without first creating the matrix space parent, generic matrices in Julia do not contain a reference to their parent. They contain the row and column numbers (or degree, in the case of matrix algebras) and the base ring on a per matrix basis. The parent object can then be reconstructed from this data on demand.","category":"page"},{"location":"matrix/#Abstract-types","page":"Matrix functionality","title":"Abstract types","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"The generic matrix types (matrix spaces) belong to the abstract type MatElem{T} and the matrix space parent types belong to MatSpace{T}. Similarly the generic matrix algebra matrix types belong to the abstract type MatRingElem{T} and the parent types belong to MatRing{T} Note that both the concrete type of a matrix space parent object and the abstract class it belongs to have the name MatElem, therefore disambiguation is required to specify which is intended. The same is true for the abstract types for matrix spaces and their elements.","category":"page"},{"location":"matrix/#Matrix-space-constructors","page":"Matrix functionality","title":"Matrix space constructors","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"A matrix space in AbstractAlgebra.jl represents a collection of all matrices with given dimensions and base ring.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"In order to construct matrices in AbstractAlgebra.jl, one can first construct the matrix space itself. This is accomplished with the following constructor. We discuss creation of matrix algebras separately in a dedicated section elsewhere in the documentation.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"matrix_space(R::Ring, rows::Int, cols::Int)","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Construct the space of matrices with the given number of rows and columns over the given base ring.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Here are some examples of creating matrix spaces and making use of the resulting parent objects to coerce various elements into the matrix space.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in t over rationals\n\njulia> A = S()\n[0 0 0]\n[0 0 0]\n[0 0 0]\n\njulia> B = S(12)\n[12 0 0]\n[ 0 12 0]\n[ 0 0 12]\n\njulia> C = S(R(11))\n[11 0 0]\n[ 0 11 0]\n[ 0 0 11]\n","category":"page"},{"location":"matrix/#Matrix-element-constructors","page":"Matrix functionality","title":"Matrix element constructors","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"There are a few ways to construct matrices other than by coercing elements as shown above. The first method is from an array of elements.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"This can be done with either two or one dimensional arrays.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"(S::MatSpace{T})(A::Matrix{S}) where {S <: RingElement, T <: RingElement}\n(S::MatRing{T})(A::Matrix{S}) where {S <: RingElement, T <: RingElement}","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Create the matrix in the given space/algebra whose (i j) entry is given by A[i, j], where S is the type of elements that can be coerced into the base ring of the matrix.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"(S::MyMatSpace{T})(A::Vector{S}) where {S <: RingElem, T <: RingElem}\n(S::MyMatAlgebra{T})(A::Vector{S}) where {S <: RingElem, T <: RingElem}","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Create the matrix in the given space/algebra of matrices (with dimensions mtimes n say), whose (i j) entry is given by A[i*(n - 1) + j] and where S is the type of elements that can be coerced into the base ring of the matrix.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"We also provide the following syntax for constructing literal matrices (similar to how Julia arrays can be be constructed).","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"R[a b c...;...]","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Create the matrix over the base ring R consisting of the given rows (separated by semicolons). Each entry is coerced into R automatically. Note that parentheses may be placed around individual entries if the lists would otherwise be ambiguous, e.g. R[1 2; 2 (- 3)].","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Also see the Matrix interface for a list of other ways to create matrices.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> S = matrix_space(QQ, 2, 3)\nMatrix space of 2 rows and 3 columns\n over rationals\n\njulia> T = matrix_ring(QQ, 2)\nMatrix ring of degree 2\n over rationals\n\njulia> M1 = S(Rational{BigInt}[2 3 1; 1 0 4])\n[2//1 3//1 1//1]\n[1//1 0//1 4//1]\n\njulia> M2 = S(BigInt[2 3 1; 1 0 4])\n[2//1 3//1 1//1]\n[1//1 0//1 4//1]\n\njulia> M3 = S(BigInt[2, 3, 1, 1, 0, 4])\n[2//1 3//1 1//1]\n[1//1 0//1 4//1]\n\njulia> N1 = T(Rational{BigInt}[2 3; 1 0])\n[2//1 3//1]\n[1//1 0//1]\n\njulia> N2 = T(BigInt[2 3; 1 0])\n[2//1 3//1]\n[1//1 0//1]\n\njulia> N3 = T(BigInt[2, 3, 1, 1])\n[2//1 3//1]\n[1//1 1//1]\n\njulia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in t over rationals\n\njulia> M = R[t + 1 1; t^2 0]\n[t + 1 1]\n[ t^2 0]\n\njulia> N = R[t + 1 2 t] # create a row vector\n[t + 1 2 t]\n\njulia> P = R[1; 2; t] # create a column vector\n[1]\n[2]\n[t]","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"It is also possible to create matrices (in a matrix space only) directly, without first creating the corresponding matrix space (the inner constructor being called directly).","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"matrix(R::Ring, arr::Matrix{T}) where T <: RingElement","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Given an mtimes n Julia matrix of entries, construct the corresponding AbstractAlgebra.jl matrix over the given ring R, assuming all the entries can be coerced into R.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"matrix(R::Ring, r::Int, c::Int, A::Vector{T}) where T <: RingElement","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Construct the given rtimes c AbstractAlgebra.jl matrix over the ring R whose (i j) entry is given by A[c*(i - 1) + j], assuming that all the entries can be coerced into R.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"zero_matrix(R::Ring, r::Int, c::Int)","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Construct the rtimes c AbstractAlgebra.jl zero matrix over the ring R.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> M = matrix(ZZ, BigInt[3 1 2; 2 0 1])\n[3 1 2]\n[2 0 1]\n\njulia> N = matrix(ZZ, 3, 2, BigInt[3, 1, 2, 2, 0, 1])\n[3 1]\n[2 2]\n[0 1]\n\njulia> P = zero_matrix(ZZ, 3, 2)\n[0 0]\n[0 0]\n[0 0]\n\njulia> R = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> M = R()\n[0 0]\n[0 0]","category":"page"},{"location":"matrix/#Block-diagonal-matrix-constructors","page":"Matrix functionality","title":"Block diagonal matrix constructors","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"It is also possible to create block diagonal matrices from a vector of existing matrices. It is also possible to construct them from Julia matrices if one supplies the base ring.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Note that if the input matrices are not square, the output matrix may not be square.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"block_diagonal_matrix(::Vector{<:MatElem{T}}) where T <: RingElement\nblock_diagonal_matrix(::Ring, ::Vector{<:Matrix{T}}) where T <: RingElement","category":"page"},{"location":"matrix/#AbstractAlgebra.block_diagonal_matrix-Union{Tuple{Vector{<:MatElem{T}}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.block_diagonal_matrix","text":"block_diagonal_matrix(V::Vector{<:MatElem{T}}) where T <: NCRingElement\n\nCreate the block diagonal matrix whose blocks are given by the matrices in V. There must be at least one matrix in V.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.block_diagonal_matrix-Union{Tuple{T}, Tuple{Ring, Vector{<:Matrix{T}}}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.block_diagonal_matrix","text":"block_diagonal_matrix(R::NCRing, V::Vector{<:Matrix{T}}) where T <: NCRingElement\n\nCreate the block diagonal matrix over the ring R whose blocks are given by the matrices in V. Entries are coerced into R upon creation.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> block_diagonal_matrix(ZZ, [[1 2; 3 4], [4 5 6; 7 8 9]])\n[1 2 0 0 0]\n[3 4 0 0 0]\n[0 0 4 5 6]\n[0 0 7 8 9]\n\njulia> M = matrix(ZZ, [1 2; 3 4])\n[1 2]\n[3 4]\n\njulia> N = matrix(ZZ, [4 5 6; 7 8 9])\n[4 5 6]\n[7 8 9]\n\njulia> block_diagonal_matrix([M, N])\n[1 2 0 0 0]\n[3 4 0 0 0]\n[0 0 4 5 6]\n[0 0 7 8 9]","category":"page"},{"location":"matrix/#Conversion-to-Julia-matrices,-iteration-and-broacasting","page":"Matrix functionality","title":"Conversion to Julia matrices, iteration and broacasting","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"While AbstractAlgebra matrices are not instances of AbstractArray, they are closely related to Julia matrices. For convenience, a Matrix and an Array constructors taking an AbstractAlgebra matrix as input are provided:","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Matrix(::MatrixElem{T}) where T <: RingElement\nArray(::MatrixElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#Base.Matrix-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"Base.Matrix","text":"Matrix(A::MatrixElem{T}) where {T<:NCRingElement}\nMatrix{U}(A::MatrixElem{T}) where {U<:NCRingElement, T<:NCRingElement}\n\nConvert A to a Julia Matrix{U} of the same dimensions with the same elements. If U is omitted then eltype(M) is used in its place.\n\nExamples\n\njulia> A = ZZ[1 2 3; 4 5 6]\n[1 2 3]\n[4 5 6]\n\njulia> Matrix(A)\n2×3 Matrix{BigInt}:\n 1 2 3\n 4 5 6\n\njulia> Matrix{Int}(A)\n2×3 Matrix{Int64}:\n 1 2 3\n 4 5 6\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Core.Array-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"Core.Array","text":"Array(A::MatrixElem{T}) where T <: NCRingElement\n\nConvert A to a Julia Matrix of the same dimensions with the same elements.\n\nExamples\n\njulia> R, x = ZZ[\"x\"]; A = R[x^0 x^1; x^2 x^3]\n[ 1 x]\n[x^2 x^3]\n\njulia> Array(A)\n2×2 Matrix{AbstractAlgebra.Generic.Poly{BigInt}}:\n 1 x\n x^2 x^3\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Matrices also support iteration, and therefore functions accepting an iterator can be called on them, e.g.:","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> M = matrix_space(ZZ, 2, 3); x = M(1:6)\n[1 2 3]\n[4 5 6]\n\njulia> collect(x)\n2×3 Matrix{BigInt}:\n 1 2 3\n 4 5 6\n\njulia> Set(x)\nSet{BigInt} with 6 elements:\n 5\n 4\n 6\n 2\n 3\n 1","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Matrices also support broadcasting, which amounts to elementwise application of functions to matrices:","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> k = GF(5);\n\njulia> A = ZZ[1 2; 3 4];\n\njulia> k.(A)\n[1 2]\n[3 4]\n\njulia> 3 .* A .+ 2\n[ 5 8]\n[11 14]\n\njulia> B = ZZ[3 4; 5 6];\n\njulia> ((x, y) -> x^2 + y^2).(A, B)\n[10 20]\n[34 52]","category":"page"},{"location":"matrix/#Views","page":"Matrix functionality","title":"Views","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"As per Julia, AbstractAlgebra supports the construction of matrix views. These allow one to work with a submatrix of a given matrix. Modifying the submatrix also modifies the original matrix.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"The syntax for views is as for Julia's own views.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> M = matrix(ZZ, 3, 3, BigInt[1, 2, 3, 2, 3, 4, 3, 4, 5])\n[1 2 3]\n[2 3 4]\n[3 4 5]\n\njulia> N1 = @view M[1:2, :]\n[1 2 3]\n[2 3 4]\n\njulia> N2 = @view M[:, 1:2]\n[1 2]\n[2 3]\n[3 4]\n\njulia> R = N1*N2\n[14 20]\n[20 29]","category":"page"},{"location":"matrix/#Matrix-functionality-provided-by-AbstractAlgebra.jl","page":"Matrix functionality","title":"Matrix functionality provided by AbstractAlgebra.jl","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Most of the following generic functionality is available for both matrix spaces and matrix algebras. Exceptions include functions that do not return or accept square matrices or which cannot specify a parent. Such functions include solve, kernel, and nullspace which can't be provided for matrix algebras.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"For details on functionality that is provided for matrix algebras only, see the dedicated section of the documentation.","category":"page"},{"location":"matrix/#Basic-matrix-functionality","page":"Matrix functionality","title":"Basic matrix functionality","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"As well as the Ring and Matrix interfaces, the following functions are provided to manipulate matrices and to set and retrieve entries and other basic data associated with the matrices.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"dense_matrix_type(::Ring)","category":"page"},{"location":"matrix/#AbstractAlgebra.Generic.dense_matrix_type-Tuple{Ring}","page":"Matrix functionality","title":"AbstractAlgebra.Generic.dense_matrix_type","text":"dense_matrix_type(::Type{T}) where T<:NCRingElement\ndense_matrix_type(::T) where T<:NCRingElement\ndense_matrix_type(::Type{S}) where S<:NCRing\ndense_matrix_type(::S) where S<:NCRing\n\nReturn the type of matrices with coefficients of type T respectively elem_type(S).\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"number_of_rows(::MatSpace)\nnumber_of_columns(::MatSpace)","category":"page"},{"location":"matrix/#AbstractAlgebra.number_of_rows-Tuple{MatSpace}","page":"Matrix functionality","title":"AbstractAlgebra.number_of_rows","text":"number_of_rows(a::MatSpace)\n\nReturn the number of rows of the given matrix space.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.number_of_columns-Tuple{MatSpace}","page":"Matrix functionality","title":"AbstractAlgebra.number_of_columns","text":"number_of_columns(a::MatSpace)\n\nReturn the number of columns of the given matrix space.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"number_of_rows(::MatrixElem{T}) where T <: RingElement\nnumber_of_columns(::MatrixElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#AbstractAlgebra.number_of_rows-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.number_of_rows","text":"number_of_rows(a::MatrixElem{T}) where T <: NCRingElement\n\nReturn the number of rows of the given matrix.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.number_of_columns-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.number_of_columns","text":"number_of_columns(a::MatrixElem{T}) where T <: NCRingElement\n\nReturn the number of columns of the given matrix.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"length(::MatrixElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#Base.length-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"Base.length","text":"length(a::MatrixElem{T}) where T <: NCRingElement\n\nReturn the number of entries in the given matrix.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"isempty(::MatrixElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#Base.isempty-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"Base.isempty","text":"isempty(a::MatrixElem{T}) where T <: NCRingElement\n\nReturn true if a does not contain any entry (i.e. length(a) == 0), and false otherwise.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"identity_matrix(::Ring, ::Int)","category":"page"},{"location":"matrix/#AbstractAlgebra.identity_matrix-Tuple{Ring, Int64}","page":"Matrix functionality","title":"AbstractAlgebra.identity_matrix","text":"identity_matrix(R::NCRing, n::Int)\n\nReturn the n times n identity matrix over R.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"identity_matrix(::MatElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#AbstractAlgebra.identity_matrix-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.identity_matrix","text":"identity_matrix(M::MatElem{T}) where T <: NCRingElement\n\nConstruct the identity matrix in the same matrix space as M, i.e. with ones down the diagonal and zeroes elsewhere. M must be square. This is an alias for one(M).\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"scalar_matrix(R::Ring, n::Int, a::RingElement)","category":"page"},{"location":"matrix/#AbstractAlgebra.scalar_matrix-Tuple{Ring, Int64, RingElement}","page":"Matrix functionality","title":"AbstractAlgebra.scalar_matrix","text":"scalar_matrix(R::NCRing, n::Int, a::NCRingElement)\nscalar_matrix(n::Int, a::NCRingElement)\n\nReturn the n times n matrix over R with a along the main diagonal and zeroes elsewhere. If R is not specified, it defaults to parent(a).\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"diagonal_matrix(::RingElement, ::Int, ::Int)","category":"page"},{"location":"matrix/#AbstractAlgebra.diagonal_matrix-Tuple{RingElement, Int64, Int64}","page":"Matrix functionality","title":"AbstractAlgebra.diagonal_matrix","text":"diagonal_matrix(x::NCRingElement, m::Int, [n::Int])\n\nReturn the m times n matrix over R with x along the main diagonal and zeroes elsewhere. If n is not specified, it defaults to m.\n\nExamples\n\njulia> diagonal_matrix(ZZ(2), 2, 3)\n[2 0 0]\n[0 2 0]\n\njulia> diagonal_matrix(QQ(-1), 3)\n[-1//1 0//1 0//1]\n[ 0//1 -1//1 0//1]\n[ 0//1 0//1 -1//1]\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"zero(::MatSpace)\nzero(::MatrixElem{T}, ::Ring) where T <: RingElement","category":"page"},{"location":"matrix/#Base.zero-Tuple{MatSpace}","page":"Matrix functionality","title":"Base.zero","text":"zero(a::MatSpace)\n\nReturn the zero matrix in the given matrix space.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Base.zero-Union{Tuple{T}, Tuple{MatrixElem{T}, Ring}} where T<:RingElement","page":"Matrix functionality","title":"Base.zero","text":"zero(x::MatrixElem{T}, R::NCRing, r::Int, c::Int) where T <: NCRingElement\nzero(x::MatrixElem{T}, R::NCRing=base_ring(x)) where T <: NCRingElement\nzero(x::MatrixElem{T}, r::Int, c::Int) where T <: NCRingElement\n\nReturn a zero matrix similar to the given matrix, with optionally different base ring or dimensions.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"one(::MatSpace)\none(::MatElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#Base.one-Tuple{MatSpace}","page":"Matrix functionality","title":"Base.one","text":"one(a::MatSpace)\n\nReturn the identity matrix of given matrix space. The matrix space must contain square matrices or else an error is thrown.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Base.one-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"Base.one","text":"one(a::MatrixElem{T}) where T <: NCRingElement\n\nReturn the identity matrix in the same matrix space as a. If the space does not contain square matrices, an error is thrown.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"lower_triangular_matrix(L::AbstractVector{T}) where {T <: RingElement}","category":"page"},{"location":"matrix/#AbstractAlgebra.lower_triangular_matrix-Union{Tuple{AbstractVector{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.lower_triangular_matrix","text":"lower_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}\n\nReturn the n by n matrix whose entries on and below the main diagonal are the elements of L, and which has zeroes elsewhere. The value of n is determined by the condition that L has length n(n+1)2.\n\nAn exception is thrown if there is no integer n with this property.\n\nExamples\n\njulia> lower_triangular_matrix([1, 2, 3])\n[1 0]\n[2 3]\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"upper_triangular_matrix(L::AbstractVector{T}) where {T <: RingElement}","category":"page"},{"location":"matrix/#AbstractAlgebra.upper_triangular_matrix-Union{Tuple{AbstractVector{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.upper_triangular_matrix","text":"upper_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}\n\nReturn the n by n matrix whose entries on and above the main diagonal are the elements of L, and which has zeroes elsewhere. The value of n is determined by the condition that L has length n(n+1)2.\n\nAn exception is thrown if there is no integer n with this property.\n\nExamples\n\njulia> upper_triangular_matrix([1, 2, 3])\n[1 2]\n[0 3]\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"strictly_lower_triangular_matrix(L::AbstractVector{T}) where {T <: RingElement}","category":"page"},{"location":"matrix/#AbstractAlgebra.strictly_lower_triangular_matrix-Union{Tuple{AbstractVector{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.strictly_lower_triangular_matrix","text":"strictly_lower_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}\n\nReturn the n by n matrix whose entries below the main diagonal are the elements of L, and which has zeroes elsewhere. The value of n is determined by the condition that L has length (n-1)n2.\n\nAn exception is thrown if there is no integer n with this property.\n\nExamples\n\njulia> strictly_lower_triangular_matrix([1, 2, 3])\n[0 0 0]\n[1 0 0]\n[2 3 0]\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"strictly_upper_triangular_matrix(L::AbstractVector{T}) where {T <: RingElement}","category":"page"},{"location":"matrix/#AbstractAlgebra.strictly_upper_triangular_matrix-Union{Tuple{AbstractVector{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.strictly_upper_triangular_matrix","text":"strictly_upper_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}\n\nReturn the n by n matrix whose entries above the main diagonal are the elements of L, and which has zeroes elsewhere. The value of n is determined by the condition that L has length (n-1)n2.\n\nAn exception is thrown if there is no integer n with this property.\n\nExamples\n\njulia> strictly_upper_triangular_matrix([1, 2, 3])\n[0 1 2]\n[0 0 3]\n[0 0 0]\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_lower_triangular(::MatrixElem)","category":"page"},{"location":"matrix/#AbstractAlgebra.is_lower_triangular-Tuple{MatrixElem}","page":"Matrix functionality","title":"AbstractAlgebra.is_lower_triangular","text":"is_lower_triangular(A::MatrixElem)\n\nReturn true if A is an lower triangular matrix, that is, all entries above the main diagonal are zero. Note that this definition also applies to non-square matrices.\n\nAlias for LinearAlgebra.istril.\n\nExamples\n\njulia> is_lower_triangular(QQ[1 2 ; 0 4])\nfalse\n\njulia> is_lower_triangular(QQ[1 0 ; 3 4])\ntrue\n\njulia> is_lower_triangular(QQ[1 2 ;])\nfalse\n\njulia> is_lower_triangular(QQ[1 ; 2])\ntrue\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_upper_triangular(::MatrixElem)","category":"page"},{"location":"matrix/#AbstractAlgebra.is_upper_triangular-Tuple{MatrixElem}","page":"Matrix functionality","title":"AbstractAlgebra.is_upper_triangular","text":"is_upper_triangular(A::MatrixElem)\n\nReturn true if A is an upper triangular matrix, that is, all entries below the main diagonal are zero. Note that this definition also applies to non-square matrices.\n\nAlias for LinearAlgebra.istriu.\n\nExamples\n\njulia> is_upper_triangular(QQ[1 2 ; 0 4])\ntrue\n\njulia> is_upper_triangular(QQ[1 0 ; 3 4])\nfalse\n\njulia> is_upper_triangular(QQ[1 2 ;])\ntrue\n\njulia> is_upper_triangular(QQ[1 ; 2])\nfalse\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_diagonal(::MatrixElem)","category":"page"},{"location":"matrix/#AbstractAlgebra.is_diagonal-Tuple{MatrixElem}","page":"Matrix functionality","title":"AbstractAlgebra.is_diagonal","text":"is_diagonal(A::MatrixElem)\n\nReturn true if A is a diagonal matrix, that is, all entries off the main diagonal are zero. Note that this definition also applies to non-square matrices.\n\nAlias for LinearAlgebra.isdiag.\n\nExamples\n\njulia> is_diagonal(QQ[1 0 ; 0 4])\ntrue\n\njulia> is_diagonal(QQ[1 2 ; 3 4])\nfalse\n\njulia> is_diagonal(QQ[1 0 ;])\ntrue\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"change_base_ring(::Ring, ::MatElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#AbstractAlgebra.change_base_ring-Union{Tuple{T}, Tuple{Ring, MatElem{T}}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.change_base_ring","text":"change_base_ring(R::NCRing, M::MatrixElem{T}) where T <: NCRingElement\n\nReturn the matrix obtained by coercing each entry into R.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Base.map(f, ::MatrixElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#Base.map-Union{Tuple{T}, Tuple{Any, MatrixElem{T}}} where T<:RingElement","page":"Matrix functionality","title":"Base.map","text":"map(f, a::MatrixElem{T}) where T <: NCRingElement\n\nTransform matrix a by applying f on each element. This is equivalent to map_entries(f, a).\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Base.map!(f, ::MatrixElem{S}, ::MatrixElem{T}) where {S <: RingElement, T <: RingElement}","category":"page"},{"location":"matrix/#Base.map!-Union{Tuple{T}, Tuple{S}, Tuple{Any, MatrixElem{S}, MatrixElem{T}}} where {S<:RingElement, T<:RingElement}","page":"Matrix functionality","title":"Base.map!","text":"map!(f, dst::MatrixElem{T}, src::MatrixElem{U}) where {T <: NCRingElement, U <: NCRingElement}\n\nLike map, but stores the result in dst rather than a new matrix. This is equivalent to map_entries!(f, dst, src).\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in t over rationals\n\njulia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])\n[t + 1 t 1]\n[ t^2 t t]\n[ -2 t + 2 t^2 + t + 1]\n\njulia> B = S([R(2) R(3) R(1); t t + 1 t + 2; R(-1) t^2 t^3])\n[ 2 3 1]\n[ t t + 1 t + 2]\n[-1 t^2 t^3]\n\njulia> T = dense_matrix_type(R)\nAbstractAlgebra.Generic.MatSpaceElem{AbstractAlgebra.Generic.Poly{Rational{BigInt}}}\n\njulia> r = number_of_rows(B)\n3\n\njulia> c = number_of_columns(B)\n3\n\njulia> length(B)\n9\n\njulia> isempty(B)\nfalse\n\njulia> M = A + B\n[ t + 3 t + 3 2]\n[t^2 + t 2*t + 1 2*t + 2]\n[ -3 t^2 + t + 2 t^3 + t^2 + t + 1]\n\njulia> N = 2 + A\n[t + 3 t 1]\n[ t^2 t + 2 t]\n[ -2 t + 2 t^2 + t + 3]\n\njulia> M1 = deepcopy(A)\n[t + 1 t 1]\n[ t^2 t t]\n[ -2 t + 2 t^2 + t + 1]\n\njulia> A != B\ntrue\n\njulia> isone(one(S))\ntrue\n\njulia> V = A[1:2, :]\n[t + 1 t 1]\n[ t^2 t t]\n\njulia> W = A^3\n[ 3*t^4 + 4*t^3 + t^2 - 3*t - 5 t^4 + 5*t^3 + 10*t^2 + 7*t + 4 2*t^4 + 7*t^3 + 9*t^2 + 8*t + 1]\n[t^5 + 4*t^4 + 3*t^3 - 7*t^2 - 4*t 4*t^4 + 8*t^3 + 7*t^2 + 2*t t^5 + 5*t^4 + 9*t^3 + 7*t^2 - t]\n[ t^5 + 3*t^4 - 10*t^2 - 16*t - 2 t^5 + 6*t^4 + 12*t^3 + 11*t^2 + 5*t - 2 t^6 + 3*t^5 + 8*t^4 + 15*t^3 + 10*t^2 + t - 5]\n\njulia> Z = divexact(2*A, 2)\n[t + 1 t 1]\n[ t^2 t t]\n[ -2 t + 2 t^2 + t + 1]\n\njulia> M = matrix(ZZ, BigInt[2 3 0; 1 1 1])\n[2 3 0]\n[1 1 1]\n\njulia> M[1, 2] = BigInt(4)\n4\n\njulia> c = M[1, 1]\n2\n","category":"page"},{"location":"matrix/#Transpose","page":"Matrix functionality","title":"Transpose","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"transpose(::MatrixElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#Base.transpose-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"Base.transpose","text":"transpose(x::MatrixElem{T}) where T <: NCRingElement\n\nReturn the transpose of the given matrix.\n\nExamples\n\njulia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in t over rationals\n\njulia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])\n[t + 1 t 1]\n[ t^2 t t]\n[ -2 t + 2 t^2 + t + 1]\n\njulia> B = transpose(A)\n[t + 1 t^2 -2]\n[ t t t + 2]\n[ 1 t t^2 + t + 1]\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Submatrices","page":"Matrix functionality","title":"Submatrices","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Submatrices are only available for matrix spaces, not for matrix algebras and generally only available for generic matrices built on Julia arrays.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Submatrices return a new matrix with the same entries as the submatrix with the given range of rows and columns. They are best illustrated with examples.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> M = matrix(ZZ, BigInt[1 2 3; 2 3 4; 3 4 5])\n[1 2 3]\n[2 3 4]\n[3 4 5]\n\njulia> N1 = M[1:2, :]\n[1 2 3]\n[2 3 4]\n\njulia> N2 = M[:, :]\n[1 2 3]\n[2 3 4]\n[3 4 5]\n\njulia> N3 = M[2:3, 2:3]\n[3 4]\n[4 5]\n","category":"page"},{"location":"matrix/#Elementary-row-and-column-operations","page":"Matrix functionality","title":"Elementary row and column operations","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"add_column(::MatElem{T}, ::Int, ::Int, ::Int) where T <: RingElement\nadd_column!(::MatElem{T}, ::Int, ::Int, ::Int) where T <: RingElement\nadd_row(::MatElem{T}, ::Int, ::Int, ::Int) where T <: RingElement\nadd_row!(::MatElem{T}, ::Int, ::Int, ::Int) where T <: RingElement\nmultiply_column(::MatElem{T}, ::Int, ::Int) where T <: RingElement\nmultiply_column!(::MatElem{T}, ::Int, ::Int) where T <: RingElement\nmultiply_row(::MatElem{T}, ::Int, ::Int) where T <: RingElement\nmultiply_row!(::MatElem{T}, ::Int, ::Int) where T <: RingElement\n","category":"page"},{"location":"matrix/#AbstractAlgebra.add_column-Union{Tuple{T}, Tuple{MatElem{T}, Int64, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.add_column","text":"add_column(a::MatrixElem{T}, s::RingElement, i::Int, j::Int, rows = 1:nrows(a)) where T <: RingElement\n\nCreate a copy of a and add s times the i-th row to the j-th row of a.\n\nBy default, the transformation is applied to all rows of a. This can be changed using the optional rows argument.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.add_column!-Union{Tuple{T}, Tuple{MatElem{T}, Int64, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.add_column!","text":"add_column!(a::MatrixElem{T}, s::RingElement, i::Int, j::Int, rows = 1:nrows(a)) where T <: RingElement\n\nAdd s times the i-th row to the j-th row of a.\n\nBy default, the transformation is applied to all rows of a. This can be changed using the optional rows argument.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.add_row-Union{Tuple{T}, Tuple{MatElem{T}, Int64, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.add_row","text":"add_row(a::MatrixElem{T}, s::RingElement, i::Int, j::Int, cols = 1:ncols(a)) where T <: RingElement\n\nCreate a copy of a and add s times the i-th row to the j-th row of a.\n\nBy default, the transformation is applied to all columns of a. This can be changed using the optional cols argument.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.add_row!-Union{Tuple{T}, Tuple{MatElem{T}, Int64, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.add_row!","text":"add_row!(a::MatrixElem{T}, s::RingElement, i::Int, j::Int, cols = 1:ncols(a)) where T <: RingElement\n\nAdd s times the i-th row to the j-th row of a.\n\nBy default, the transformation is applied to all columns of a. This can be changed using the optional cols argument.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.multiply_column-Union{Tuple{T}, Tuple{MatElem{T}, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.multiply_column","text":"multiply_column(a::MatrixElem{T}, s::RingElement, i::Int, rows = 1:nrows(a)) where T <: RingElement\n\nCreate a copy of a and multiply the ith column of a with s.\n\nBy default, the transformation is applied to all rows of a. This can be changed using the optional rows argument.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.multiply_column!-Union{Tuple{T}, Tuple{MatElem{T}, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.multiply_column!","text":"multiply_column!(a::MatrixElem{T}, s::RingElement, i::Int, rows = 1:nrows(a)) where T <: RingElement\n\nMultiply the ith column of a with s.\n\nBy default, the transformation is applied to all rows of a. This can be changed using the optional rows argument.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.multiply_row-Union{Tuple{T}, Tuple{MatElem{T}, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.multiply_row","text":"multiply_row(a::MatrixElem{T}, s::RingElement, i::Int, cols = 1:ncols(a)) where T <: RingElement\n\nCreate a copy of a and multiply the ith row of a with s.\n\nBy default, the transformation is applied to all columns of a. This can be changed using the optional cols argument.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.multiply_row!-Union{Tuple{T}, Tuple{MatElem{T}, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.multiply_row!","text":"multiply_row!(a::MatrixElem{T}, s::RingElement, i::Int, cols = 1:ncols(a)) where T <: RingElement\n\nMultiply the ith row of a with s.\n\nBy default, the transformation is applied to all columns of a. This can be changed using the optional cols argument.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> M = ZZ[1 2 3; 2 3 4; 4 5 5]\n[1 2 3]\n[2 3 4]\n[4 5 5]\n\njulia> add_column(M, 2, 3, 1)\n[ 7 2 3]\n[10 3 4]\n[14 5 5]\n\njulia> add_row(M, 1, 2, 3)\n[1 2 3]\n[2 3 4]\n[6 8 9]\n\njulia> multiply_column(M, 2, 3)\n[1 2 6]\n[2 3 8]\n[4 5 10]\n\njulia> multiply_row(M, 2, 3)\n[1 2 3]\n[2 3 4]\n[8 10 10]","category":"page"},{"location":"matrix/#Swapping-rows-and-columns","page":"Matrix functionality","title":"Swapping rows and columns","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"swap_rows(a::MatrixElem{T}, i::Int, j::Int) where T <: RingElement\nswap_rows!(a::MatrixElem{T}, i::Int, j::Int) where T <: RingElement\nswap_cols(a::MatrixElem{T}, i::Int, j::Int) where T <: RingElement\nswap_cols!(a::MatrixElem{T}, i::Int, j::Int) where T <: RingElement","category":"page"},{"location":"matrix/#AbstractAlgebra.swap_rows-Union{Tuple{T}, Tuple{MatrixElem{T}, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.swap_rows","text":"swap_rows(a::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement\n\nReturn a matrix b with the entries of a, where the ith and jth row are swapped.\n\nExamples\n\njulia> M = identity_matrix(ZZ, 3)\n[1 0 0]\n[0 1 0]\n[0 0 1]\n\njulia> swap_rows(M, 1, 2)\n[0 1 0]\n[1 0 0]\n[0 0 1]\n\njulia> M # was not modified\n[1 0 0]\n[0 1 0]\n[0 0 1]\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.swap_rows!-Union{Tuple{T}, Tuple{MatrixElem{T}, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.swap_rows!","text":"swap_rows!(a::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement\n\nSwap the ith and jth row of a in place. The function returns the mutated matrix (since matrices are assumed to be mutable in AbstractAlgebra.jl).\n\nExamples\n\njulia> M = identity_matrix(ZZ, 3)\n[1 0 0]\n[0 1 0]\n[0 0 1]\n\njulia> swap_rows!(M, 1, 2)\n[0 1 0]\n[1 0 0]\n[0 0 1]\n\njulia> M # was modified\n[0 1 0]\n[1 0 0]\n[0 0 1]\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.swap_cols-Union{Tuple{T}, Tuple{MatrixElem{T}, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.swap_cols","text":"swap_cols(a::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement\n\nReturn a matrix b with the entries of a, where the ith and jth row are swapped.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.swap_cols!-Union{Tuple{T}, Tuple{MatrixElem{T}, Int64, Int64}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.swap_cols!","text":"swap_cols!(a::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement\n\nSwap the ith and jth column of a in place. The function returns the mutated matrix (since matrices are assumed to be mutable in AbstractAlgebra.jl).\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Swap the rows of M in place. The function returns the mutated matrix (since matrices are assumed to be mutable in AbstractAlgebra.jl).","category":"page"},{"location":"matrix/#Concatenation","page":"Matrix functionality","title":"Concatenation","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"The following are only available for matrix spaces, not for matrix algebras.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"hcat(M::T, N::T) where T <: MatElem","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Return the horizontal concatenation of M and N. It is assumed that the number of rows of M and N are the same.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"vcat(M::T, N::T) where T <: MatElem","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Return the vertical concatenation of M and N. It is assumed that the number of columns of M and N are the same.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> M = matrix(ZZ, BigInt[1 2 3; 2 3 4; 3 4 5])\n[1 2 3]\n[2 3 4]\n[3 4 5]\n\njulia> N = matrix(ZZ, BigInt[1 0 1; 0 1 0; 1 0 1])\n[1 0 1]\n[0 1 0]\n[1 0 1]\n\njulia> P = hcat(M, N)\n[1 2 3 1 0 1]\n[2 3 4 0 1 0]\n[3 4 5 1 0 1]\n\njulia> Q = vcat(M, N)\n[1 2 3]\n[2 3 4]\n[3 4 5]\n[1 0 1]\n[0 1 0]\n[1 0 1]\n","category":"page"},{"location":"matrix/#Similar-and-zero","page":"Matrix functionality","title":"Similar and zero","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Both similar and zero construct new matrices, but the entries are either undefined with similar or zero-initialized with zero.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"similar(x::MatElem, R::Ring=base_ring(x))\nzero(x::MatElem, R::Ring=base_ring(x))","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Construct the matrix with the same dimensions as the given matrix, and the same base ring unless explicitly specified.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"similar(x::MatElem, R::Ring, r::Int, c::Int)\nsimilar(x::MatElem, r::Int, c::Int)\nzero(x::MatElem, R::Ring, r::Int, c::Int)\nzero(x::MatElem, r::Int, c::Int)","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Construct the rtimes c matrix with R as base ring (which defaults to the base ring of the the given matrix). If x belongs to a matrix algebra and r neq c, an exception is raised, and it's also possible to specify only one Int as the order (e.g. similar(x, n)).","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Base.isassigned(M::MatElem, i, j)","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Test whether the given matrix has a value associated with indices i and j.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> M = matrix(ZZ, BigInt[3 1 2; 2 0 1])\n[3 1 2]\n[2 0 1]\n\njulia> isassigned(M, 1, 2)\ntrue\n\njulia> isassigned(M, 4, 4)\nfalse\n\njulia> A = similar(M)\n[#undef #undef #undef]\n[#undef #undef #undef]\n\njulia> isassigned(A, 1, 2)\nfalse\n\njulia> B = zero(M)\n[0 0 0]\n[0 0 0]\n\njulia> C = similar(M, 4, 5)\n[#undef #undef #undef #undef #undef]\n[#undef #undef #undef #undef #undef]\n[#undef #undef #undef #undef #undef]\n[#undef #undef #undef #undef #undef]\n\njulia> base_ring(B)\nIntegers\n\njulia> D = zero(M, QQ, 2, 2)\n[0//1 0//1]\n[0//1 0//1]\n\njulia> base_ring(D)\nRationals","category":"page"},{"location":"matrix/#Symmetry-testing","page":"Matrix functionality","title":"Symmetry testing","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_symmetric(::MatrixElem)","category":"page"},{"location":"matrix/#AbstractAlgebra.is_symmetric-Tuple{MatrixElem}","page":"Matrix functionality","title":"AbstractAlgebra.is_symmetric","text":"is_symmetric(M::MatrixElem)\n\nReturn true if the given matrix is symmetric with respect to its main diagonal, i.e., transpose(M) == M, otherwise return false.\n\nAlias for LinearAlgebra.issymmetric.\n\nExamples\n\njulia> M = matrix(ZZ, [1 2 3; 2 4 5; 3 5 6])\n[1 2 3]\n[2 4 5]\n[3 5 6]\n\njulia> is_symmetric(M)\ntrue\n\njulia> N = matrix(ZZ, [1 2 3; 4 5 6; 7 8 9])\n[1 2 3]\n[4 5 6]\n[7 8 9]\n\njulia> is_symmetric(N)\nfalse\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_skew_symmetric(::MatrixElem)","category":"page"},{"location":"matrix/#AbstractAlgebra.is_skew_symmetric-Tuple{MatrixElem}","page":"Matrix functionality","title":"AbstractAlgebra.is_skew_symmetric","text":"is_skew_symmetric(M::MatrixElem)\n\nReturn true if the given matrix is skew symmetric with respect to its main diagonal, i.e., transpose(M) == -M, otherwise return false.\n\nExamples\n\njulia> M = matrix(ZZ, [0 -1 -2; 1 0 -3; 2 3 0])\n[0 -1 -2]\n[1 0 -3]\n[2 3 0]\n\njulia> is_skew_symmetric(M)\ntrue\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Powering","page":"Matrix functionality","title":"Powering","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"powers(::MatElem, ::Int)","category":"page"},{"location":"matrix/#AbstractAlgebra.powers-Tuple{MatElem, Int64}","page":"Matrix functionality","title":"AbstractAlgebra.powers","text":"powers(a::Union{NCRingElement, MatElem}, d::Int)\n\nReturn an array M of \"powers\" of a where Mi + 1 = a^i for i = 0d.\n\nExamples\n\njulia> M = ZZ[1 2 3; 2 3 4; 4 5 5]\n[1 2 3]\n[2 3 4]\n[4 5 5]\n\njulia> A = powers(M, 4)\n5-element Vector{AbstractAlgebra.Generic.MatSpaceElem{BigInt}}:\n [1 0 0; 0 1 0; 0 0 1]\n [1 2 3; 2 3 4; 4 5 5]\n [17 23 26; 24 33 38; 34 48 57]\n [167 233 273; 242 337 394; 358 497 579]\n [1725 2398 2798; 2492 3465 4044; 3668 5102 5957]\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Gram-matrix","page":"Matrix functionality","title":"Gram matrix","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"gram(::MatElem)","category":"page"},{"location":"matrix/#AbstractAlgebra.gram-Tuple{MatElem}","page":"Matrix functionality","title":"AbstractAlgebra.gram","text":"gram(x::MatElem)\n\nReturn the Gram matrix of x, i.e. if x is an rtimes c matrix return the rtimes r matrix whose entries i j are the dot products of the i-th and j-th rows, respectively.\n\nExamples\n\njulia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in t over rationals\n\njulia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])\n[t + 1 t 1]\n[ t^2 t t]\n[ -2 t + 2 t^2 + t + 1]\n\njulia> B = gram(A)\n[2*t^2 + 2*t + 2 t^3 + 2*t^2 + t 2*t^2 + t - 1]\n[t^3 + 2*t^2 + t t^4 + 2*t^2 t^3 + 3*t]\n[ 2*t^2 + t - 1 t^3 + 3*t t^4 + 2*t^3 + 4*t^2 + 6*t + 9]\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Trace","page":"Matrix functionality","title":"Trace","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"tr(::MatElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#LinearAlgebra.tr-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"LinearAlgebra.tr","text":"tr(x::MatrixElem{T}) where T <: NCRingElement\n\nReturn the trace of the matrix a, i.e. the sum of the diagonal elements. We require the matrix to be square.\n\nExamples\n\njulia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in t over rationals\n\njulia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])\n[t + 1 t 1]\n[ t^2 t t]\n[ -2 t + 2 t^2 + t + 1]\n\njulia> b = tr(A)\nt^2 + 3*t + 2\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Content","page":"Matrix functionality","title":"Content","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"content(::MatElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#AbstractAlgebra.content-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.content","text":"content(x::MatrixElem{T}) where T <: RingElement\n\nReturn the content of the matrix a, i.e. the greatest common divisor of all its entries, assuming it exists.\n\nExamples\n\njulia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in t over rationals\n\njulia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])\n[t + 1 t 1]\n[ t^2 t t]\n[ -2 t + 2 t^2 + t + 1]\n\njulia> b = content(A)\n1\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Permutation","page":"Matrix functionality","title":"Permutation","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"*(::Perm, ::MatElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#Base.:*-Union{Tuple{T}, Tuple{Perm, MatElem{T}}} where T<:RingElement","page":"Matrix functionality","title":"Base.:*","text":"*(P::perm, x::MatrixElem{T}) where T <: NCRingElement\n\nApply the pemutation P to the rows of the matrix x and return the result.\n\nExamples\n\njulia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in t over rationals\n\njulia> G = SymmetricGroup(3)\nFull symmetric group over 3 elements\n\njulia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])\n[t + 1 t 1]\n[ t^2 t t]\n[ -2 t + 2 t^2 + t + 1]\n\njulia> P = G([1, 3, 2])\n(2,3)\n\njulia> B = P*A\n[t + 1 t 1]\n[ -2 t + 2 t^2 + t + 1]\n[ t^2 t t]\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#LU-factorisation","page":"Matrix functionality","title":"LU factorisation","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"lu{T <: FieldElem}(::MatElem{T}, ::SymmetricGroup)","category":"page"},{"location":"matrix/#LinearAlgebra.lu-Union{Tuple{T}, Tuple{MatElem{T}, AbstractAlgebra.SymmetricGroup}} where T<:FieldElem","page":"Matrix functionality","title":"LinearAlgebra.lu","text":"lu(A::MatrixElem{T}, P = SymmetricGroup(nrows(A))) where {T <: FieldElement}\n\nReturn a tuple r p L U consisting of the rank of A, a permutation p of A belonging to P, a lower triangular matrix L and an upper triangular matrix U such that p(A) = LU, where p(A) stands for the matrix whose rows are the given permutation p of the rows of A.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"fflu{T <: RingElem}(::MatElem{T}, ::SymmetricGroup)","category":"page"},{"location":"matrix/#AbstractAlgebra.fflu-Union{Tuple{T}, Tuple{MatElem{T}, AbstractAlgebra.SymmetricGroup}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.fflu","text":"fflu(A::MatrixElem{T}, P = SymmetricGroup(nrows(A))) where {T <: RingElement}\n\nReturn a tuple r d p L U consisting of the rank of A, a denominator d, a permutation p of A belonging to P, a lower triangular matrix L and an upper triangular matrix U such that p(A) = LDU, where p(A) stands for the matrix whose rows are the given permutation p of the rows of A and such that D is the diagonal matrix diag(p_1 p_1p_2 ldots p_n-2p_n-1 p_n-1p_n) where the p_i are the inverses of the diagonal entries of L. The denominator d is set to pm mathrmdet(S) where S is an appropriate submatrix of A (S = A if A is square and nonsingular) and the sign is decided by the parity of the permutation.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> K, = residue_field(R, x^3 + 3x + 1); a = K(x);\n\njulia> S = matrix_space(K, 3, 3)\nMatrix space of 3 rows and 3 columns\n over residue field of univariate polynomial ring modulo x^3 + 3*x + 1\n\njulia> A = S([K(0) 2a + 3 a^2 + 1; a^2 - 2 a - 1 2a; a^2 - 2 a - 1 2a])\n[ 0 2*x + 3 x^2 + 1]\n[x^2 - 2 x - 1 2*x]\n[x^2 - 2 x - 1 2*x]\n\njulia> r, P, L, U = lu(A)\n(2, (1,2), [1 0 0; 0 1 0; 1 0 1], [x^2-2 x-1 2*x; 0 2*x+3 x^2+1; 0 0 0])\n\njulia> r, d, P, L, U = fflu(A)\n(2, 3*x^2 - 10*x - 8, (1,2), [x^2-2 0 0; 0 3*x^2-10*x-8 0; x^2-2 0 1], [x^2-2 x-1 2*x; 0 3*x^2-10*x-8 -4*x^2-x-2; 0 0 0])\n","category":"page"},{"location":"matrix/#Reduced-row-echelon-form","page":"Matrix functionality","title":"Reduced row-echelon form","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"rref_rational{T <: RingElem}(::MatElem{T})\nrref{T <: FieldElem}(::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.rref_rational-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.rref_rational","text":"rref_rational(M::MatrixElem{T}) where {T <: RingElement}\n\nReturn a tuple (r A d) consisting of the rank r of M and a denominator d in the base ring of M and a matrix A such that Ad is the reduced row echelon form of M. Note that the denominator is not usually minimal.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.rref-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:FieldElem","page":"Matrix functionality","title":"AbstractAlgebra.rref","text":"rref(M::MatrixElem{T}) where {T <: FieldElement}\n\nReturn a tuple (r A) consisting of the rank r of M and a reduced row echelon form A of M.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_rref{T <: RingElem}(::MatElem{T})\nis_rref{T <: FieldElem}(::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.is_rref-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.is_rref","text":"is_rref(M::MatrixElem{T}) where {T <: RingElement}\n\nReturn true if M is in reduced row echelon form, otherwise return false.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.is_rref-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:FieldElem","page":"Matrix functionality","title":"AbstractAlgebra.is_rref","text":"is_rref(M::MatrixElem{T}) where {T <: RingElement}\n\nReturn true if M is in reduced row echelon form, otherwise return false.\n\n\n\n\n\nis_rref(M::MatrixElem{T}) where {T <: FieldElement}\n\nReturn true if M is in reduced row echelon form, otherwise return false.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> K, = residue_field(R, x^3 + 3x + 1); a = K(x);\n\njulia> S = matrix_space(K, 3, 3)\nMatrix space of 3 rows and 3 columns\n over residue field of univariate polynomial ring modulo x^3 + 3*x + 1\n\njulia> M = S([K(0) 2a + 3 a^2 + 1; a^2 - 2 a - 1 2a; a^2 + 3a + 1 2a K(1)])\n[ 0 2*x + 3 x^2 + 1]\n[ x^2 - 2 x - 1 2*x]\n[x^2 + 3*x + 1 2*x 1]\n\njulia> r, A = rref(M)\n(3, [1 0 0; 0 1 0; 0 0 1])\n\njulia> is_rref(A)\ntrue\n\njulia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in x over integers\n\njulia> M = S([R(0) 2x + 3 x^2 + 1; x^2 - 2 x - 1 2x; x^2 + 3x + 1 2x R(1)])\n[ 0 2*x + 3 x^2 + 1]\n[ x^2 - 2 x - 1 2*x]\n[x^2 + 3*x + 1 2*x 1]\n\njulia> r, A, d = rref_rational(M)\n(3, [-x^5-2*x^4-15*x^3-18*x^2-8*x-7 0 0; 0 -x^5-2*x^4-15*x^3-18*x^2-8*x-7 0; 0 0 -x^5-2*x^4-15*x^3-18*x^2-8*x-7], -x^5 - 2*x^4 - 15*x^3 - 18*x^2 - 8*x - 7)\n\njulia> is_rref(A)\ntrue","category":"page"},{"location":"matrix/#Determinant","page":"Matrix functionality","title":"Determinant","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"det{T <: RingElem}(::MatElem{T})","category":"page"},{"location":"matrix/#LinearAlgebra.det-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"LinearAlgebra.det","text":"det(M::MatrixElem{T}) where {T <: RingElement}\n\nReturn the determinant of the matrix M. We assume M is square.\n\nExamples\n\njulia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> A = R[x 1; 1 x^2];\n\njulia> d = det(A)\nx^3 - 1\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Rank","page":"Matrix functionality","title":"Rank","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"rank{T <: RingElem}(::MatElem{T})","category":"page"},{"location":"matrix/#LinearAlgebra.rank-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"LinearAlgebra.rank","text":"rank(M::MatrixElem{T}) where {T <: RingElement}\n\nReturn the rank of the matrix M.\n\nExamples\n\njulia> A = QQ[1 2; 3 4];\n\njulia> d = rank(A)\n2\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Minors","page":"Matrix functionality","title":"Minors","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"minors(::MatElem, ::Int)","category":"page"},{"location":"matrix/#AbstractAlgebra.minors-Tuple{MatElem, Int64}","page":"Matrix functionality","title":"AbstractAlgebra.minors","text":"minors(A::MatElem, k::Int)\n\nReturn an array consisting of the k-minors of A.\n\nExamples\n\njulia> A = ZZ[1 2 3; 4 5 6]\n[1 2 3]\n[4 5 6]\n\njulia> minors(A, 2)\n3-element Vector{BigInt}:\n -3\n -6\n -3\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Exterior-power","page":"Matrix functionality","title":"Exterior power","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"exterior_power(::MatElem, ::Int)","category":"page"},{"location":"matrix/#AbstractAlgebra.exterior_power-Tuple{MatElem, Int64}","page":"Matrix functionality","title":"AbstractAlgebra.exterior_power","text":"exterior_power(A::MatElem, k::Int) -> MatElem\n\nReturn the k-th exterior power of A.\n\nExamples\n\njulia> A = matrix(ZZ, 3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]);\n\njulia> exterior_power(A, 2)\n[-3 -6 -3]\n[-6 -12 -6]\n[-3 -6 -3]\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Pfaffian","page":"Matrix functionality","title":"Pfaffian","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"pfaffian(::MatElem)\npfaffians(::MatElem, ::Int)","category":"page"},{"location":"matrix/#AbstractAlgebra.pfaffian-Tuple{MatElem}","page":"Matrix functionality","title":"AbstractAlgebra.pfaffian","text":"pfaffian(M::MatElem)\n\nReturn the Pfaffian of a skew-symmetric matrix M.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.pfaffians-Tuple{MatElem, Int64}","page":"Matrix functionality","title":"AbstractAlgebra.pfaffians","text":"pfaffians(M::MatElem, k::Int)\n\nReturn a vector consisting of the k-Pfaffians of a skew-symmetric matrix M.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> R, x = polynomial_ring(QQ, [\"x$i\" for i in 1:6])\n(Multivariate polynomial ring in 6 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x1, x2, x3, x4, x5, x6])\n\njulia> M = R[0 x[1] x[2] x[3]; -x[1] 0 x[4] x[5]; -x[2] -x[4] 0 x[6]; -x[3] -x[5] -x[6] 0]\n[ 0 x1 x2 x3]\n[-x1 0 x4 x5]\n[-x2 -x4 0 x6]\n[-x3 -x5 -x6 0]\n\njulia> pfaffian(M)\nx1*x6 - x2*x5 + x3*x4\n\njulia> pfaffians(M, 2)\n6-element Vector{AbstractAlgebra.Generic.MPoly{Rational{BigInt}}}:\n x1\n x2\n x4\n x3\n x5\n x6\n ","category":"page"},{"location":"matrix/#Linear-solving","page":"Matrix functionality","title":"Linear solving","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"solve{T <: FieldElem}(::MatElem{T}, ::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.solve-Union{Tuple{T}, Tuple{MatElem{T}, MatElem{T}}} where T<:FieldElem","page":"Matrix functionality","title":"AbstractAlgebra.solve","text":"solve(a::MatElem{S}, b::MatElem{S}) where {S <: RingElement}\n\nGiven an mtimes r matrix a over a ring and an mtimes n matrix b over the same ring, return an rtimes n matrix x such that ax = b. If no such matrix exists, an exception is raised. See also solve_left.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"solve_rational{T <: RingElem}(::MatElem{T}, ::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.solve_rational-Union{Tuple{T}, Tuple{MatElem{T}, MatElem{T}}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.solve_rational","text":"solve_rational(M::MatElem{T}, b::MatElem{T}) where T <: RingElement\n\nGiven a non-singular ntimes n matrix over a ring and an ntimes m matrix over the same ring, return a tuple x d consisting of an ntimes m matrix x and a denominator d such that Ax = db. The denominator will be the determinant of A up to sign. If A is singular an exception is raised.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"can_solve_with_solution{T <: RingElement}(::MatElem{T}, ::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.can_solve_with_solution-Union{Tuple{T}, Tuple{MatElem{T}, MatElem{T}}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.can_solve_with_solution","text":"can_solve_with_solution(a::MatElem{S}, b::MatElem{S}; side::Symbol = :right) where S <: RingElement\n\nGiven two matrices a and b over the same ring, try to solve ax = b if side is :right or xa = b if side is :left. In either case, return a tuple (flag, x). If a solution exists, flag is set to true and x is a solution. If no solution exists, flag is set to false and x is arbitrary. If the dimensions of a and b are incompatible, an exception is raised.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"can_solve{T <: RingElement}(::MatElem{T}, ::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.can_solve-Union{Tuple{T}, Tuple{MatElem{T}, MatElem{T}}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.can_solve","text":"can_solve(a::MatElem{S}, b::MatElem{S}; side::Symbol = :right) where S <: RingElement\n\nGiven two matrices a and b over the same ring, check the solubility of ax = b if side is :right or xa = b if side is :left. Return true if a solution exists, false otherwise. If the dimensions of a and b are incompatible, an exception is raised. If a solution should be computed as well, use can_solve_with_solution instead.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"solve_left{T <: RingElem}(::MatElem{T}, ::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.solve_left-Union{Tuple{T}, Tuple{MatElem{T}, MatElem{T}}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.solve_left","text":"solve_left(a::MatElem{S}, b::MatElem{S}) where S <: RingElement\n\nGiven an rtimes n matrix a over a ring and an mtimes n matrix b over the same ring, return an mtimes r matrix x such that xa = b. If no such matrix exists, an exception is raised. See also solve.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"solve_triu{T <: FieldElem}(::MatElem{T}, ::MatElem{T}, ::Bool)","category":"page"},{"location":"matrix/#AbstractAlgebra.solve_triu-Union{Tuple{T}, Tuple{MatElem{T}, MatElem{T}, Bool}} where T<:FieldElem","page":"Matrix functionality","title":"AbstractAlgebra.solve_triu","text":"solve_triu(U::MatElem{T}, b::MatElem{T}, unit::Bool = false) where {T <: FieldElement}\n\nGiven a non-singular ntimes n matrix U over a field which is upper triangular, and an ntimes m matrix b over the same field, return an ntimes m matrix x such that Ux = b. If U is singular an exception is raised. If unit is true then U is assumed to have ones on its diagonal, and the diagonal will not be read.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"can_solve_left_reduced_triu{T <: RingElement}(::MatElem{T}, ::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.can_solve_left_reduced_triu-Union{Tuple{T}, Tuple{MatElem{T}, MatElem{T}}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.can_solve_left_reduced_triu","text":"can_solve_left_reduced_triu(r::MatElem{T},\n M::MatElem{T}) where T <: RingElement\n\nReturn a tuple flag, x where flag is set to true if xM = r has a solution, where M is an mtimes n matrix in (upper triangular) Hermite normal form or reduced row echelon form and r and x are row vectors with m columns (i.e. 1 times m matrices). If there is no solution, flag is set to false and x is set to zero.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> K, = residue_field(R, x^3 + 3x + 1); a = K(x);\n\njulia> S = matrix_space(K, 3, 3)\nMatrix space of 3 rows and 3 columns\n over residue field of univariate polynomial ring modulo x^3 + 3*x + 1\n\njulia> U = matrix_space(K, 3, 1)\nMatrix space of 3 rows and 1 column\n over residue field of univariate polynomial ring modulo x^3 + 3*x + 1\n\njulia> A = S([K(0) 2a + 3 a^2 + 1; a^2 - 2 a - 1 2a; a^2 + 3a + 1 2a K(1)])\n[ 0 2*x + 3 x^2 + 1]\n[ x^2 - 2 x - 1 2*x]\n[x^2 + 3*x + 1 2*x 1]\n\njulia> b = U([2a, a + 1, (-a - 1)])\n[ 2*x]\n[ x + 1]\n[-x - 1]\n\njulia> x = solve(A, b)\n[ 1984//7817*x^2 + 1573//7817*x - 937//7817]\n[ -2085//7817*x^2 + 1692//7817*x + 965//7817]\n[-3198//7817*x^2 + 3540//7817*x - 3525//7817]\n\njulia> A = matrix(ZZ, 2, 2, [1, 2, 0, 2])\n[1 2]\n[0 2]\n\njulia> b = matrix(ZZ, 2, 1, [2, 1])\n[2]\n[1]\n\njulia> can_solve(A, b, side = :right)\nfalse\n\njulia> A = matrix(QQ, 2, 2, [3, 4, 5, 6])\n[3//1 4//1]\n[5//1 6//1]\n\njulia> b = matrix(QQ, 1, 2, [2, 1])\n[2//1 1//1]\n\njulia> can_solve_with_solution(A, b; side = :left)\n(true, [-7//2 5//2])\n\njulia> A = S([a + 1 2a + 3 a^2 + 1; K(0) a^2 - 1 2a; K(0) K(0) a])\n[x + 1 2*x + 3 x^2 + 1]\n[ 0 x^2 - 1 2*x]\n[ 0 0 x]\n\njulia> bb = U([2a, a + 1, (-a - 1)])\n[ 2*x]\n[ x + 1]\n[-x - 1]\n\njulia> x = solve_triu(A, bb, false)\n[ 1//3*x^2 + 8//3*x + 13//3]\n[-3//5*x^2 - 3//5*x - 12//5]\n[ x^2 + 2]\n\njulia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in x over integers\n\njulia> U = matrix_space(R, 3, 2)\nMatrix space of 3 rows and 2 columns\n over univariate polynomial ring in x over integers\n\njulia> A = S([R(0) 2x + 3 x^2 + 1; x^2 - 2 x - 1 2x; x^2 + 3x + 1 2x R(1)])\n[ 0 2*x + 3 x^2 + 1]\n[ x^2 - 2 x - 1 2*x]\n[x^2 + 3*x + 1 2*x 1]\n\njulia> bbb = U(transpose([2x x + 1 (-x - 1); x + 1 (-x) x^2]))\n[ 2*x x + 1]\n[ x + 1 -x]\n[-x - 1 x^2]\n\njulia> x, d = solve_rational(A, bbb)\n([3*x^4-10*x^3-8*x^2-11*x-4 -x^5+3*x^4+x^3-2*x^2+3*x-1; -2*x^5-x^4+6*x^3+2*x+1 x^6+x^5+4*x^4+9*x^3+8*x^2+5*x+2; 6*x^4+12*x^3+15*x^2+6*x-3 -2*x^5-4*x^4-6*x^3-9*x^2-4*x+1], x^5 + 2*x^4 + 15*x^3 + 18*x^2 + 8*x + 7)\n\njulia> S = matrix_space(ZZ, 3, 3)\nMatrix space of 3 rows and 3 columns\n over integers\n\njulia> T = matrix_space(ZZ, 3, 1)\nMatrix space of 3 rows and 1 column\n over integers\n\njulia> A = S([BigInt(2) 3 5; 1 4 7; 9 2 2])\n[2 3 5]\n[1 4 7]\n[9 2 2]\n\njulia> B = T([BigInt(4), 5, 7])\n[4]\n[5]\n[7]","category":"page"},{"location":"matrix/#Inverse","page":"Matrix functionality","title":"Inverse","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Base.inv{T <: RingElement}(::MatrixElem{T})","category":"page"},{"location":"matrix/#Base.inv-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"Base.inv","text":"inv(M::MatrixElem{T}) where {T <: RingElement}\n\nGiven a non-singular ntimes n matrix over a ring, return an ntimes n matrix X such that MX = I_n, where I_n is the ntimes n identity matrix. If M is not invertible over the base ring an exception is raised.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_invertible_with_inverse{T <: RingElement}(::MatrixElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.is_invertible_with_inverse-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.is_invertible_with_inverse","text":"is_invertible_with_inverse(A::MatrixElem{T}; side::Symbol = :left) where {T <: RingElement}\n\nGiven an ntimes m matrix A over a ring, return a tuple (flag, B). If side is :right and flag is true, B is the right inverse of A i.e. AB is the ntimes n unit matrix. If side is :left and flag is true, B is the left inverse of A i.e. BA is the mtimes m unit matrix. If flag is false, no right or left inverse exists.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_invertible{T <: RingElement}(::MatrixElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.is_invertible-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.is_invertible","text":"is_invertible(A::MatrixElem{T}) where {T <: RingElement}\n\nReturn true if a given square matrix is invertible, false otherwise. If the inverse should also be computed, use is_invertible_with_inverse.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> K, = residue_field(R, x^3 + 3x + 1); a = K(x);\n\njulia> S = matrix_space(K, 3, 3)\nMatrix space of 3 rows and 3 columns\n over residue field of univariate polynomial ring modulo x^3 + 3*x + 1\n\njulia> A = S([K(0) 2a + 3 a^2 + 1; a^2 - 2 a - 1 2a; a^2 + 3a + 1 2a K(1)])\n[ 0 2*x + 3 x^2 + 1]\n[ x^2 - 2 x - 1 2*x]\n[x^2 + 3*x + 1 2*x 1]\n\njulia> X = inv(A)\n[-343//7817*x^2 + 717//7817*x - 2072//7817 -4964//23451*x^2 + 2195//23451*x - 11162//23451 -232//23451*x^2 - 4187//23451*x - 1561//23451]\n[ 128//7817*x^2 - 655//7817*x + 2209//7817 599//23451*x^2 - 2027//23451*x - 1327//23451 -1805//23451*x^2 + 2702//23451*x - 7394//23451]\n[ 545//7817*x^2 + 570//7817*x + 2016//7817 -1297//23451*x^2 - 5516//23451*x - 337//23451 8254//23451*x^2 - 2053//23451*x + 16519//23451]\n\njulia> is_invertible(A)\ntrue\n\njulia> is_invertible_with_inverse(A)\n(true, [-343//7817*x^2+717//7817*x-2072//7817 -4964//23451*x^2+2195//23451*x-11162//23451 -232//23451*x^2-4187//23451*x-1561//23451; 128//7817*x^2-655//7817*x+2209//7817 599//23451*x^2-2027//23451*x-1327//23451 -1805//23451*x^2+2702//23451*x-7394//23451; 545//7817*x^2+570//7817*x+2016//7817 -1297//23451*x^2-5516//23451*x-337//23451 8254//23451*x^2-2053//23451*x+16519//23451])\n\njulia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S = matrix_space(R, 3, 3)\nMatrix space of 3 rows and 3 columns\n over univariate polynomial ring in x over integers\n\njulia> A = S([R(0) 2x + 3 x^2 + 1; x^2 - 2 x - 1 2x; x^2 + 3x + 1 2x R(1)])\n[ 0 2*x + 3 x^2 + 1]\n[ x^2 - 2 x - 1 2*x]\n[x^2 + 3*x + 1 2*x 1]\n\njulia> X, d = pseudo_inv(A)\n([4*x^2-x+1 -2*x^3+3 x^3-5*x^2-5*x-1; -2*x^3-5*x^2-2*x-2 x^4+3*x^3+2*x^2+3*x+1 -x^4+x^2+2; -x^3+2*x^2+2*x-1 -2*x^3-9*x^2-11*x-3 2*x^3+3*x^2-4*x-6], -x^5 - 2*x^4 - 15*x^3 - 18*x^2 - 8*x - 7)\n","category":"page"},{"location":"matrix/#Nullspace","page":"Matrix functionality","title":"Nullspace","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"nullspace{T <: FieldElem}(::MatElem{T})","category":"page"},{"location":"matrix/#LinearAlgebra.nullspace-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:FieldElem","page":"Matrix functionality","title":"LinearAlgebra.nullspace","text":"nullspace(M::MatElem{T}) where {T <: RingElement}\n\nReturn a tuple (nu N) consisting of the nullity nu of M and a basis N (consisting of column vectors) for the right nullspace of M, i.e. such that MN is the zero matrix. If M is an mtimes n matrix N will be an ntimes nu matrix. Note that the nullspace is taken to be the vector space kernel over the fraction field of the base ring if the latter is not a field. In AbstractAlgebra we use the name \"kernel\" for a function to compute an integral kernel.\n\nExamples\n\njulia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S = matrix_space(R, 4, 4)\nMatrix space of 4 rows and 4 columns\n over univariate polynomial ring in x over integers\n\njulia> M = S([-6*x^2+6*x+12 -12*x^2-21*x-15 -15*x^2+21*x+33 -21*x^2-9*x-9;\n -8*x^2+8*x+16 -16*x^2+38*x-20 90*x^2-82*x-44 60*x^2+54*x-34;\n -4*x^2+4*x+8 -8*x^2+13*x-10 35*x^2-31*x-14 22*x^2+21*x-15;\n -10*x^2+10*x+20 -20*x^2+70*x-25 150*x^2-140*x-85 105*x^2+90*x-50])\n[ -6*x^2 + 6*x + 12 -12*x^2 - 21*x - 15 -15*x^2 + 21*x + 33 -21*x^2 - 9*x - 9]\n[ -8*x^2 + 8*x + 16 -16*x^2 + 38*x - 20 90*x^2 - 82*x - 44 60*x^2 + 54*x - 34]\n[ -4*x^2 + 4*x + 8 -8*x^2 + 13*x - 10 35*x^2 - 31*x - 14 22*x^2 + 21*x - 15]\n[-10*x^2 + 10*x + 20 -20*x^2 + 70*x - 25 150*x^2 - 140*x - 85 105*x^2 + 90*x - 50]\n\njulia> n, N = nullspace(M)\n(2, [1320*x^4-330*x^2-1320*x-1320 1056*x^4+1254*x^3+1848*x^2-66*x-330; -660*x^4+1320*x^3+1188*x^2-1848*x-1056 -528*x^4+132*x^3+1584*x^2+660*x-264; 396*x^3-396*x^2-792*x 0; 0 396*x^3-396*x^2-792*x])\n\n\n\n\n\nnullspace(M::MatElem{T}) where {T <: FieldElement}\n\nReturn a tuple (nu N) consisting of the nullity nu of M and a basis N (consisting of column vectors) for the right nullspace of M, i.e. such that MN is the zero matrix. If M is an mtimes n matrix N will be an ntimes nu matrix.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Kernel","page":"Matrix functionality","title":"Kernel","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"kernel{T <: RingElem}(::MatElem{T})\nleft_kernel{T <: RingElem}(::MatElem{T})\nright_kernel{T <: RingElem}(::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.kernel-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.kernel","text":"kernel(A::MatElem{T}; side::Symbol = :right) where T <: RingElement\n\nReturn a tuple (n M), where n is the rank of the kernel of A and M is a basis for it. If side is :right or not specified, the right kernel is computed, i.e. the matrix of columns whose span gives the right kernel space. If side is :left, the left kernel is computed, i.e. the matrix of rows whose span is the left kernel space.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.left_kernel-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.left_kernel","text":"left_kernel(A::MatElem{T}) where T <: RingElement\n\nReturn a tuple (n M) where M is a matrix whose rows generate the kernel of A and n is the rank of the kernel. The transpose of the output of this function is guaranteed to be in flipped upper triangular format (i.e. upper triangular format if columns and rows are reversed).\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.right_kernel-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.right_kernel","text":"right_kernel(A::MatElem{T}) where T <: RingElement\n\nReturn a tuple (n M) where M is a matrix whose columns generate the kernel of A and n is the rank of the kernel.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> S = matrix_space(ZZ, 4, 4)\nMatrix space of 4 rows and 4 columns\n over integers\n\njulia> M = S([1 2 0 4;\n 2 0 1 1;\n 0 1 1 -1;\n 2 -1 0 2])\n[1 2 0 4]\n[2 0 1 1]\n[0 1 1 -1]\n[2 -1 0 2]\n\njulia> nr, Nr = kernel(M)\n(1, [-8; -6; 11; 5])\n\njulia> nl, Nl = left_kernel(M)\n(1, [0 -1 1 1])\n","category":"page"},{"location":"matrix/#Hessenberg-form","page":"Matrix functionality","title":"Hessenberg form","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"hessenberg{T <: RingElem}(::MatElem{T})","category":"page"},{"location":"matrix/#LinearAlgebra.hessenberg-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"LinearAlgebra.hessenberg","text":"hessenberg(A::MatrixElem{T}) where {T <: RingElement}\n\nReturn the Hessenberg form of M, i.e. an upper Hessenberg matrix which is similar to M. The upper Hessenberg form has nonzero entries above and on the diagonal and in the diagonal line immediately below the diagonal.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_hessenberg{T <: RingElem}(::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.is_hessenberg-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.is_hessenberg","text":"is_hessenberg(A::MatrixElem{T}) where {T <: RingElement}\n\nReturn true if M is in Hessenberg form, otherwise returns false.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> R, = residue_ring(ZZ, 7);\n\njulia> S = matrix_space(R, 4, 4)\nMatrix space of 4 rows and 4 columns\n over residue ring of integers modulo 7\n\njulia> M = S([R(1) R(2) R(4) R(3); R(2) R(5) R(1) R(0);\n R(6) R(1) R(3) R(2); R(1) R(1) R(3) R(5)])\n[1 2 4 3]\n[2 5 1 0]\n[6 1 3 2]\n[1 1 3 5]\n\njulia> A = hessenberg(M)\n[1 5 5 3]\n[2 1 1 0]\n[0 1 3 2]\n[0 0 2 2]\n\njulia> is_hessenberg(A)\ntrue\n","category":"page"},{"location":"matrix/#Characteristic-polynomial","page":"Matrix functionality","title":"Characteristic polynomial","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"charpoly{T <: RingElem}(::PolyRing{T}, ::MatrixElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.charpoly-Union{Tuple{T}, Tuple{PolyRing{T}, MatrixElem{T}}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.charpoly","text":"charpoly(Y::MatrixElem{T}) where {T <: RingElement}\ncharpoly(S::PolyRing{T}, Y::MatrixElem{T}) where {T <: RingElement}\n\nReturn the characteristic polynomial p of the square matrix Y. If a polynomial ring S over the same base ring as Y is supplied, the resulting polynomial is an element of it.\n\nExamples\n\njulia> R, = residue_ring(ZZ, 7);\n\njulia> S = matrix_space(R, 4, 4)\nMatrix space of 4 rows and 4 columns\n over residue ring of integers modulo 7\n\njulia> T, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over residue ring, y)\n\njulia> M = S([R(1) R(2) R(4) R(3); R(2) R(5) R(1) R(0);\n R(6) R(1) R(3) R(2); R(1) R(1) R(3) R(5)])\n[1 2 4 3]\n[2 5 1 0]\n[6 1 3 2]\n[1 1 3 5]\n\njulia> A = charpoly(T, M)\ny^4 + 2*y^2 + 6*y + 2\n\njulia> A = charpoly(M)\nx^4 + 2*x^2 + 6*x + 2\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Minimal-polynomial","page":"Matrix functionality","title":"Minimal polynomial","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"minpoly{T <: RingElem}(::PolyRing{T}, ::MatElem{T}, ::Bool)","category":"page"},{"location":"matrix/#AbstractAlgebra.minpoly-Union{Tuple{T}, Tuple{PolyRing{T}, MatElem{T}, Bool}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.minpoly","text":"minpoly(M::MatElem{T}, charpoly_only::Bool = false) where {T <: RingElement}\nminpoly(S::PolyRing{T}, M::MatElem{T}, charpoly_only::Bool = false) where {T <: RingElement}\n\nReturn the minimal polynomial p of the square matrix M. If a polynomial ring S over the same base ring as Y is supplied, the resulting polynomial is an element of it.\n\nExamples\n\njulia> R = GF(13)\nFinite field F_13\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over finite field F_13, y)\n\njulia> M = R[7 6 1;\n 7 7 5;\n 8 12 5]\n[7 6 1]\n[7 7 5]\n[8 12 5]\n\njulia> A = minpoly(S, M)\ny^2 + 10*y\n\njulia> A = minpoly(M)\nx^2 + 10*x\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Transforms","page":"Matrix functionality","title":"Transforms","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"similarity!{T <: RingElem}(::MatElem{T}, ::Int, ::T)","category":"page"},{"location":"matrix/#AbstractAlgebra.similarity!-Union{Tuple{T}, Tuple{MatElem{T}, Int64, T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.similarity!","text":"similarity!(A::MatrixElem{T}, r::Int, d::T) where {T <: RingElement}\n\nApplies a similarity transform to the ntimes n matrix M in-place. Let P be the ntimes n identity matrix that has had all zero entries of row r replaced with d, then the transform applied is equivalent to M = P^-1MP. We require M to be a square matrix. A similarity transform preserves the minimal and characteristic polynomials of a matrix.\n\nExamples\n\njulia> R, = residue_ring(ZZ, 7);\n\njulia> S = matrix_space(R, 4, 4)\nMatrix space of 4 rows and 4 columns\n over residue ring of integers modulo 7\n\njulia> M = S([R(1) R(2) R(4) R(3); R(2) R(5) R(1) R(0);\n R(6) R(1) R(3) R(2); R(1) R(1) R(3) R(5)])\n[1 2 4 3]\n[2 5 1 0]\n[6 1 3 2]\n[1 1 3 5]\n\njulia> similarity!(M, 1, R(3))\n\n\n\n\n\n\n","category":"method"},{"location":"matrix/#Hermite-normal-form","page":"Matrix functionality","title":"Hermite normal form","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"hnf{T <: RingElem}(::MatElem{T})\nhnf_with_transform{T <: RingElem}(::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.hnf-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.hnf","text":"hnf(A::MatrixElem{T}) where {T <: RingElement}\n\nReturn the upper right row Hermite normal form of A.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.hnf_with_transform-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.hnf_with_transform","text":"hnf_with_transform(A)\n\nReturn the tuple H U consisting of the upper right row Hermite normal form H of A together with invertible matrix U such that UA = H.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_hnf{T <: RingElem}(::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.is_hnf-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.is_hnf","text":"is_hnf(M::MatrixElem{T}) where T <: RingElement\n\nReturn true if the matrix is in Hermite normal form.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> A = matrix(ZZ, [2 3 -1; 3 5 7; 11 1 12])\n[ 2 3 -1]\n[ 3 5 7]\n[11 1 12]\n\njulia> H = hnf(A)\n[1 0 255]\n[0 1 17]\n[0 0 281]\n\njulia> is_hnf(H)\ntrue\n\njulia> H, U = hnf_with_transform(A)\n([1 0 255; 0 1 17; 0 0 281], [-47 28 1; -3 2 0; -52 31 1])\n\njulia> U*A\n[1 0 255]\n[0 1 17]\n[0 0 281]","category":"page"},{"location":"matrix/#Smith-normal-form","page":"Matrix functionality","title":"Smith normal form","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_snf(::MatrixElem{T}) where T <: RingElement","category":"page"},{"location":"matrix/#AbstractAlgebra.is_snf-Union{Tuple{MatrixElem{T}}, Tuple{T}} where T<:RingElement","page":"Matrix functionality","title":"AbstractAlgebra.is_snf","text":"is_snf(A::MatrixElem{T}) where T <: RingElement\n\nReturn true if A is in Smith Normal Form.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"snf{T <: RingElem}(::MatElem{T})\nsnf_with_transform{T <: RingElem}(::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.snf-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.snf","text":"snf(A::MatrixElem{T}) where {T <: RingElement}\n\nReturn the Smith normal form of A.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.snf_with_transform-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:RingElem","page":"Matrix functionality","title":"AbstractAlgebra.snf_with_transform","text":"snf_with_transform(A)\n\nReturn the tuple S T U consisting of the Smith normal form S of A together with invertible matrices T and U such that TAU = S.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> A = matrix(ZZ, [2 3 -1; 3 5 7; 11 1 12])\n[ 2 3 -1]\n[ 3 5 7]\n[11 1 12]\n\njulia> S = snf(A)\n[1 0 0]\n[0 1 0]\n[0 0 281]\n\njulia> S, T, U = snf_with_transform(A)\n([1 0 0; 0 1 0; 0 0 281], [1 0 0; 7 1 0; 229 31 1], [0 -3 26; 0 2 -17; -1 0 1])\n\njulia> T*A*U\n[1 0 0]\n[0 1 0]\n[0 0 281]","category":"page"},{"location":"matrix/#(Weak)-Popov-form","page":"Matrix functionality","title":"(Weak) Popov form","text":"","category":"section"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"AbstractAlgebra.jl provides algorithms for computing the (weak) Popov of a matrix with entries in a univariate polynomial ring over a field.","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"is_weak_popov(P::MatrixElem{T}, rank::Int) where T <: Generic.Poly","category":"page"},{"location":"matrix/#AbstractAlgebra.is_weak_popov-Union{Tuple{T}, Tuple{MatrixElem{T}, Int64}} where T<:AbstractAlgebra.Generic.Poly","page":"Matrix functionality","title":"AbstractAlgebra.is_weak_popov","text":"is_weak_popov(P::MatrixElem{T}, rank::Int) where T <: PolyRingElem\n\nReturn true if P is a matrix in weak Popov form of the given rank.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"weak_popov{T <: PolyRingElem}(::MatElem{T})\nweak_popov_with_transform{T <: PolyRingElem}(::MatElem{T})\npopov{T <: PolyRingElem}(::MatElem{T})\npopov_with_transform{T <: PolyRingElem}(::MatElem{T})","category":"page"},{"location":"matrix/#AbstractAlgebra.weak_popov-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:PolyRingElem","page":"Matrix functionality","title":"AbstractAlgebra.weak_popov","text":"weak_popov(A::MatElem{T}) where {T <: PolyRingElem}\n\nReturn the weak Popov form of A.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.weak_popov_with_transform-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:PolyRingElem","page":"Matrix functionality","title":"AbstractAlgebra.weak_popov_with_transform","text":"weak_popov_with_transform(A::MatElem{T}) where {T <: PolyRingElem}\n\nCompute a tuple (P U) where P is the weak Popov form of A and U is a transformation matrix so that P = UA.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.popov-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:PolyRingElem","page":"Matrix functionality","title":"AbstractAlgebra.popov","text":"popov(A::MatElem{T}) where {T <: PolyRingElem}\n\nReturn the Popov form of A.\n\n\n\n\n\n","category":"method"},{"location":"matrix/#AbstractAlgebra.popov_with_transform-Union{Tuple{MatElem{T}}, Tuple{T}} where T<:PolyRingElem","page":"Matrix functionality","title":"AbstractAlgebra.popov_with_transform","text":"popov_with_transform(A::MatElem{T}) where {T <: PolyRingElem}\n\nCompute a tuple (P U) where P is the Popov form of A and U is a transformation matrix so that P = UA.\n\n\n\n\n\n","category":"method"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"Examples","category":"page"},{"location":"matrix/","page":"Matrix functionality","title":"Matrix functionality","text":"julia> R, x = polynomial_ring(QQ, \"x\");\n\njulia> A = matrix(R, map(R, Any[1 2 3 x; x 2*x 3*x x^2; x x^2+1 x^3+x^2 x^4+x^2+1]))\n[1 2 3 x]\n[x 2*x 3*x x^2]\n[x x^2 + 1 x^3 + x^2 x^4 + x^2 + 1]\n\njulia> P = weak_popov(A)\n[ 1 2 3 x]\n[ 0 0 0 0]\n[-x^3 -2*x^3 + x^2 - 2*x + 1 -2*x^3 + x^2 - 3*x 1]\n\njulia> P, U = weak_popov_with_transform(A)\n([1 2 3 x; 0 0 0 0; -x^3 -2*x^3+x^2-2*x+1 -2*x^3+x^2-3*x 1], [1 0 0; -x 1 0; -x^3-x 0 1])\n\njulia> U*A\n[ 1 2 3 x]\n[ 0 0 0 0]\n[-x^3 -2*x^3 + x^2 - 2*x + 1 -2*x^3 + x^2 - 3*x 1]","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"misc/#Miscellaneous","page":"Miscellaneous","title":"Miscellaneous","text":"","category":"section"},{"location":"misc/#Printing-options","page":"Miscellaneous","title":"Printing options","text":"","category":"section"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"AbstractAlgebra supports printing to LaTeX using the MIME type \"text/latex\". To enable LaTeX rendering in Jupyter notebooks and query for the current state, use the following functions:","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"set_html_as_latex\nget_html_as_latex","category":"page"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.set_html_as_latex","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.set_html_as_latex","text":"set_html_as_latex(fl::Bool)\n\nToggles whether MIME type text/html should be printed as text/latex. Note that this is a global option. The return value is the old value.\n\n\n\n\n\n","category":"function"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.get_html_as_latex","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.get_html_as_latex","text":"get_html_as_latex()\n\nReturns whether MIME type text/html is printed as text/latex.\n\n\n\n\n\n","category":"function"},{"location":"misc/#Updating-the-type-diagrams","page":"Miscellaneous","title":"Updating the type diagrams","text":"","category":"section"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"Updating the diagrams of the documentation can be done by modifying and running the script docs/create_type_diagrams.jl. Note that this requires the package Kroki.","category":"page"},{"location":"misc/#Attributes","page":"Miscellaneous","title":"Attributes","text":"","category":"section"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"Often it is desirable to have a flexible way to attach additional data to mathematical structures such as groups, rings, fields, etc. beyond what the original implementation covers. To facilitate this, we provide an attributes system: for objects of suitable types, one may use set_attribute! to attach key-value pairs to the object, and query them using has_attribute, get_attribute and get_attribute!.","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"Attributes are supported for all singletons (i.e., instances of an empty struct type), as well as for instances of mutable struct type for which attribute storage was enabled. There are two ways to enable attribute storage for such types:","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"By applying @attributes to a mutable struct declaration, storage is reserved inside that struct type itself (this increases the size of each struct by 8 bytes if no attributes are set).\nBy applying @attributes to the name of a mutable struct type, methods are installed which store attributes to instances of the type in a WeakKeyDict outside the struct.","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"@attributes\n@attr\nhas_attribute\nget_attribute\nget_attribute!\nset_attribute!","category":"page"},{"location":"misc/#AbstractAlgebra.@attributes","page":"Miscellaneous","title":"AbstractAlgebra.@attributes","text":"@attributes typedef\n\nThis is a helper macro that ensures that there is storage for attributes in the type declared in the expression typedef, which must be either a mutable struct definition expression, or the name of a mutable struct type.\n\nThe latter variant is useful to enable attribute storage for types defined in other packages. Note that @attributes is idempotent: when applied to a type for which attribute storage is already available, it does nothing.\n\nFor singleton types, attribute storage is also supported, and in fact always enabled. Thus it is not necessary to apply this macro to such a type.\n\nnote: Note\nWhen applied to a struct definition this macro adds a new field to the struct. For structs without constructor, this will change the signature of the default inner constructor, which requires explicit values for every field, including the attribute storage field this macro adds. Usually it is thus preferable to add an explicit default constructor, as in the example below.\n\nExamples\n\nApplying the macro to a struct definition results in internal storage of the attributes:\n\njulia> @attributes mutable struct MyGroup\n order::Int\n MyGroup(order::Int) = new(order)\n end\n\njulia> G = MyGroup(5)\nMyGroup(5, #undef)\n\njulia> set_attribute!(G, :isfinite, :true)\n\njulia> get_attribute(G, :isfinite)\ntrue\n\nApplying the macro to a typename results in external storage of the attributes:\n\njulia> mutable struct MyOtherGroup\n order::Int\n MyOtherGroup(order::Int) = new(order)\n end\n\njulia> @attributes MyOtherGroup\n\njulia> G = MyOtherGroup(5)\nMyOtherGroup(5)\n\njulia> set_attribute!(G, :isfinite, :true)\n\njulia> get_attribute(G, :isfinite)\ntrue\n\n\n\n\n\n","category":"macro"},{"location":"misc/#AbstractAlgebra.@attr","page":"Miscellaneous","title":"AbstractAlgebra.@attr","text":"@attr [RetType] funcdef\n\nThis macro is applied to the definition of a unary function, and enables caching (\"memoization\") of its return values based on the argument. This assumes the argument supports attribute storing (see @attributes) via get_attribute!.\n\nThe name of the function is used as name for the underlying attribute.\n\nEffectively, this turns code like this:\n\n@attr RetType function myattr(obj::Foo)\n # ... expensive computation\n return result\nend\n\ninto something essentially equivalent to this:\n\nfunction myattr(obj::Foo)\n return get_attribute!(obj, :myattr) do\n # ... expensive computation\n return result\n end::RetType\nend\n\nExamples\n\njulia> @attributes mutable struct Foo\n x::Int\n Foo(x::Int) = new(x)\n end;\n\njulia> @attr Int function myattr(obj::Foo)\n println(\"Performing expensive computation\")\n return factorial(obj.x)\n end;\n\njulia> obj = Foo(5);\n\njulia> myattr(obj)\nPerforming expensive computation\n120\n\njulia> myattr(obj) # second time uses the cached result\n120\n\n\n\n\n\n\n","category":"macro"},{"location":"misc/#AbstractAlgebra.has_attribute","page":"Miscellaneous","title":"AbstractAlgebra.has_attribute","text":"has_attribute(G::Any, attr::Symbol)\n\nReturn a boolean indicating whether G has a value stored for the attribute attr.\n\n\n\n\n\n","category":"function"},{"location":"misc/#AbstractAlgebra.get_attribute","page":"Miscellaneous","title":"AbstractAlgebra.get_attribute","text":"get_attribute(f::Function, G::Any, attr::Symbol)\n\nReturn the value stored for the attribute attr, or if no value has been set, return f().\n\nThis is intended to be called using do block syntax.\n\nget_attribute(obj, attr) do\n # default value calculated here if needed\n ...\nend\n\n\n\n\n\nget_attribute(G::Any, attr::Symbol, default::Any = nothing)\n\nReturn the value stored for the attribute attr, or if no value has been set, return default.\n\n\n\n\n\n","category":"function"},{"location":"misc/#AbstractAlgebra.get_attribute!","page":"Miscellaneous","title":"AbstractAlgebra.get_attribute!","text":"get_attribute!(f::Function, G::Any, attr::Symbol)\n\nReturn the value stored for the attribute attr of G, or if no value has been set, store key => f() and return f().\n\nThis is intended to be called using do block syntax.\n\nget_attribute!(obj, attr) do\n # default value calculated here if needed\n ...\nend\n\n\n\n\n\nget_attribute!(G::Any, attr::Symbol, default::Any)\n\nReturn the value stored for the attribute attr of G, or if no value has been set, store key => default, and return default.\n\n\n\n\n\n","category":"function"},{"location":"misc/#AbstractAlgebra.set_attribute!","page":"Miscellaneous","title":"AbstractAlgebra.set_attribute!","text":"set_attribute!(G::Any, data::Pair{Symbol, <:Any}...)\n\nAttach the given sequence of key=>value pairs as attributes of G.\n\n\n\n\n\nset_attribute!(G::Any, attr::Symbol, value::Any)\n\nAttach the given value as attribute attr of G.\n\n\n\n\n\n","category":"function"},{"location":"misc/#Advanced-printing","page":"Miscellaneous","title":"Advanced printing","text":"","category":"section"},{"location":"misc/#Self-given-names","page":"Miscellaneous","title":"Self-given names","text":"","category":"section"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"We provide macros @show_name, @show_special and @show_special_elem to change the way certain objects are printed.","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"In compact and supercompact printing mode, @show_name tries to determine a suitable name to print instead of the object (see AbstractAlgebra.get_name).","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"@show_special checks if an attribute :show is present. If so, it has to be a function taking IO, optionally a MIME-type, and the object. This is then called instead of the usual show function.","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"Similarly, @show_special_elem checks if an attribute :show_elem is present in the object's parent. The semantics are the same as for @show_special.","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"All are supposed to be used within the usual show function, where @show_special_elem is only relevant for element types of algebraic structures.","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"function show(io::IO, A::MyObj)\n @show_name(io, A)\n @show_special(io, A)\n\n # ... usual stuff\nend\n\nfunction show(io::IO, ::MIME\"text/plain\", A::MyObj)\n @show_name(io, A)\n @show_special(io, MIME\"text/plain\"(), A)\n\n # ... usual stuff\nend","category":"page"},{"location":"misc/#Documentation","page":"Miscellaneous","title":"Documentation","text":"","category":"section"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"AbstractAlgebra.@show_special\nAbstractAlgebra.@show_special_elem\nAbstractAlgebra.@show_name\nAbstractAlgebra.get_name\nAbstractAlgebra.set_name!\nAbstractAlgebra.extra_name\nAbstractAlgebra.find_name","category":"page"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.@show_special","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.@show_special","text":"@show_special(io::IO, obj)\n\nIf the obj has a show attribute, this gets called with io and obj and returns from the current scope. Otherwise, does nothing.\n\nIt is supposed to be used at the start of show methods as shown in the documentation.\n\n\n\n\n\n@show_special(io::IO, mime, obj)\n\nIf the obj has a show attribute, this gets called with io, mime and obj and returns from the current scope. Otherwise, does nothing.\n\nIt is supposed to be used at the start of show methods as shown in the documentation.\n\n\n\n\n\n","category":"macro"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.@show_special_elem","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.@show_special_elem","text":"@show_special_elem(io::IO, obj)\n\nIf the parent of obj has a show_special_elem attribute, this gets called with io and obj and returns from the current scope. Otherwise, does nothing.\n\nIt is supposed to be used at the start of show methods as shown in the documentation.\n\n\n\n\n\n@show_special_elem(io::IO, mime, obj)\n\nIf the parent of obj has a show attribute, this gets called with io, mime and obj and returns from the current scope. Otherwise, does nothing.\n\nIt is supposed to be used at the start of show methods as shown in the documentation.\n\n\n\n\n\n","category":"macro"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.@show_name","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.@show_name","text":"@show_name(io::IO, obj)\n\nIf either property :compact or :supercompact is set to true for io (see IOContext), print the name get_name(obj) of the object obj to the io stream. This macro either prints the name and returns from the current scope, or does nothing.\n\nIt is supposed to be used at the start of show methods as shown in the documentation. ```\n\n\n\n\n\n","category":"macro"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.get_name","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.get_name","text":"get_name(obj) -> Union{String,Nothing}\n\nReturns the name of the object obj if it is set, or nothing otherwise. This function tries to find a name in the following order:\n\nThe name set by AbstractAlgebra.set_name!.\nThe name of a variable in global (Main module) namespace with value bound to the object obj (see AbstractAlgebra.find_name).\nThe name returned by AbstractAlgebra.extra_name.\n\n\n\n\n\n","category":"function"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.set_name!","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.set_name!","text":"set_name!(obj, name::String; override::Bool=true)\n\nSets the name of the object obj to name. This name is used for printing using AbstractAlgebra.@show_name. If override is false, the name is only set if there is no name already set.\n\nThis function errors if obj does not support attribute storage.\n\n\n\n\n\nset_name!(obj; override::Bool=true)\n\nSets the name of the object obj to the name of a variable in global (Main module) namespace with value bound to the object obj, if such a variable exists (see AbstractAlgebra.find_name). This name is used for printing using AbstractAlgebra.@show_name. If override is false, the name is only set if there is no name already set.\n\nThis function errors if obj does not support attribute storage.\n\n\n\n\n\n","category":"function"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.extra_name","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.extra_name","text":"extra_name(obj) -> Union{String,Nothing}\n\nMay be overloaded to provide a fallback name for the object obj in AbstractAlgebra.get_name. The default implementation returns nothing.\n\n\n\n\n\n","category":"function"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.find_name","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.find_name","text":"find_name(obj, M = Main; all::Bool = false) -> Union{String,Nothing}\n\nReturn name of a variable in M's namespace with value bound to the object obj, or nothing if no such variable exists. If all is true, private and non-exported variables are also searched.\n\nnote: Note\nIf the object is stored in several variables, the first one will be used, but a name returned once is kept until the variable no longer contains this object.\n\nFor this to work in doctests, one should call AbstractAlgebra.set_current_module(@__MODULE__) in the value argument of Documenter.DocMeta.setdocmeta! and keep the default value of M = Main here.\n\nwarning: Warning\nThis function should not be used directly, but rather through AbstractAlgebra.get_name.\n\n\n\n\n\n","category":"function"},{"location":"misc/#Indentation-and-Decapitalization","page":"Miscellaneous","title":"Indentation and Decapitalization","text":"","category":"section"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"To facilitate printing of nested mathematical structures, we provide a modified IOCustom object, that supports indentation and decapitalization.","category":"page"},{"location":"misc/#Example","page":"Miscellaneous","title":"Example","text":"","category":"section"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"We illustrate this with an example","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"struct A{T}\n x::T\nend\n\nfunction Base.show(io::IO, a::A)\n io = AbstractAlgebra.pretty(io)\n println(io, \"Something of type A\")\n print(io, AbstractAlgebra.Indent(), \"over \", AbstractAlgebra.Lowercase(), a.x)\n print(io, AbstractAlgebra.Dedent()) # don't forget to undo the indentation!\nend\n\nstruct B\nend\n\nfunction Base.show(io::IO, b::B)\n io = AbstractAlgebra.pretty(io)\n print(io, LowercaseOff(), \"Hilbert thing\")\nend","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"At the REPL, this will then be printed as follows:","category":"page"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"julia> A(2)\nSomething of type A\n over 2\n\njulia> A(A(2))\nSomething of type A\n over something of type A\n over 2\n\njulia> A(B())\nSomething of type A\n over Hilbert thing","category":"page"},{"location":"misc/#Documentation-2","page":"Miscellaneous","title":"Documentation","text":"","category":"section"},{"location":"misc/","page":"Miscellaneous","title":"Miscellaneous","text":"AbstractAlgebra.pretty\nAbstractAlgebra.Indent\nAbstractAlgebra.Dedent\nAbstractAlgebra.Lowercase\nAbstractAlgebra.LowercaseOff","category":"page"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.pretty","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.pretty","text":"pretty(io::IO) -> IOCustom\n\nWrap io into an IOCustom object.\n\nExamples\n\njulia> io = AbstractAlgebra.pretty(stdout);\n\n\n\n\n\n","category":"function"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.Indent","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.Indent","text":"Indent\n\nWhen printed to an IOCustom object, increases the indentation level by one.\n\nExamples\n\njulia> io = AbstractAlgebra.pretty(stdout);\n\njulia> print(io, AbstractAlgebra.Indent(), \"This is indented\")\n This is indented\n\n\n\n\n\n","category":"type"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.Dedent","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.Dedent","text":"Dedent\n\nWhen printed to an IOCustom object, decreases the indentation level by one.\n\nExamples\n\njulia> io = AbstractAlgebra.pretty(stdout);\n\njulia> print(io, AbstractAlgebra.Indent(), AbstractAlgebra.Dedent(), \"This is indented\")\nThis is indented\n\n\n\n\n\n","category":"type"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.Lowercase","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.Lowercase","text":"Lowercase\n\nWhen printed to an IOCustom object, the next letter printed will be lowercase.\n\nExamples\n\njulia> io = AbstractAlgebra.pretty(stdout);\n\njulia> print(io, AbstractAlgebra.Lowercase(), \"Foo\")\nfoo\n\n\n\n\n\n","category":"type"},{"location":"misc/#AbstractAlgebra.PrettyPrinting.LowercaseOff","page":"Miscellaneous","title":"AbstractAlgebra.PrettyPrinting.LowercaseOff","text":"LowercaseOff\n\nWhen printed to an IOCustom object, the case of the next letter will not be changed when printed.\n\nExamples\n\njulia> io = AbstractAlgebra.pretty(stdout);\n\njulia> print(io, AbstractAlgebra.Lowercase(), AbstractAlgebra.LowercaseOff(), \"Foo\")\nFoo\n\n\n\n\n\n","category":"type"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"residue_interface/#Residue-Ring-Interface","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"","category":"section"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"Residue rings (currently a quotient ring modulo a principal ideal) are supported in AbstractAlgebra.jl, at least for Euclidean base rings. There is also partial support for residue rings of polynomial rings where the modulus has invertible leading coefficient.","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"In addition to the standard Ring interface, some additional functions are required to be present for residue rings.","category":"page"},{"location":"residue_interface/#Types-and-parents","page":"Residue Ring Interface","title":"Types and parents","text":"","category":"section"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"AbstractAlgebra provides four abstract types for residue rings and their elements:","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"ResidueRing{T} is the abstract type for residue ring parent types\nResidueField{T} is the abstract type for residue rings known to be fields\nResElem{T} is the abstract type for types of elements of residue rings (residues)\nResFieldElem{T} is the abstract type for types of elements of residue fields","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"We have that ResidueRing{T} <: AbstractAlgebra.Ring and ResElem{T} <: AbstractAlgebra.RingElem.","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"Note that these abstract types are parameterised. The type T should usually be the type of elements of the base ring of the residue ring/field.","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"If the parent object for a residue ring has type MyResRing and residues in that ring have type MyRes then one would have:","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"MyResRing <: ResidueRing{BigInt}\nMyRes <: ResElem{BigInt}","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"Residue rings should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Residue rings should at least be distinguished based on their base ring and modulus (the principal ideal one is taking a quotient of the base ring by).","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).","category":"page"},{"location":"residue_interface/#Required-functionality-for-residue-rings","page":"Residue Ring Interface","title":"Required functionality for residue rings","text":"","category":"section"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"In addition to the required functionality for the Ring interface the Residue Ring interface has the following required functions.","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"We suppose that R is a fictitious base ring, m is an element of that ring, and that S is the residue ring (quotient ring) R(m) with parent object S of type MyResRing{T}. We also assume the residues r pmodm in the residue ring have type MyRes{T}, where T is the type of elements of the base ring.","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"Note that the type T must (transitively) belong to the abstract type RingElem.","category":"page"},{"location":"residue_interface/#Data-type-and-parent-object-methods","page":"Residue Ring Interface","title":"Data type and parent object methods","text":"","category":"section"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"modulus(S::MyResRing{T}) where T <: AbstractAlgebra.RingElem","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"Return the modulus of the given residue ring, i.e. if the residue ring S was specified to be R(m), return m.","category":"page"},{"location":"residue_interface/#Basic-manipulation-of-rings-and-elements","page":"Residue Ring Interface","title":"Basic manipulation of rings and elements","text":"","category":"section"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"data(f::MyRes{T}) where T <: RingElem\nlift(f::MyRes{T}) where T <: RingElem","category":"page"},{"location":"residue_interface/","page":"Residue Ring Interface","title":"Residue Ring Interface","text":"Given a residue r pmodm, represented as such, return r. In the special case where machine integers are used to represent the residue, data will return the machine integer, whereas lift will return a multiprecision integer. Otherwise lift falls back to data by default.","category":"page"},{"location":"interface_introduction/#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"interface_introduction/","page":"Introduction","title":"Introduction","text":"AbstractAlgebra defines a series of interfaces that can be extended with new types that implement those interfaces. For example, if one were implementing a new polynomial ring type, one would implement all of the required functionality described in this chapter for the relevant AbstractAlgebra interfaces. This would include the Ring Interface and the Univariate Polynomial Ring Interface.","category":"page"},{"location":"interface_introduction/","page":"Introduction","title":"Introduction","text":"Once a new type implements all the required functionality, all the corresponding generic functionality would then function automatically for the new type.","category":"page"},{"location":"interface_introduction/","page":"Introduction","title":"Introduction","text":"One may then go on to implement some of the optional functionality for performance if the provided generic functionality is insufficient.","category":"page"},{"location":"interface_introduction/","page":"Introduction","title":"Introduction","text":"AbstractAlgebra tries to provide all generic constructions recursively so that one can have towers of generic constructions. This means that new interfaces should generally only be added if they cooperate with all the existing interfaces, at least so far as the theory exists to do so.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"series/#Power-series","page":"Power series","title":"Power series","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"AbstractAlgebra.jl allows the creation of capped relative and absolute power series over any computable commutative ring R.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Capped relative power series are power series of the form a_jx^j + a_j+1x^j+1 + cdots + a_k-1x^k-1 + O(x^k) where a_j in R and the relative precision k - j is at most equal to some specified precision n.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Capped absolute power series are power series of the form a_jx^j + a_j+1x^j+1 + cdots + a_n-1x^n-1 + O(x^n) where j geq 0, a_j in R and the precision n is fixed.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"There are two implementations of relative series: relative power series, implemented in src/RelSeries.jl for which j 0 in the above description, and Laurent series where j can be negative, implemented in src/Laurent.jl. Note that there are two implementations for Laurent series, one over rings and one over fields, though in practice most of the implementation uses the same code in both cases.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"There is a single implementation of absolute series: absolute power series, implemented in src/AbsSeries.jl.","category":"page"},{"location":"series/#Generic-power-series-types","page":"Power series","title":"Generic power series types","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"AbstractAlgebra.jl provides generic series types implemented in src/generic/AbsSeries.jl, src/generic/RelSeries.jl and src/generic/LaurentSeries.jl which implement the Series interface.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"These generic series have types Generic.RelSeries{T}, Generic.AbsSeries{T}, Generic.LaurentSeriesRingElem{T} and Generic.LaurentSeriesFieldElem{T}. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"The parent objects have types Generic.AbsPowerSeriesRing{T} and Generic.RelPowerSeriesRing{T} and Generic.LaurentSeriesRing{T} respectively.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"The default precision, string representation of the variable and base ring R of a generic power series are stored in its parent object.","category":"page"},{"location":"series/#Abstract-types","page":"Power series","title":"Abstract types","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"Relative power series elements belong to the abstract type RelPowerSeriesRingElem.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Laurent series elements belong directly to either RingElem or FieldElem since it is more useful to be able to distinguish whether they belong to a ring or field than it is to distinguish that they are relative series.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Absolute power series elements belong to AbsPowerSeriesRingElem.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"The parent types for relative and absolute power series, Generic.RelPowerSeriesRing{T} and Generic.AbsPowerSeriesRing{T} respectively, belong to SeriesRing{T}.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"The parent types of Laurent series belong directly to Ring and Field respectively.","category":"page"},{"location":"series/#Series-ring-constructors","page":"Power series","title":"Series ring constructors","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"In order to construct series in AbstractAlgebra.jl, one must first construct the ring itself. This is accomplished with any of the following constructors.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"power_series_ring(R::Ring, prec_max::Int, s::VarName; cached::Bool = true, model=:capped_relative)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"laurent_series_ring(R::Ring, prec_max::Int, s::VarName; cached::Bool = true)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"laurent_series_ring(R::Field, prec_max::Int, s::VarName; cached::Bool = true)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Given a base ring R, a maximum precision (relative or absolute, depending on the model) and a string s specifying how the generator (variable) should be printed, return a tuple S, x representing the series ring and its generator.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"By default, S will depend only on S, x and the maximum precision and will be cached. Setting the optional argument cached to false will prevent this.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"In the case of power series, the optional argument model can be set to either :capped_absolute or capped_relative, depending on which power series model is required.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"It is also possible to construct absolute and relative power series with a default variable. These are lightweight constructors and should be used in generic algorithms wherever possible when creating series rings where the symbol does not matter.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"AbsPowerSeriesRing(R::Ring, prec::Int)\nRelPowerSeriesRing(R::Ring, prec::Int)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Return the absolute or relative power series ring over the given base ring R and with precision cap given by prec. Note that a tuple is not returned, only the power series ring itself, not a generator.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Here are some examples of constructing various kinds of series rings and coercing various elements into those rings.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> R, x = power_series_ring(ZZ, 10, \"x\")\n(Univariate power series ring over integers, x + O(x^11))\n\njulia> S, y = power_series_ring(ZZ, 10, \"y\"; model=:capped_absolute)\n(Univariate power series ring over integers, y + O(y^10))\n\njulia> T, z = laurent_series_ring(ZZ, 10, \"z\")\n(Laurent series ring in z over integers, z + O(z^11))\n\njulia> U, w = laurent_series_field(QQ, 10, \"w\")\n(Laurent series field in w over rationals, w + O(w^11))\n\njulia> f = R()\nO(x^10)\n\njulia> g = S(123)\n123 + O(y^10)\n\njulia> h = U(BigInt(1234))\n1234 + O(w^10)\n\njulia> k = T(z + 1)\n1 + z + O(z^10)\n\njulia> V = AbsPowerSeriesRing(ZZ, 10)\nUnivariate power series ring in x with precision 10\n over integers","category":"page"},{"location":"series/#Power-series-constructors","page":"Power series","title":"Power series constructors","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"Series can be constructed using arithmetic operators using the generator of the series. Also see the big-oh notation below for specifying the precision.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"All of the standard ring constructors can also be used to construct power series.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"(R::SeriesRing)() # constructs zero\n(R::SeriesRing)(c::Integer)\n(R::SeriesRing)(c::elem_type(R))\n(R::SeriesRing{T})(a::T) where T <: RingElement","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"In addition, the following constructors that are specific to power series are provided. They take an array of coefficients, a length, precision and valuation. Coefficients will be coerced into the coefficient ring if they are not already in that ring.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"For relative series we have:","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"(S::SeriesRing{T})(A::Vector{T}, len::Int, prec::Int, val::Int) where T <: RingElem\n(S::SeriesRing{T})(A::Vector{U}, len::Int, prec::Int, val::Int) where {T <: RingElem, U <: RingElem}\n(S::SeriesRing{T})(A::Vector{U}, len::Int, prec::Int, val::Int) where {T <: RingElem, U <: Integer}","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"And for absolute series:","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"(S::SeriesRing{T})(A::Vector{T}, len::Int, prec::Int) where T <: RingElem","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"It is also possible to create series directly without having to create the corresponding series ring.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"abs_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T\nrel_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, val::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T\nlaurent_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, val::Int, scale::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> S, x = power_series_ring(QQ, 10, \"x\"; model=:capped_absolute)\n(Univariate power series ring over rationals, x + O(x^10))\n\njulia> f = S(Rational{BigInt}[0, 2, 3, 1], 4, 6)\n2*x + 3*x^2 + x^3 + O(x^6)\n\njulia> f = abs_series(ZZ, [1, 2, 3], 3, 5, \"y\")\n1 + 2*y + 3*y^2 + O(y^5)\n\njulia> g = rel_series(ZZ, [1, 2, 3], 3, 7, 4)\nx^4 + 2*x^5 + 3*x^6 + O(x^7)\n\njulia> k = abs_series(ZZ, [1, 2, 3], 1, 6, cached=false)\n1 + O(x^6)\n\njulia> p = rel_series(ZZ, BigInt[], 0, 3, 1)\nO(x^3)\n\njulia> q = abs_series(ZZ, [], 0, 6)\nO(x^6)\n\njulia> s = abs_series(ZZ, [1, 2, 3], 3, 5; max_precision=10)\n1 + 2*x + 3*x^2 + O(x^5)\n\njulia> s = laurent_series(ZZ, [1, 2, 3], 3, 5, 0, 2; max_precision=10)\n1 + 2*x^2 + 3*x^4 + O(x^5)","category":"page"},{"location":"series/#Big-oh-notation","page":"Power series","title":"Big-oh notation","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"Series elements can be given a precision using the big-oh notation. This is provided by a function of the following form, (or something equivalent for Laurent series):","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"O(x::SeriesElem)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> R, x = power_series_ring(ZZ, 10, \"x\")\n(Univariate power series ring over integers, x + O(x^11))\n\njulia> S, y = laurent_series_ring(ZZ, 10, \"y\")\n(Laurent series ring in y over integers, y + O(y^11))\n\njulia> f = 1 + 2x + O(x^5)\n1 + 2*x + O(x^5)\n\njulia> g = 2y + 7y^2 + O(y^7)\n2*y + 7*y^2 + O(y^7)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"What is happening here in practice is that O(x^n) is creating the series 0 + O(x^n) and the rules for addition of series dictate that if this is added to a series of greater precision, then the lower of the two precisions must be used.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Of course it may be that the precision of the series that O(x^n) is added to is already lower than n, in which case adding O(x^n) has no effect. This is the case if the default precision is too low, since x on its own has the default precision.","category":"page"},{"location":"series/#Power-series-models","page":"Power series","title":"Power series models","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"Capped relative power series have their maximum relative precision capped at some value prec_max. This means that if the leading term of a nonzero power series element is c_ax^a and the precision is b then the power series is of the form c_ax^a + c_a+1x^a+1 + ldots + O(x^a + b).","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"The zero power series is simply taken to be 0 + O(x^b).","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"The capped relative model has the advantage that power series are stable multiplicatively. In other words, for nonzero power series f and g we have that divexact(f*g), g) == f.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"However, capped relative power series are not additively stable, i.e. we do not always have (f + g) - g = f.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Similar comments apply to Laurent series.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"On the other hand, capped absolute power series have their absolute precision capped. This means that if the leading term of a nonzero power series element is c_ax^a and the precision is b then the power series is of the form c_ax^a + c_a+1x^a+1 + ldots + O(x^b).","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Capped absolute series are additively stable, but not necessarily multiplicatively stable.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"For all models, the maximum precision is also used as a default precision in the case of coercing coefficients into the ring and for any computation where the result could mathematically be given to infinite precision.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"In all models we say that two power series are equal if they agree up to the minimum absolute precision of the two power series.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Thus, for example, x^5 + O(x^10) == 0 + O(x^5), since the minimum absolute precision is 5.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"During computations, it is possible for power series to lose relative precision due to cancellation. For example if f = x^3 + x^5 + O(x^8) and g = x^3 + x^6 + O(x^8) then f - g = x^5 - x^6 + O(x^8) which now has relative precision 3 instead of relative precision 5.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Amongst other things, this means that equality is not transitive. For example x^6 + O(x^11) == 0 + O(x^5) and x^7 + O(x^12) == 0 + O(x^5) but x^6 + O(x^11) neq x^7 + O(x^12).","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Sometimes it is necessary to compare power series not just for arithmetic equality, as above, but to see if they have precisely the same precision and terms. For this purpose we introduce the isequal function.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"For example, if f = x^2 + O(x^7) and g = x^2 + O(x^8) and h = 0 + O(x^2) then f == g, f == h and g == h, but isequal(f, g), isequal(f, h) and isequal(g, h) would all return false. However, if k = x^2 + O(x^7) then isequal(f, k) would return true.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"There are further difficulties if we construct polynomial over power series. For example, consider the polynomial in y over the power series ring in x over the rationals. Normalisation of such polynomials is problematic. For instance, what is the leading coefficient of (0 + O(x^10))y + (1 + O(x^10))?","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"If one takes it to be (0 + O(x^10)) then some functions may not terminate due to the fact that algorithms may require the degree of polynomials to decrease with each iteration. Instead, the degree may remain constant and simply accumulate leading terms which are arithmetically zero but not identically zero.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"On the other hand, when constructing power series over other power series, if we simply throw away terms which are arithmetically equal to zero, our computations may have different output depending on the order in which the power series are added!","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"One should be aware of these difficulties when working with power series. Power series, as represented on a computer, simply don't satisfy the axioms of a ring. They must be used with care in order to approximate operations in a mathematical power series ring.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Simply increasing the precision will not necessarily give a \"more correct\" answer and some computations may not even terminate due to the presence of arithmetic zeroes!","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"An absolute power series ring over a ring R with precision p behaves very much like the quotient Rx(x^p) of the polynomial ring over R. Therefore one can often treat absolute power series rings as though they were rings. However, this depends on all series being given a precision equal to the specified maximum precision and not a lower precision.","category":"page"},{"location":"series/#Functions-for-types-and-parents-of-series-rings","page":"Power series","title":"Functions for types and parents of series rings","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"base_ring(R::SeriesRing)\nbase_ring(a::SeriesElem)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Return the coefficient ring of the given series ring or series.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"parent(a::SeriesElem)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Return the parent of the given series.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"characteristic(R::SeriesRing)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Return the characteristic of the given series ring. If the characteristic is not known, an exception is raised.","category":"page"},{"location":"series/#Series-functions","page":"Power series","title":"Series functions","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"Unless otherwise noted, the functions below are available for all series models, including Laurent series. We denote this by using the abstract type RelPowerSeriesRingElem, even though absolute series and Laurent series types do not belong to this abstract type.","category":"page"},{"location":"series/#Basic-functionality","page":"Power series","title":"Basic functionality","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"Series implement the Ring Interface","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"zero(R::SeriesRing)\none(R::SeriesRing)\niszero(a::SeriesElem)\nisone(a::SeriesElem)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"divexact(a::T, b::T) where T <: SeriesElem\ninv(a::SeriesElem) ","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Series also implement the Series Interface, the most important basic functions being the following.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"var(S::SeriesRing)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Return a symbol for the variable of the given series ring.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"max_precision(S::SeriesRing)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Return the precision cap of the given series ring.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"precision(f::SeriesElem)\nvaluation(f::SeriesElem)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"gen(R::SeriesRing)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"The following functions are also provided for all series.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"coeff(a::SeriesElem, n::Int)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Return the degree n coefficient of the given power series. Note coefficients are numbered from n = 0 for the constant coefficient. If n exceeds the current precision of the power series, the function returns a zero coefficient.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"For power series types, n must be non-negative. Laurent series do not have this restriction.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"modulus{T <: ResElem}(::SeriesElem{T})","category":"page"},{"location":"series/#AbstractAlgebra.modulus-Union{Tuple{SeriesElem{T}}, Tuple{T}} where T<:ResElem","page":"Power series","title":"AbstractAlgebra.modulus","text":"modulus(a::SeriesElem{T}) where {T <: ResElem}\n\nReturn the modulus of the coefficients of the given power series.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"is_gen(::RelPowerSeriesRingElem)","category":"page"},{"location":"series/#AbstractAlgebra.is_gen-Tuple{RelPowerSeriesRingElem}","page":"Power series","title":"AbstractAlgebra.is_gen","text":"is_gen(a::RelPowerSeriesRingElem)\n\nReturn true if the given power series is arithmetically equal to the generator of its power series ring to its current precision, otherwise return false.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> S, x = power_series_ring(ZZ, 10, \"x\")\n(Univariate power series ring over integers, x + O(x^11))\n\njulia> f = 1 + 3x + x^3 + O(x^10)\n1 + 3*x + x^3 + O(x^10)\n\njulia> g = 1 + 2x + x^2 + O(x^10)\n1 + 2*x + x^2 + O(x^10)\n\njulia> h = zero(S)\nO(x^10)\n\njulia> k = one(S)\n1 + O(x^10)\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> n = pol_length(f)\n4\n\njulia> c = polcoeff(f, 3)\n1\n\njulia> U = base_ring(S)\nIntegers\n\njulia> v = var(S)\n:x\n\njulia> max_precision(S) == 10\ntrue\n\njulia> T = parent(x + 1)\nUnivariate power series ring in x with precision 10\n over integers\n\njulia> g == deepcopy(g)\ntrue\n\njulia> t = divexact(2g, 2)\n1 + 2*x + x^2 + O(x^10)\n\njulia> p = precision(f)\n10\n\njulia> R, t = power_series_ring(QQ, 10, \"t\")\n(Univariate power series ring over rationals, t + O(t^11))\n\njulia> S, x = power_series_ring(R, 30, \"x\")\n(Univariate power series ring over univariate power series ring, x + O(x^31))\n\njulia> a = O(x^4)\nO(x^4)\n\njulia> b = (t + 3)*x + (t^2 + 1)*x^2 + O(x^4)\n(3 + t + O(t^10))*x + (1 + t^2 + O(t^10))*x^2 + O(x^4)\n\njulia> k = is_gen(gen(R))\ntrue\n\njulia> m = is_unit(-1 + x + 2x^2)\ntrue\n\njulia> n = valuation(a)\n4\n\njulia> p = valuation(b)\n1\n\njulia> c = coeff(b, 2)\n1 + t^2 + O(t^10)\n\njulia> S, x = power_series_ring(ZZ, 10, \"x\")\n(Univariate power series ring over integers, x + O(x^11))\n\njulia> f = 1 + 3x + x^3 + O(x^5)\n1 + 3*x + x^3 + O(x^5)\n\njulia> g = S(BigInt[1, 2, 0, 1, 0, 0, 0], 4, 10, 3);\n\njulia> set_length!(g, 3)\nx^3 + 2*x^4 + O(x^10)\n\njulia> g = setcoeff!(g, 2, BigInt(11))\nx^3 + 2*x^4 + 11*x^5 + O(x^10)\n\njulia> fit!(g, 8)\n\njulia> g = setcoeff!(g, 7, BigInt(4))\nx^3 + 2*x^4 + 11*x^5 + O(x^10)","category":"page"},{"location":"series/#Change-base-ring","page":"Power series","title":"Change base ring","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"map_coefficients(::Any, ::AbsPowerSeriesRingElem{<:RingElem})\nchange_base_ring(::Ring, ::AbsPowerSeriesRingElem{<:RingElem})","category":"page"},{"location":"series/#AbstractAlgebra.map_coefficients-Tuple{Any, AbsPowerSeriesRingElem{<:RingElem}}","page":"Power series","title":"AbstractAlgebra.map_coefficients","text":"map_coefficients(f, p::SeriesElem{<: RingElement}; cached::Bool=true, parent::PolyRing)\n\nTransform the series p by applying f on each non-zero coefficient.\n\nIf the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"series/#AbstractAlgebra.change_base_ring-Tuple{Ring, AbsPowerSeriesRingElem{<:RingElem}}","page":"Power series","title":"AbstractAlgebra.change_base_ring","text":"change_base_ring(R::Ring, p::SeriesElem{<: RingElement}; parent::PolyRing)\n\nReturn the series obtained by coercing the non-zero coefficients of p into R.\n\nIf the optional parent keyword is provided, the series will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> R, x = power_series_ring(ZZ, 10, \"x\")\n(Univariate power series ring over integers, x + O(x^11))\n\njulia> f = 4*x^6 + x^7 + 9*x^8 + 16*x^9 + 25*x^10 + O(x^11)\n4*x^6 + x^7 + 9*x^8 + 16*x^9 + 25*x^10 + O(x^11)\n\njulia> map_coefficients(AbstractAlgebra.sqrt, f)\n2*x^6 + x^7 + 3*x^8 + 4*x^9 + 5*x^10 + O(x^11)\n\njulia> change_base_ring(QQ, f)\n4*x^6 + x^7 + 9*x^8 + 16*x^9 + 25*x^10 + O(x^11)","category":"page"},{"location":"series/#Shifting","page":"Power series","title":"Shifting","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"shift_left{T <: RingElem}(::RelPowerSeriesRingElem{T}, ::Int)","category":"page"},{"location":"series/#AbstractAlgebra.shift_left-Union{Tuple{T}, Tuple{RelPowerSeriesRingElem{T}, Int64}} where T<:RingElem","page":"Power series","title":"AbstractAlgebra.shift_left","text":"shift_left(x::RelPowerSeriesRingElem{T}, n::Int) where T <: RingElement\n\nReturn the power series x shifted left by n terms, i.e. multiplied by x^n.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"shift_right{T <: RingElem}(::RelPowerSeriesRingElem{T}, ::Int)","category":"page"},{"location":"series/#AbstractAlgebra.shift_right-Union{Tuple{T}, Tuple{RelPowerSeriesRingElem{T}, Int64}} where T<:RingElem","page":"Power series","title":"AbstractAlgebra.shift_right","text":"shift_right(x::RelPowerSeriesRingElem{T}, n::Int) where T <: RingElement\n\nReturn the power series x shifted right by n terms, i.e. divided by x^n.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S, x = power_series_ring(R, 30, \"x\")\n(Univariate power series ring over univariate polynomial ring, x + O(x^31))\n\njulia> a = 2x + x^3\n2*x + x^3 + O(x^31)\n\njulia> b = O(x^4)\nO(x^4)\n\njulia> c = 1 + x + 2x^2 + O(x^5)\n1 + x + 2*x^2 + O(x^5)\n\njulia> d = 2x + x^3 + O(x^4)\n2*x + x^3 + O(x^4)\n\njulia> f = shift_left(a, 2)\n2*x^3 + x^5 + O(x^33)\n\njulia> g = shift_left(b, 2)\nO(x^6)\n\njulia> h = shift_right(c, 1)\n1 + 2*x + O(x^4)\n\njulia> k = shift_right(d, 3)\n1 + O(x^1)\n","category":"page"},{"location":"series/#Truncation","page":"Power series","title":"Truncation","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"truncate{T <: RingElem}(::RelPowerSeriesRingElem{T}, ::Int)","category":"page"},{"location":"series/#Base.truncate-Union{Tuple{T}, Tuple{RelPowerSeriesRingElem{T}, Int64}} where T<:RingElem","page":"Power series","title":"Base.truncate","text":"truncate(a::RelPowerSeriesRingElem{T}, n::Int) where T <: RingElement\n\nReturn a truncated to (absolute) precision n.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S, x = power_series_ring(R, 30, \"x\")\n(Univariate power series ring over univariate polynomial ring, x + O(x^31))\n\njulia> a = 2x + x^3\n2*x + x^3 + O(x^31)\n\njulia> b = O(x^4)\nO(x^4)\n\njulia> c = 1 + x + 2x^2 + O(x^5)\n1 + x + 2*x^2 + O(x^5)\n\njulia> d = 2x + x^3 + O(x^4)\n2*x + x^3 + O(x^4)\n\njulia> f = truncate(a, 3)\n2*x + O(x^3)\n\njulia> g = truncate(b, 2)\nO(x^2)\n\njulia> h = truncate(c, 7)\n1 + x + 2*x^2 + O(x^5)\n\njulia> k = truncate(d, 5)\n2*x + x^3 + O(x^4)\n","category":"page"},{"location":"series/#Division","page":"Power series","title":"Division","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"Base.inv(::RelPowerSeriesRingElem)","category":"page"},{"location":"series/#Base.inv-Tuple{RelPowerSeriesRingElem}","page":"Power series","title":"Base.inv","text":"Base.inv(a::RelPowerSeriesRingElem)\n\nReturn the inverse of the power series a, i.e. 1a.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S, x = power_series_ring(R, 30, \"x\")\n(Univariate power series ring over univariate polynomial ring, x + O(x^31))\n\njulia> a = 1 + x + 2x^2 + O(x^5)\n1 + x + 2*x^2 + O(x^5)\n\njulia> b = S(-1)\n-1 + O(x^30)\n\njulia> c = inv(a)\n1 - x - x^2 + 3*x^3 - x^4 + O(x^5)\n\njulia> d = inv(b)\n-1 + O(x^30)\n","category":"page"},{"location":"series/#Composition","page":"Power series","title":"Composition","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"compose(a::RelPowerSeriesRingElem, b::RelPowerSeriesRingElem)","category":"page"},{"location":"series/#AbstractAlgebra.compose-Tuple{RelPowerSeriesRingElem, RelPowerSeriesRingElem}","page":"Power series","title":"AbstractAlgebra.compose","text":"compose(a::RelPowerSeriesRingElem, b::RelPowerSeriesRingElem)\n\nCompose the series a with the series b and return the result, i.e. return acirc b. The two series do not need to be in the same ring, however the series b must have positive valuation or an exception is raised.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"Note that subst can be used instead of compose, however the provided functionality is the same. General series substitution is not well-defined.","category":"page"},{"location":"series/#Derivative-and-integral","page":"Power series","title":"Derivative and integral","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"derivative(a::RelPowerSeriesRingElem)","category":"page"},{"location":"series/#AbstractAlgebra.derivative-Tuple{RelPowerSeriesRingElem}","page":"Power series","title":"AbstractAlgebra.derivative","text":"derivative(f::AbsPowerSeriesRingElem{T})\n\nReturn the derivative of the power series f.\n\n\n\n\n\nderivative(f::RelPowerSeriesRingElem{T})\n\nReturn the derivative of the power series f.\n\njulia> R, x = power_series_ring(QQ, 10, \"x\")\n(Univariate power series ring in x over Rationals, x + O(x^11))\n\njulia> f = 2 + x + 3x^3\n2 + x + 3*x^3 + O(x^10)\n\njulia> derivative(f)\n1 + 9*x^2 + O(x^9)\n\n\n\n\n\nderivative(f::MPolyRingElem{T}, j::Int) where {T <: RingElement}\n\nReturn the partial derivative of f with respect to j-th variable of the polynomial ring.\n\n\n\n\n\nderivative(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement\n\nReturn the partial derivative of f with respect to x. The value x must be a generator of the polynomial ring of f.\n\n\n\n\n\nderivative(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the derivative of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"integral(a::RelPowerSeriesRingElem)","category":"page"},{"location":"series/#AbstractAlgebra.integral-Tuple{RelPowerSeriesRingElem}","page":"Power series","title":"AbstractAlgebra.integral","text":"integral(f::AbsPowerSeriesRingElem{T})\n\nReturn the integral of the power series f.\n\n\n\n\n\nintegral(f::RelPowerSeriesRingElem{T})\n\nReturn the integral of the power series f.\n\njulia> R, x = power_series_ring(QQ, 10, \"x\")\n(Univariate power series ring in x over Rationals, x + O(x^11))\n\njulia> f = 2 + x + 3x^3\n2 + x + 3*x^3 + O(x^10)\n\njulia> integral(f)\n2*x + 1//2*x^2 + 3//4*x^4 + O(x^11)\n\n\n\n\n\nintegral(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the integral of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"series/#Special-functions","page":"Power series","title":"Special functions","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"Base.log(a::SeriesElem{T}) where T <: FieldElem","category":"page"},{"location":"series/#Base.log-Union{Tuple{SeriesElem{T}}, Tuple{T}} where T<:FieldElem","page":"Power series","title":"Base.log","text":"log(a::SeriesElem{T}) where T <: FieldElement\n\nReturn the logarithm of the power series a.\n\n\n\n\n\nlog(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the logarithm of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"Base.exp(a::RelPowerSeriesRingElem)","category":"page"},{"location":"series/#Base.exp-Tuple{RelPowerSeriesRingElem}","page":"Power series","title":"Base.exp","text":"exp(a::AbsPowerSeriesRingElem)\n\nReturn the exponential of the power series a.\n\n\n\n\n\nexp(a::RelPowerSeriesRingElem)\n\nReturn the exponential of the power series a.\n\n\n\n\n\nexp(a::Generic.LaurentSeriesElem)\n\nReturn the exponential of the power series a.\n\n\n\n\n\nexp(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the exponential of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"Base.sqrt(a::RelPowerSeriesRingElem)","category":"page"},{"location":"series/#Base.sqrt-Tuple{RelPowerSeriesRingElem}","page":"Power series","title":"Base.sqrt","text":"sqrt(a::RelPowerSeriesRingElem)\n\nReturn the square root of the power series a. By default the function raises an exception if the input is not a square. If check=false this check is omitted.\n\n\n\n\n\n","category":"method"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S, x = power_series_ring(R, 30, \"x\")\n(Univariate power series ring over univariate polynomial ring, x + O(x^31))\n\njulia> T, z = power_series_ring(QQ, 30, \"z\")\n(Univariate power series ring over rationals, z + O(z^31))\n\njulia> a = 1 + z + 3z^2 + O(z^5)\n1 + z + 3*z^2 + O(z^5)\n\njulia> b = z + 2z^2 + 5z^3 + O(z^5)\nz + 2*z^2 + 5*z^3 + O(z^5)\n\njulia> c = exp(x + O(x^40))\n1 + x + 1//2*x^2 + 1//6*x^3 + 1//24*x^4 + 1//120*x^5 + 1//720*x^6 + 1//5040*x^7 + 1//40320*x^8 + 1//362880*x^9 + 1//3628800*x^10 + 1//39916800*x^11 + 1//479001600*x^12 + 1//6227020800*x^13 + 1//87178291200*x^14 + 1//1307674368000*x^15 + 1//20922789888000*x^16 + 1//355687428096000*x^17 + 1//6402373705728000*x^18 + 1//121645100408832000*x^19 + 1//2432902008176640000*x^20 + 1//51090942171709440000*x^21 + 1//1124000727777607680000*x^22 + 1//25852016738884976640000*x^23 + 1//620448401733239439360000*x^24 + 1//15511210043330985984000000*x^25 + 1//403291461126605635584000000*x^26 + 1//10888869450418352160768000000*x^27 + 1//304888344611713860501504000000*x^28 + 1//8841761993739701954543616000000*x^29 + 1//265252859812191058636308480000000*x^30 + O(x^31)\n\njulia> d = divexact(x, exp(x + O(x^40)) - 1)\n1 - 1//2*x + 1//12*x^2 - 1//720*x^4 + 1//30240*x^6 - 1//1209600*x^8 + 1//47900160*x^10 - 691//1307674368000*x^12 + 1//74724249600*x^14 - 3617//10670622842880000*x^16 + 43867//5109094217170944000*x^18 - 174611//802857662698291200000*x^20 + 77683//14101100039391805440000*x^22 - 236364091//1693824136731743669452800000*x^24 + 657931//186134520519971831808000000*x^26 - 3392780147//37893265687455865519472640000000*x^28 + O(x^29)\n\njulia> f = exp(b)\n1 + z + 5//2*z^2 + 43//6*z^3 + 193//24*z^4 + O(z^5)\n\njulia> log(exp(b)) == b\ntrue\n\njulia> h = sqrt(a)\n1 + 1//2*z + 11//8*z^2 - 11//16*z^3 - 77//128*z^4 + O(z^5)\n","category":"page"},{"location":"series/#Random-generation","page":"Power series","title":"Random generation","text":"","category":"section"},{"location":"series/","page":"Power series","title":"Power series","text":"Random series can be constructed using the rand function. A range of possible valuations is provided. The maximum precision of the ring is used as a bound on the precision. Other parameters are used to construct random coefficients.","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"rand(R::SeriesRing, val_range::AbstractUnitRange{Int}, v...)","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"Examples","category":"page"},{"location":"series/","page":"Power series","title":"Power series","text":"julia> R, x = power_series_ring(ZZ, 10, \"x\")\n(Univariate power series ring over integers, x + O(x^11))\n\njulia> f = rand(R, 3:5, -10:10)\n3*x^4 - x^5 + 4*x^7 + 4*x^8 - 7*x^9 + 2*x^10 + 4*x^11 - x^12 - 4*x^13 + O(x^14)","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"ideal/#Ideal-functionality","page":"Ideal functionality","title":"Ideal functionality","text":"","category":"section"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"AbstractAlgebra.jl provides a module, implemented in src/generic/Ideal.jl for ideals of a Euclidean domain (assuming the existence of a gcdx function) or of a univariate or multivariate polynomial ring over the integers. Univariate and multivariate polynomial rings over other domains (other than fields) are not supported at this time.","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"info: Info\nA more complete implementation for ideals defined over other rings is provided by Hecke and Oscar.","category":"page"},{"location":"ideal/#Generic-ideal-types","page":"Ideal functionality","title":"Generic ideal types","text":"","category":"section"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"AbstractAlgebra.jl provides a generic ideal type based on Julia arrays which is implemented in src/generic/Ideal.jl.","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"These generic ideals have type Generic.Ideal{T} where T is the type of elements of the ring the ideals belong to. Internally they consist of a Julia array of generators and some additional fields for a parent object, etc. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"Parent objects of ideals have type Generic.IdealSet{T}.","category":"page"},{"location":"ideal/#Abstract-types","page":"Ideal functionality","title":"Abstract types","text":"","category":"section"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"All ideal types belong to the abstract type Ideal{T} and their parents belong to the abstract type Set. This enables one to write generic functions that can accept any AbstractAlgebra ideal type.","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"note: Note\nBoth the generic ideal type Generic.Ideal{T} and the abstract type it belongs to, Ideal{T}, are called Ideal. The former is a (parameterised) concrete type for an ideal in the ring whose elements have type T. The latter is an abstract type representing all ideal types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).","category":"page"},{"location":"ideal/#Ideal-constructors","page":"Ideal functionality","title":"Ideal constructors","text":"","category":"section"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"One may construct ideals in AbstractAlgebra.jl with the following constructor.","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"Generic.Ideal(R::Ring, V::Vector{T}) where T <: RingElement","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"Given a set of elements V in the ring R, construct the ideal of R generated by the elements V. Note that V may be arbitrary, e.g. it can contain duplicates, zero entries or be empty.","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"Examples","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"]; ordering=:degrevlex)\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> V = [3*x^2*y - 3*y^2, 9*x^2*y + 7*x*y]\n2-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:\n 3*x^2*y - 3*y^2\n 9*x^2*y + 7*x*y\n\njulia> I = Generic.Ideal(R, V)\nAbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.MPoly{BigInt}}(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[7*x*y + 9*y^2, 243*y^3 - 147*y^2, x*y^2 + 36*y^3 - 21*y^2, x^2*y + 162*y^3 - 99*y^2])\n\njulia> W = map(ZZ, [2, 5, 7])\n3-element Vector{BigInt}:\n 2\n 5\n 7\n\njulia> J = Generic.Ideal(ZZ, W)\nAbstractAlgebra.Generic.Ideal{BigInt}(Integers, BigInt[1])","category":"page"},{"location":"ideal/#Ideal-functions","page":"Ideal functionality","title":"Ideal functions","text":"","category":"section"},{"location":"ideal/#Basic-functionality","page":"Ideal functionality","title":"Basic functionality","text":"","category":"section"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"gens(::Generic.Ideal{T}) where T <: RingElement","category":"page"},{"location":"ideal/#AbstractAlgebra.gens-Union{Tuple{AbstractAlgebra.Generic.Ideal{T}}, Tuple{T}} where T<:RingElement","page":"Ideal functionality","title":"AbstractAlgebra.gens","text":"gens(I::Ideal{T}) where T <: RingElement\n\nReturn a list of generators of the ideal I in reduced form and canonicalised.\n\n\n\n\n\n","category":"method"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"Examples","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> V = [1 + 2x^2 + 3x^3, 5x^4 + 1, 2x - 1]\n3-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:\n 3*x^3 + 2*x^2 + 1\n 5*x^4 + 1\n 2*x - 1\n\njulia> I = Generic.Ideal(R, V)\nAbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.Poly{BigInt}}(Univariate polynomial ring in x over integers, AbstractAlgebra.Generic.Poly{BigInt}[3, x + 1])\n\njulia> gens(I)\n2-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:\n 3\n x + 1","category":"page"},{"location":"ideal/#Arithmetic-of-Ideals","page":"Ideal functionality","title":"Arithmetic of Ideals","text":"","category":"section"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"Ideals support addition, multiplication, scalar multiplication and equality testing of ideals.","category":"page"},{"location":"ideal/#Containment","page":"Ideal functionality","title":"Containment","text":"","category":"section"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"contains(::Generic.Ideal{T}, ::Generic.Ideal{T}) where T <: RingElement","category":"page"},{"location":"ideal/#Base.contains-Union{Tuple{T}, Tuple{AbstractAlgebra.Generic.Ideal{T}, AbstractAlgebra.Generic.Ideal{T}}} where T<:RingElement","page":"Ideal functionality","title":"Base.contains","text":"Base.contains(I::Ideal{T}, J::Ideal{T}) where T <: RingElement\n\nReturn true if the ideal J is contained in the ideal I.\n\n\n\n\n\n","category":"method"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"intersect(::Generic.Ideal{T}, ::Generic.Ideal{T}) where T <: RingElement","category":"page"},{"location":"ideal/#Base.intersect-Union{Tuple{T}, Tuple{AbstractAlgebra.Generic.Ideal{T}, AbstractAlgebra.Generic.Ideal{T}}} where T<:RingElement","page":"Ideal functionality","title":"Base.intersect","text":"intersect(I::Ideal{T}, J::Ideal{T}) where T <: RingElement\n\nReturn the intersection of the ideals I and J.\n\n\n\n\n\n","category":"method"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"Examples","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> V = [1 + 2x^2 + 3x^3, 5x^4 + 1, 2x - 1]\n3-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:\n 3*x^3 + 2*x^2 + 1\n 5*x^4 + 1\n 2*x - 1\n\njulia> W = [1 + 2x^2 + 3x^3, 5x^4 + 1]\n2-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:\n 3*x^3 + 2*x^2 + 1\n 5*x^4 + 1\n\njulia> I = Generic.Ideal(R, V)\nAbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.Poly{BigInt}}(Univariate polynomial ring in x over integers, AbstractAlgebra.Generic.Poly{BigInt}[3, x + 1])\n\njulia> J = Generic.Ideal(R, W)\nAbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.Poly{BigInt}}(Univariate polynomial ring in x over integers, AbstractAlgebra.Generic.Poly{BigInt}[282, 3*x + 255, x^2 + 107])\n\njulia> contains(J, I)\nfalse\n\njulia> contains(I, J)\ntrue\n\njulia> intersection(I, J) == J\ntrue","category":"page"},{"location":"ideal/#Normal-form","page":"Ideal functionality","title":"Normal form","text":"","category":"section"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"For ideal of polynomial rings it is possible to return the normal form of a polynomial with respect to an ideal.","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"normal_form(::U, ::Generic.Ideal{U}) where {T <: RingElement, U <: Union{PolyRingElem{T}, MPolyRingElem{T}}}","category":"page"},{"location":"ideal/#AbstractAlgebra.Generic.normal_form-Union{Tuple{U}, Tuple{T}, Tuple{U, AbstractAlgebra.Generic.Ideal{U}}} where {T<:RingElement, U<:Union{MPolyRingElem{T}, PolyRingElem{T}}}","page":"Ideal functionality","title":"AbstractAlgebra.Generic.normal_form","text":"normal_form(p::U, I::Ideal{U}) where {T <: RingElement, U <: Union{AbstractAlgebra.PolyRingElem{T}, AbstractAlgebra.MPolyRingElem{T}}}\n\nReturn the normal form of the polynomial p with respect to the ideal I.\n\n\n\n\n\n","category":"method"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"Examples","category":"page"},{"location":"ideal/","page":"Ideal functionality","title":"Ideal functionality","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"]; ordering=:degrevlex)\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> V = [3*x^2*y - 3*y^2, 9*x^2*y + 7*x*y]\n2-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:\n 3*x^2*y - 3*y^2\n 9*x^2*y + 7*x*y\n\njulia> I = Generic.Ideal(R, V)\nAbstractAlgebra.Generic.Ideal{AbstractAlgebra.Generic.MPoly{BigInt}}(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[7*x*y + 9*y^2, 243*y^3 - 147*y^2, x*y^2 + 36*y^3 - 21*y^2, x^2*y + 162*y^3 - 99*y^2])\n\n\njulia> normal_form(30x^5*y + 2x + 1, I)\n135*y^4 + 138*y^3 - 147*y^2 + 2*x + 1","category":"page"},{"location":"field_interface/#Field-Interface","page":"Field Interface","title":"Field Interface","text":"","category":"section"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"AbstractAlgebra.jl generic code makes use of a standardised set of functions which it expects to be implemented for all fields. Here we document this interface. All libraries which want to make use of the generic capabilities of AbstractAlgebra.jl must supply all of the required functionality for their fields.","category":"page"},{"location":"field_interface/#Types","page":"Field Interface","title":"Types","text":"","category":"section"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"Most fields must supply two types:","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"a type for the parent object (representing the field itself)\na type for elements of that field","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"For example, the generic fraction field type in AbstractAlgebra.jl provides two types in generic/GenericTypes.jl: ","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"Generic.FracField{T} for the parent objects\nGeneric.FracFieldElem{T} for the actual fractions","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"The parent type must belong to Field and the element type must belong to FieldElem. Of course, the types may belong to these abstract types transitively.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"For parameterised fields, we advise that the types of both the parent objects and element objects to be parameterised by the types of the elements of the base ring.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"There can be variations on this theme: e.g. in some areas of mathematics there is a notion of a coefficient domain, in which case it may make sense to parameterise all types by the type of elements of this coefficient domain. But note that this may have implications for the ad hoc operators one might like to explicitly implement.","category":"page"},{"location":"field_interface/#FieldElement-type-union","page":"Field Interface","title":"FieldElement type union","text":"","category":"section"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"Because of its lack of multiple inheritance, Julia does not allow Julia Base types to belong to FieldElem. To allow us to work equally with AbstractAlgebra and Julia types that represent elements of fields we define a union type FieldElement in src/julia/JuliaTypes.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"So far, in addition to FieldElem the union type FieldElement includes the Julia types Rational and AbstractFloat.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"Most of the generic code in AbstractAlgebra makes use of the union type FieldElement instead of FieldElem so that the generic functions also accept the Julia Base field types.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"note: Note\nOne must be careful when defining ad hoc binary operations for field element types. It is often necessary to define separate versions of the functions for FieldElem then for each of the Julia types separately in order to avoid ambiguity warnings.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"Note that even though FieldElement is a union type we still have the following inclusion","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"FieldElement <: RingElement","category":"page"},{"location":"field_interface/#Parent-object-caches","page":"Field Interface","title":"Parent object caches","text":"","category":"section"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"In many cases, it is desirable to have only one object in the system to represent each field. This means that if the same field is constructed twice, elements of the two fields will be compatible as far as arithmetic is concerned.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"In order to facilitate this, global caches of fields are stored in AbstractAlgebra.jl, usually implemented using dictionaries. For example, the Generic.FracField parent objects are looked up in a dictionary FracDict to see if they have been previously defined.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"Whether these global caches are provided or not, depends on both mathematical and algorithmic considerations. E.g. in the case of number fields, it isn't desirable to identify all number fields with the same defining polynomial, as they may be considered with distinct embeddings into one another. In other cases, identifying whether two fields are the same may be prohibitively expensive. Generally, it may only make sense algorithmically to identify two fields if they were constructed from identical data.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"If a global cache is provided, it must be optionally possible to construct the parent objects without caching. This is done by passing a boolean value cached to the inner constructor of the parent object. See generic/GenericTypes.jl for examples of how to construct and handle such caches.","category":"page"},{"location":"field_interface/#Required-functions-for-all-fields","page":"Field Interface","title":"Required functions for all fields","text":"","category":"section"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"In the following, we list all the functions that are required to be provided for fields in AbstractAlgebra.jl or by external libraries wanting to use AbstractAlgebra.jl.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"We give this interface for fictitious types MyParent for the type of the field parent object R and MyElem for the type of the elements of the field.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"note: Note\nGeneric functions in AbstractAlgebra.jl may not rely on the existence of functions that are not documented here. If they do, those functions will only be available for fields that implement that additional functionality, and should be documented as such.","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"In the first place, all fields are rings and therefore any field type must implement all of the Ring interface. The functionality below is in addition to this basic functionality.","category":"page"},{"location":"field_interface/#Data-type-and-parent-object-methods","page":"Field Interface","title":"Data type and parent object methods","text":"","category":"section"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"characteristic(R::MyParent)","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"Return the characteristic of the field. If the characteristic is not known, an exception is raised.","category":"page"},{"location":"field_interface/#Basic-manipulation-of-rings-and-elements","page":"Field Interface","title":"Basic manipulation of rings and elements","text":"","category":"section"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"is_unit(f::MyElem)","category":"page"},{"location":"field_interface/","page":"Field Interface","title":"Field Interface","text":"Return true if the given element is invertible, i.e. nonzero in the field.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"mpoly_interface/#Multivariate-Polynomial-Ring-Interface","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Multivariate polynomial rings are supported in AbstractAlgebra.jl, and in addition to the standard Ring interface, numerous additional functions are provided.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Unlike other kinds of rings, even complex operations such as GCD depend heavily on the multivariate representation. Therefore AbstractAlgebra.jl cannot provide much in the way of additional functionality to external multivariate implementations.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"This means that external libraries must be able to implement their multivariate formats in whatever way they see fit. The required interface here should be implemented, even if it is not optimal. But it can be extended, either by implementing one of the optional interfaces, or by extending the required interface in some other way.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Naturally, any multivariate polynomial ring implementation provides the full Ring interface, in order to be treated as a ring for the sake of AbstractAlgebra.jl.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Considerations which make it impossible for AbstractAlgebra.jl to provide generic functionality on top of an arbitrary multivariate module include:","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"orderings (lexical, degree, weighted, block, arbitrary)\nsparse or dense representation\ndistributed or recursive representation\npacked or unpacked exponents\nexponent bounds (and whether adaptive or not)\nrandom access or iterators\nwhether monomials and polynomials have the same type\nwhether special cache aware data structures such as Geobuckets are used","category":"page"},{"location":"mpoly_interface/#Types-and-parents","page":"Multivariate Polynomial Ring Interface","title":"Types and parents","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"AbstractAlgebra.jl provides two abstract types for multivariate polynomial rings and their elements:","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"MPolyRing{T} is the abstract type for multivariate polynomial ring parent types\nMPolyRingElem{T} is the abstract type for multivariate polynomial types","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"We have that MPolyRing{T} <: Ring and MPolyRingElem{T} <: RingElem.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Note that both abstract types are parameterised. The type T should usually be the type of elements of the coefficient ring of the polynomial ring. For example, in the case of mathbbZx y the type T would be the type of an integer, e.g. BigInt.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Multivariate polynomial rings should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Multivariate polynomial rings should at least be distinguished based on their base (coefficient) ring and number of variables. But if they have the same base ring, symbols (for their variables/generators) and ordering, they should certainly have the same parent object.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).","category":"page"},{"location":"mpoly_interface/#Required-functionality-for-multivariate-polynomials","page":"Multivariate Polynomial Ring Interface","title":"Required functionality for multivariate polynomials","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"In addition to the required functionality for the Ring interface, the Multivariate Polynomial interface has the following required functions.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"We suppose that R is a fictitious base ring (coefficient ring) and that S is a multivariate polynomial ring over R (i.e. S = Rx y ldots) with parent object S of type MyMPolyRing{T}. We also assume the polynomials in the ring have type MyMPoly{T}, where T is the type of elements of the base (coefficient) ring.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Note that the type T must (transitively) belong to the abstract type RingElem or more generally the union type RingElement which includes the Julia integer, rational and floating point types.","category":"page"},{"location":"mpoly_interface/#Constructors","page":"Multivariate Polynomial Ring Interface","title":"Constructors","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"To construct a multivariate polynomial ring, there is the following constructor.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"polynomial_ring(R::Ring, s::Vector{Symbol})","category":"page"},{"location":"mpoly_interface/#AbstractAlgebra.polynomial_ring-Tuple{Ring, Vector{Symbol}}-mpoly_interface","page":"Multivariate Polynomial Ring Interface","title":"AbstractAlgebra.polynomial_ring","text":"polynomial_ring(R::Ring, varnames::Vector{Symbol}; cached=true, ordering=:lex)\n\nGiven a coefficient ring R and variable names, say varnames = [:x1, :x2, ...], return a tuple S, [x1, x2, ...] of the polynomial ring S = Rx1 x2 dots and its generators x1 x2 dots.\n\nBy default (cached=true), the output S will be cached, i.e. if polynomial_ring is invoked again with the same arguments, the same (identical) ring is returned. Setting cached to false ensures a distinct new ring is returned, and will also prevent it from being cached.\n\nThe ordering of the polynomial ring can be one of :lex, :deglex or :degrevlex.\n\nSee also: polynomial_ring(::Ring, ::Vararg), @polynomial_ring.\n\nExample\n\njulia> S, generators = polynomial_ring(ZZ, [:x, :y, :z])\n(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y, z])\n\n\n\n\n\n","category":"method"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Polynomials in a given ring can be constructed using the generators and basic polynomial arithmetic. However, this is inefficient and the following build context is provided for building polynomials term-by-term. It assumes the polynomial data type is random access, and so the constructor functions must be reimplemented for all other types of polynomials.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"MPolyBuildCtx(R::MPolyRing)","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return a build context for creating polynomials in the given polynomial ring.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"push_term!(M::MPolyBuildCtx, c::RingElem, v::Vector{Int})","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Add the term with coefficient c and exponent vector v to the polynomial under construction in the build context M.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"finish(M::MPolyBuildCtx)","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Finish construction of the polynomial, sort the terms, remove duplicate and zero terms and return the created polynomial.","category":"page"},{"location":"mpoly_interface/#Data-type-and-parent-object-methods","page":"Multivariate Polynomial Ring Interface","title":"Data type and parent object methods","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"symbols(S::MyMPolyRing{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return an array of Symbols representing the variables (generators) of the polynomial ring. Note that these are Symbols not Strings, though their string values will usually be used when printing polynomials.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"number_of_variables(f::MyMPolyRing{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the number of variables of the polynomial ring.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"gens(S::MyMPolyRing{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return an array of all the generators (variables) of the given polynomial ring (as polynomials).","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"The first entry in the array will be the variable with most significance with respect to the ordering.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"gen(S::MyMPolyRing{T}, i::Int) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the i-th generator (variable) of the given polynomial ring (as a polynomial).","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"ordering(S::MyMPolyRing{T})","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the ordering of the given polynomial ring as a symbol. Supported values currently include :lex, :deglex and :degrevlex.","category":"page"},{"location":"mpoly_interface/#Basic-manipulation-of-rings-and-elements","page":"Multivariate Polynomial Ring Interface","title":"Basic manipulation of rings and elements","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"length(f::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the number of nonzero terms of the given polynomial. The length of the zero polynomial is defined to be 0. The return value should be of type Int.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"degrees(f::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return an array of the degrees of the polynomial f in each of the variables.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"total_degree(f::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the total degree of the polynomial f, i.e. the highest sum of exponents occurring in any term of f.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"is_gen(x::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return true if x is a generator of the polynomial ring.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"coefficients(p::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return an iterator for the coefficients of the polynomial p, starting with the coefficient of the most significant term with respect to the ordering. Generic code will provide this function automatically for random access polynomials that implement the coeff function.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"monomials(p::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return an iterator for the monomials of the polynomial p, starting with the monomial of the most significant term with respect to the ordering. Monomials in AbstractAlgebra are defined to have coefficient 1. See the function terms if you also require the coefficients, however note that only monomials can be compared. Generic code will provide this function automatically for random access polynomials that implement the monomial function.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"terms(p::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return an iterator for the terms of the polynomial p, starting with the most significant term with respect to the ordering. Terms in AbstractAlgebra include the coefficient. Generic code will provide this function automatically for random access polynomials that implement the term function.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"exponent_vectors(a::MyMPoly{T}) where T <: RingElement","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return an iterator for the exponent vectors for each of the terms of the polynomial starting with the most significant term with respect to the ordering. Each exponent vector is an array of Ints, one for each variable, in the order given when the polynomial ring was created. Generic code will provide this function automatically for random access polynomials that implement the exponent_vector function.","category":"page"},{"location":"mpoly_interface/#Exact-division","page":"Multivariate Polynomial Ring Interface","title":"Exact division","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"For any ring that implements exact division, the following can be implemented.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"divexact(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the exact quotient of f by g if it exists, otherwise throw an error.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"divides(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return a tuple (flag, q) where flag is true if g divides f, in which case q will be the exact quotient, or flag is false and q is set to zero.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"remove(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return a tuple (v q) such that the highest power of g that divides f is g^v and the cofactor is q.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"valuation(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return v such that the highest power of g that divides f is g^v.","category":"page"},{"location":"mpoly_interface/#Ad-hoc-exact-division","page":"Multivariate Polynomial Ring Interface","title":"Ad hoc exact division","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"For any ring that implements exact division, the following can be implemented.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"divexact(f::MyMPoly{T}, c::Integer) where T <: RingElem\ndivexact(f::MyMPoly{T}, c::Rational) where T <: RingElem\ndivexact(f::MyMPoly{T}, c::T) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Divide the polynomial exactly by the constant c.","category":"page"},{"location":"mpoly_interface/#Euclidean-division","page":"Multivariate Polynomial Ring Interface","title":"Euclidean division","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Although multivariate polynomial rings are not in general Euclidean, it is possible to define a quotient with remainder function that depends on the polynomial ordering in the case that the quotient ring is a field or a Euclidean domain. In the case that a polynomial g divides a polynomial f, the result no longer depends on the ordering and the remainder is zero, with the quotient agreeing with the exact quotient.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"divrem(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return a tuple (q r) such that f = qg + r, where the coefficients of terms of r whose monomials are divisible by the leading monomial of g are reduced modulo the leading coefficient of g (according to the Euclidean function on the coefficients).","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Note that the result of this function depends on the ordering of the polynomial ring.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"div(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"As per the divrem function, but returning the quotient only. Especially when the quotient happens to be exact, this function can be exceedingly fast.","category":"page"},{"location":"mpoly_interface/#GCD","page":"Multivariate Polynomial Ring Interface","title":"GCD","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"In cases where there is a meaningful Euclidean structure on the coefficient ring, it is possible to compute the GCD of multivariate polynomials.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"gcd(f::MyMPoly{T}, g::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return a greatest common divisor of f and g.","category":"page"},{"location":"mpoly_interface/#Square-root","page":"Multivariate Polynomial Ring Interface","title":"Square root","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Over rings for which an exact square root is available, it is possible to take the square root of a polynomial or test whether it is a square.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"sqrt(f::MyMPoly{T}, check::Bool=true) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the square root of the polynomial f and raise an exception if it is not a square. If check is set to false, the input is assumed to be a perfect square and this assumption is not fully checked. This can be significantly faster.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"is_square(::MyMPoly{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return true if f is a square.","category":"page"},{"location":"mpoly_interface/#Interface-for-sparse-distributed,-random-access-multivariates","page":"Multivariate Polynomial Ring Interface","title":"Interface for sparse distributed, random access multivariates","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"The following additional functions should be implemented by libraries that provide a sparse distributed polynomial format, stored in a representation for which terms can be accessed in constant time (e.g. where arrays are used to store coefficients and exponent vectors).","category":"page"},{"location":"mpoly_interface/#Sparse-distributed,-random-access-constructors","page":"Multivariate Polynomial Ring Interface","title":"Sparse distributed, random access constructors","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"In addition to the standard constructors, the following constructor, taking arrays of coefficients and exponent vectors, should be provided.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"(S::MyMPolyRing{T})(A::Vector{T}, m::Vector{Vector{Int}}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Create the polynomial in the given ring with nonzero coefficients specified by the elements of A and corresponding exponent vectors given by the elements of m.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"There is no assumption about coefficients being nonzero or terms being in order or unique. Zero terms are removed by the function, duplicate terms are combined (added) and the terms are sorted so that they are in the correct order.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Each exponent vector uses a separate integer for each exponent field, the first of which should be the exponent for the most significant variable with respect to the ordering. All exponents must be non-negative.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"A library may also optionally provide an interface that makes use of BigInt (or any other big integer type) for exponents instead of Int.","category":"page"},{"location":"mpoly_interface/#Sparse-distributed,-random-access-basic-manipulation","page":"Multivariate Polynomial Ring Interface","title":"Sparse distributed, random access basic manipulation","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"coeff(f::MyMPoly{T}, n::Int) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the coefficient of the n-th term of f. The first term should be the most significant term with respect to the ordering.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"coeff(a::MyMPoly{T}, exps::Vector{Int}) where T <: RingElement","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the coefficient of the term with the given exponent vector, or zero if there is no such term.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"monomial(f::MyMPoly{T}, n::Int) where T <: RingElem\nmonomial!(m::MyMPoly{T}, f::MyMPoly{T}, n::Int) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the n-th monomial of f or set m to the n-th monomial of f, respectively. The first monomial should be the most significant term with respect to the ordering. Monomials have coefficient 1 in AbstractAlgebra. See the function term if you also require the coefficient, however, note that only monomials can be compared.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"term(f::MyMPoly{T}, n::Int) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the n-th term of f. The first term should be the one whose monomial is most significant with respect to the ordering.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"exponent(f::MyMPoly{T}, i::Int, j::Int) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return the exponent of the j-th variable in the i-th term of the polynomial f. The first term is the one with whose monomial is most significant with respect to the ordering.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"exponent_vector(a::MyMPoly{T}, i::Int) where T <: RingElement","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Return a vector of exponents, corresponding to the exponent vector of the i-th term of the polynomial. Term numbering begins at 1 and the exponents are given in the order of the variables for the ring, as supplied when the ring was created.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"setcoeff!(a::MyMPoly, exps::Vector{Int}, c::S) where S <: RingElement","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Set the coefficient of the term with the given exponent vector to the given value c. If no such term exists (and c neq 0), one will be inserted. This function takes O(log n) operations if a term with the given exponent already exists and c neq 0, or if the term is inserted at the end of the polynomial. Otherwise it can take O(n) operations in the worst case. This function must return the modified polynomial.","category":"page"},{"location":"mpoly_interface/#Unsafe-functions","page":"Multivariate Polynomial Ring Interface","title":"Unsafe functions","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"The following functions must be provided, but are considered unsafe, as they may leave the polynomials in an inconsistent state and they mutate their inputs. As usual, such functions should only be applied on polynomials that have no references elsewhere in the system and are mainly intended to be used in carefully written library code, rather than by users.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Users should instead build polynomials using the constructors described above.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"fit!(f::MyMPoly{T}, n::Int) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Ensure that the polynomial f internally has space for n nonzero terms. This function must mutate the function in-place if it is mutable. It does not return the mutated polynomial. Immutable types can still be supported by defining this function to do nothing.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"setcoeff!(a::MyMPoly{T}, i::Int, c::T) where T <: RingElement\nsetcoeff!(a::MyMPoly{T}, i::Int, c::U) where {T <: RingElement, U <: Integer}","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Set the i-th coefficient of the polynomial a to c. No check is performed on the index i or for c = 0. It may be necessary to call combine_like_terms after calls to this function, to remove zero terms. The function must return the modified polynomial.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"combine_like_terms!(a::MyMPoly{T}) where T <: RingElement","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Remove zero terms and combine any adjacent terms with the same exponent vector (by adding them). It is assumed that all the exponent vectors are already in the correct order with respect to the ordering. The function must return the resulting polynomial.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"set_exponent_vector!(a::MyMPoly{T}, i::Int, exps::Vector{Int}) where T <: RingElement","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Set the i-th exponent vector to the given exponent vector. No check is performed on the index i, which is assumed to be valid (or that the polynomial has enough space allocated). No sorting of exponents is performed by this function. To sort the terms after setting any number of exponents with this function, run the sort_terms! function. The function must return the modified polynomial.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"sort_terms!(a::MyMPoly{T}) where {T <: RingElement}","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Sort the terms of the given polynomial according to the polynomial ring ordering. Zero terms and duplicate exponents are ignored. To deal with those call combine_like_terms. The sorted polynomial must be returned by the function.","category":"page"},{"location":"mpoly_interface/#Optional-functionality-for-multivariate-polynomials","page":"Multivariate Polynomial Ring Interface","title":"Optional functionality for multivariate polynomials","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"The following functions can optionally be implemented for multivariate polynomial types.","category":"page"},{"location":"mpoly_interface/#Reduction-by-an-ideal","page":"Multivariate Polynomial Ring Interface","title":"Reduction by an ideal","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"divrem(f::MyMPoly{T}, G::Vector{MyMPoly{T}}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"As per the divrem function above, except that each term of r starting with the most significant term, is reduced modulo the leading terms of each of the polynomials in the array G for which the leading monomial is a divisor.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"A tuple (Q r) is returned from the function, where Q is an array of polynomials of the same length as G, and such that f = r + sum QiGi.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"The result is again dependent on the ordering in general, but if the polynomials in G are over a field and the reduced generators of a Groebner basis, then the result is unique.","category":"page"},{"location":"mpoly_interface/#Evaluation","page":"Multivariate Polynomial Ring Interface","title":"Evaluation","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"evaluate(a::MyMPoly{T}, A::Vector{T}) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Evaluate the polynomial at the given values in the coefficient ring of the polynomial. The result should be an element of the coefficient ring.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"evaluate(f::MyMPoly{T}, A::Vector{U}) where {T <: RingElem, U <: Integer}","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Evaluate the polynomial f at the values specified by the entries of the array A.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"(a::MyMPoly{T})(vals::Union{NCRingElem, RingElement}...) where T <: RingElement","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Evaluate the polynomial at the given arguments. This provides functional notation for polynomial evaluation, i.e. f(a b c). It must be defined for each supported polynomial type (Julia does not allow functional notation to be defined for an abstract type).","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"The code for this function in MPoly.jl can be used when implementing this as it provides the most general possible evaluation, which is much more general than the case of evaluation at elements of the same ring.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"The evaluation should succeed for any set of values for which a multiplication is defined with the product of a coefficient and all the values before it.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"note: Note\nThe values at which a polynomial is evaluated may be in non-commutative rings. Products are performed in the order of the variables in the polynomial ring that the polynomial belongs to, preceded by a multiplication by the coefficient on the left.","category":"page"},{"location":"mpoly_interface/#Derivations","page":"Multivariate Polynomial Ring Interface","title":"Derivations","text":"","category":"section"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"The following function allows to compute derivations of multivariate polynomials of type MPoly.","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"derivative(f::MyMPoly{T}, j::Int) where T <: RingElem","category":"page"},{"location":"mpoly_interface/","page":"Multivariate Polynomial Ring Interface","title":"Multivariate Polynomial Ring Interface","text":"Compute the derivative of f with respect to the j-th variable of the polynomial ring.","category":"page"},{"location":"euclidean_interface/","page":"Euclidean Ring Interface","title":"Euclidean Ring Interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = :(using AbstractAlgebra)","category":"page"},{"location":"euclidean_interface/#Euclidean-Ring-Interface","page":"Euclidean Ring Interface","title":"Euclidean Ring Interface","text":"","category":"section"},{"location":"euclidean_interface/","page":"Euclidean Ring Interface","title":"Euclidean Ring Interface","text":"If a ring provides a meaningful Euclidean structure such that a useful Euclidean remainder can be computed practically, various additional functionality is provided by AbstractAlgebra.jl for those rings. This functionality depends on the following functions existing. An implementation must provide divrem, and the remaining are optional as generic fallbacks exist.","category":"page"},{"location":"euclidean_interface/","page":"Euclidean Ring Interface","title":"Euclidean Ring Interface","text":"Base.divrem(f::T, g::T) where T <: RingElem\nmod(f::T, g::T) where T <: RingElem\nBase.div(f::T, g::T) where T <: RingElem\nmulmod(f::T, g::T, m::T) where T <: RingElem\npowermod(f::T, e::Int, m::T) where T <: RingElem\ninvmod(f::T, m::T) where T <: RingElem\ndivides(f::T, g::T) where T <: RingElem\nremove(f::T, p::T) where T <: RingElem\nvaluation(f::T, p::T) where T <: RingElem\ngcd(f::T, g::T) where T <: RingElem\ngcd(f::T, g::T, hs::T...) where T <: RingElem\ngcd(fs::AbstractArray{<:T}) where T <: RingElem\nlcm(f::T, g::T) where T <: RingElem\nlcm(f::T, g::T, hs::T...) where T <: RingElem\nlcm(fs::AbstractArray{<:T}) where T <: RingElem\ngcdx(f::T, g::T) where T <: RingElem\ngcdinv(f::T, g::T) where T <: RingElem\ncrt(r1::T, m1::T, r2::T, m2::T; check::Bool=true) where T <: RingElement\ncrt(r::Vector{T}, m::Vector{T}; check::Bool=true) where T <: RingElement\ncrt_with_lcm(r1::T, m1::T, r2::T, m2::T; check::Bool=true) where T <: RingElement\ncrt_with_lcm(r::Vector{T}, m::Vector{T}; check::Bool=true) where T <: RingElement","category":"page"},{"location":"euclidean_interface/#Base.divrem-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.divrem","text":"divrem(f::T, g::T) where T <: RingElem\n\nReturn a pair q, r consisting of the Euclidean quotient and remainder of f by g. A DivideError should be thrown if g is zero.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.mod-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.mod","text":"mod(f::T, g::T) where T <: RingElem\n\nReturn the Euclidean remainder of f by g. A DivideError should be thrown if g is zero.\n\nnote: Note\nFor best compatibility with the internal assumptions made by AbstractAlgebra, the Euclidean remainder function should provide unique representatives for the residue classes; the mod function should satisfymod(a_1, b) = mod(a_2, b) if and only if b divides a_1 - a_2, and\nmod(0, b) = 0.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.div-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.div","text":"div(f::T, g::T) where T <: RingElem\n\nReturn the Euclidean quotient of f by g. A DivideError should be thrown if g is zero.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#AbstractAlgebra.mulmod-Union{Tuple{T}, Tuple{T, T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"AbstractAlgebra.mulmod","text":"mulmod(f::T, g::T, m::T) where T <: RingElem\n\nReturn mod(f*g, m) but possibly computed more efficiently.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.powermod-Union{Tuple{T}, Tuple{T, Int64, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.powermod","text":"powermod(f::T, e::Int, m::T) where T <: RingElem\n\nReturn mod(f^e, m) but possibly computed more efficiently.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.invmod-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.invmod","text":"invmod(f::T, m::T) where T <: RingElem\n\nReturn an inverse of f modulo m, meaning that isone(mod(invmod(f,m)*f,m)) returns true.\n\nIf such an inverse doesn't exist, a NotInvertibleError should be thrown.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#AbstractAlgebra.divides-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"AbstractAlgebra.divides","text":"divides(f::T, g::T) where T <: RingElem\n\nReturn a pair, flag, q, where flag is set to true if g divides f, in which case q is set to the quotient, or flag is set to false and q is set to zero(f).\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#AbstractAlgebra.remove-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"AbstractAlgebra.remove","text":"remove(f::T, p::T) where T <: RingElem\n\nReturn a pair v, q where p^v is the highest power of p dividing f and q is the cofactor after f is divided by this power.\n\nSee also valuation, which only returns the valuation.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#AbstractAlgebra.valuation-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"AbstractAlgebra.valuation","text":"valuation(f::T, p::T) where T <: RingElem\n\nReturn v where p^v is the highest power of p dividing f.\n\nSee also remove.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.gcd-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.gcd","text":"gcd(a::T, b::T) where T <: RingElem\n\nReturn a greatest common divisor of a and b, i.e., an element g which is a common divisor of a and b, and with the property that any other common divisor of a and b divides g.\n\nnote: Note\nFor best compatibility with the internal assumptions made by AbstractAlgebra, the return is expected to be unit-normalized in such a way that if the return is a unit, that unit should be one.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.gcd-Union{Tuple{T}, Tuple{T, T, Vararg{T}}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.gcd","text":"gcd(f::T, g::T, hs::T...) where T <: RingElem\n\nReturn a greatest common divisor of f, g and the elements in hs.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.gcd-Union{Tuple{AbstractArray{<:T}}, Tuple{T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.gcd","text":"gcd(fs::AbstractArray{<:T}) where T <: RingElem\n\nReturn a greatest common divisor of the elements in fs. Requires that fs is not empty.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.lcm-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.lcm","text":"lcm(f::T, g::T) where T <: RingElem\n\nReturn a least common multiple of f and g, i.e., an element d which is a common multiple of f and g, and with the property that any other common multiple of f and g is a multiple of d.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.lcm-Union{Tuple{T}, Tuple{T, T, Vararg{T}}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.lcm","text":"lcm(f::T, g::T, hs::T...) where T <: RingElem\n\nReturn a least common multiple of f, g and the elements in hs.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.lcm-Union{Tuple{AbstractArray{<:T}}, Tuple{T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.lcm","text":"lcm(fs::AbstractArray{<:T}) where T <: RingElem\n\nReturn a least common multiple of the elements in fs. Requires that fs is not empty.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#Base.gcdx-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"Base.gcdx","text":"gcdx(f::T, g::T) where T <: RingElem\n\nReturn a triple d, s, t such that d = gcd(f g) and d = sf + tg, with s loosely reduced modulo gd and t loosely reduced modulo fd.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#AbstractAlgebra.gcdinv-Union{Tuple{T}, Tuple{T, T}} where T<:RingElem","page":"Euclidean Ring Interface","title":"AbstractAlgebra.gcdinv","text":"gcdinv(f::T, g::T) where T <: RingElem\n\nReturn a tuple d, s such that d = gcd(f g) and s = (fd)^-1 pmodgd. Note that d = 1 iff f is invertible modulo g, in which case s = f^-1 pmodg.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#AbstractAlgebra.crt-Union{Tuple{T}, NTuple{4, T}} where T<:RingElement","page":"Euclidean Ring Interface","title":"AbstractAlgebra.crt","text":"crt(r1::T, m1::T, r2::T, m2::T; check::Bool=true) where T <: RingElement\n\nReturn an element congruent to r_1 modulo m_1 and r_2 modulo m_2. If check = true and no solution exists, an error is thrown.\n\nIf T is a fixed precision integer type (like Int), the result will be correct if abs(ri) <= abs(mi) and abs(m1 * m2) < typemax(T).\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#AbstractAlgebra.crt-Union{Tuple{T}, Tuple{Vector{T}, Vector{T}}} where T<:RingElement","page":"Euclidean Ring Interface","title":"AbstractAlgebra.crt","text":"crt(r::Vector{T}, m::Vector{T}; check::Bool=true) where T <: RingElement\n\nReturn an element congruent to r_i modulo m_i for each i.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#AbstractAlgebra.crt_with_lcm-Union{Tuple{T}, NTuple{4, T}} where T<:RingElement","page":"Euclidean Ring Interface","title":"AbstractAlgebra.crt_with_lcm","text":"crt_with_lcm(r1::T, m1::T, r2::T, m2::T; check::Bool=true) where T <: RingElement\n\nReturn a tuple consisting of an element congruent to r_1 modulo m_1 and r_2 modulo m_2 and the least common multiple of m_1 and m_2. If check = true and no solution exists, an error is thrown.\n\n\n\n\n\n","category":"method"},{"location":"euclidean_interface/#AbstractAlgebra.crt_with_lcm-Union{Tuple{T}, Tuple{Vector{T}, Vector{T}}} where T<:RingElement","page":"Euclidean Ring Interface","title":"AbstractAlgebra.crt_with_lcm","text":"crt_with_lcm(r::Vector{T}, m::Vector{T}; check::Bool=true) where T <: RingElement\n\nReturn a tuple consisting of an element congruent to r_i modulo m_i for each i and the least common multiple of the m_i.\n\n\n\n\n\n","category":"method"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"quotient_module/#Quotient-modules","page":"Quotient modules","title":"Quotient modules","text":"","category":"section"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"AbstractAlgebra allows the construction of quotient modules/spaces of AbstractAlgebra modules over euclidean domains. These are given as the quotient of a module by a submodule of that module.","category":"page"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"We define two quotient modules to be equal if they are quotients of the same module M by two equal submodules.","category":"page"},{"location":"quotient_module/#Generic-quotient-module-type","page":"Quotient modules","title":"Generic quotient module type","text":"","category":"section"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"AbstractAlgebra implements the generic quotient module type Generic.QuotientModule{T} where T is the element type of the base ring, in src/generic/QuotientModule.jl.","category":"page"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"Elements of generic quotient modules have type Generic.QuotientModuleElem{T}.","category":"page"},{"location":"quotient_module/#Abstract-types","page":"Quotient modules","title":"Abstract types","text":"","category":"section"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"Quotient module types belong to the FPModule{T} abstract type and their elements to FPModuleElem{T}.","category":"page"},{"location":"quotient_module/#Constructors","page":"Quotient modules","title":"Constructors","text":"","category":"section"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"quo(M::FPModule{T}, v::Generic.Submodule{T}) where T <: RingElement","category":"page"},{"location":"quotient_module/#AbstractAlgebra.quo-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, AbstractAlgebra.Generic.Submodule{T}}} where T<:RingElement","page":"Quotient modules","title":"AbstractAlgebra.quo","text":"quo(m::FPModule{T}, subm::FPModule{T}) where T <: RingElement\n\nReturn the quotient M of the module m by the module subm (which must have been (transitively) constructed as a submodule of m or be m itself) along with the canonical quotient map from m to M.\n\n\n\n\n\n","category":"method"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"Note that a preimage of the canonical projection can be obtained using the preimage function described in the section on module homomorphisms. Note that a preimage element of the canonical projection is not unique and has no special properties.","category":"page"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"Examples","category":"page"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"julia> M = FreeModule(ZZ, 2)\nFree module of rank 2 over integers\n\njulia> m = M([ZZ(1), ZZ(2)])\n(1, 2)\n\njulia> N, f = sub(M, [m])\n(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 2 over integers)\n\njulia> Q, g = quo(M, N)\n(Quotient module over Integers with 1 generator and no relations, Hom: free module of rank 2 over integers -> quotient module over Integers with 1 generator and no relations)\n\njulia> p = M([ZZ(3), ZZ(1)])\n(3, 1)\n\njulia> v2 = g(p)\n(-5)\n\njulia> V = VectorSpace(QQ, 2)\nVector space of dimension 2 over rationals\n\njulia> m = V([QQ(1), QQ(2)])\n(1//1, 2//1)\n\njulia> N, f = sub(V, [m])\n(Subspace over Rationals with 1 generator and no relations, Hom: subspace over Rationals with 1 generator and no relations -> vector space of dimension 2 over rationals)\n\njulia> Q, g = quo(V, N)\n(Quotient space over:\nRationals with 1 generator and no relations, Hom: vector space of dimension 2 over rationals -> quotient space over:\nRationals with 1 generator and no relations)\n","category":"page"},{"location":"quotient_module/#Functionality-for-submodules","page":"Quotient modules","title":"Functionality for submodules","text":"","category":"section"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"In addition to the Module interface, AbstractAlgebra submodules implement the following functionality.","category":"page"},{"location":"quotient_module/#Basic-manipulation","page":"Quotient modules","title":"Basic manipulation","text":"","category":"section"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"supermodule(M::Generic.QuotientModule{T}) where T <: RingElement\n\ndim(N::Generic.QuotientModule{T}) where T <: FieldElement","category":"page"},{"location":"quotient_module/#AbstractAlgebra.Generic.supermodule-Union{Tuple{AbstractAlgebra.Generic.QuotientModule{T}}, Tuple{T}} where T<:RingElement","page":"Quotient modules","title":"AbstractAlgebra.Generic.supermodule","text":"supermodule(M::QuotientModule{T}) where T <: RingElement\n\nReturn the module that this module is a quotient of.\n\n\n\n\n\n","category":"method"},{"location":"quotient_module/#AbstractAlgebra.Generic.dim-Union{Tuple{AbstractAlgebra.Generic.QuotientModule{T}}, Tuple{T}} where T<:FieldElement","page":"Quotient modules","title":"AbstractAlgebra.Generic.dim","text":"dim(N::QuotientModule{T}) where T <: FieldElement\n\nReturn the dimension of the given vector quotient space.\n\n\n\n\n\n","category":"method"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"Examples","category":"page"},{"location":"quotient_module/","page":"Quotient modules","title":"Quotient modules","text":"julia> M = FreeModule(ZZ, 2)\nFree module of rank 2 over integers\n\njulia> m = M([ZZ(2), ZZ(3)])\n(2, 3)\n\njulia> N, g = sub(M, [m])\n(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 2 over integers)\n\njulia> Q, h = quo(M, N)\n(Quotient module over Integers with 2 generators and relations:\n[2 3], Hom: free module of rank 2 over integers -> quotient module over Integers with 2 generators and relations:\n[2 3])\n\njulia> supermodule(Q) == M\ntrue\n\njulia> V = VectorSpace(QQ, 2)\nVector space of dimension 2 over rationals\n\njulia> m = V([QQ(1), QQ(2)])\n(1//1, 2//1)\n\njulia> N, f = sub(V, [m])\n(Subspace over Rationals with 1 generator and no relations, Hom: subspace over Rationals with 1 generator and no relations -> vector space of dimension 2 over rationals)\n\njulia> Q, g = quo(V, N)\n(Quotient space over:\nRationals with 1 generator and no relations, Hom: vector space of dimension 2 over rationals -> quotient space over:\nRationals with 1 generator and no relations)\n\njulia> dim(V)\n2\n\njulia> dim(Q)\n1\n","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"free_module/#Free-Modules-and-Vector-Spaces","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"","category":"section"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"AbstractAlgebra allows the construction of free modules of any rank over any Euclidean ring and the vector space of any dimension over a field. By default the system considers the free module of a given rank over a given ring or vector space of given dimension over a field to be unique.","category":"page"},{"location":"free_module/#Generic-free-module-and-vector-space-types","page":"Free Modules and Vector Spaces","title":"Generic free module and vector space types","text":"","category":"section"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"AbstractAlgebra provides generic types for free modules and vector spaces, via the type FreeModule{T} for free modules, where T is the type of the elements of the ring R over which the module is built.","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"Elements of a free module have type FreeModuleElem{T}.","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"Vector spaces are simply free modules over a field.","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"The implementation of generic free modules can be found in src/generic/FreeModule.jl.","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"The free module of a given rank over a given ring is made unique on the system by caching them (unless an optional cache parameter is set to false).","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).","category":"page"},{"location":"free_module/#Abstract-types","page":"Free Modules and Vector Spaces","title":"Abstract types","text":"","category":"section"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"The type FreeModule{T} belongs to FPModule{T} and FreeModuleElem{T} to FPModuleElem{T}. Here the FP prefix stands for finitely presented.","category":"page"},{"location":"free_module/#Functionality-for-free-modules","page":"Free Modules and Vector Spaces","title":"Functionality for free modules","text":"","category":"section"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"As well as implementing the entire module interface, free modules provide the following functionality.","category":"page"},{"location":"free_module/#Constructors","page":"Free Modules and Vector Spaces","title":"Constructors","text":"","category":"section"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"FreeModule(R::Ring, rank::Int)\nVectorSpace(F::Field, dim::Int)","category":"page"},{"location":"free_module/#AbstractAlgebra.FreeModule-Tuple{Ring, Int64}","page":"Free Modules and Vector Spaces","title":"AbstractAlgebra.FreeModule","text":"FreeModule(R::NCRing, rank::Int; cached::Bool = true)\n\nReturn the free module over the ring R with the given rank.\n\n\n\n\n\n","category":"method"},{"location":"free_module/#AbstractAlgebra.VectorSpace-Tuple{Field, Int64}","page":"Free Modules and Vector Spaces","title":"AbstractAlgebra.VectorSpace","text":"VectorSpace(R::Field, dim::Int; cached::Bool = true)\n\nReturn the vector space over the field R with the given dimension.\n\n\n\n\n\n","category":"method"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"Construct the free module/vector space of given rank/dimension.","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"Examples","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"julia> M = FreeModule(ZZ, 3)\nFree module of rank 3 over integers\n\njulia> V = VectorSpace(QQ, 2)\nVector space of dimension 2 over rationals\n","category":"page"},{"location":"free_module/#Basic-manipulation","page":"Free Modules and Vector Spaces","title":"Basic manipulation","text":"","category":"section"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"rank(M::Generic.FreeModule{T}) where T <: RingElem\ndim(V::Generic.FreeModule{T}) where T <: FieldElem\nbasis(V::Generic.FreeModule{T}) where T <: FieldElem","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"Examples","category":"page"},{"location":"free_module/","page":"Free Modules and Vector Spaces","title":"Free Modules and Vector Spaces","text":"julia> M = FreeModule(ZZ, 3)\nFree module of rank 3 over integers\n\njulia> V = VectorSpace(QQ, 2)\nVector space of dimension 2 over rationals\n\njulia> rank(M)\n3\n\njulia> dim(V)\n2\n\njulia> basis(V)\n2-element Vector{AbstractAlgebra.Generic.FreeModuleElem{Rational{BigInt}}}:\n (1//1, 0//1)\n (0//1, 1//1)","category":"page"},{"location":"constructors/#Constructing-mathematical-objects-in-AbstractAlgebra.jl","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"","category":"section"},{"location":"constructors/#Constructing-objects-in-Julia","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing objects in Julia","text":"","category":"section"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"In Julia, one constructs objects of a given type by calling a type constructor. This is simply a function with the same name as the type itself. For example, to construct a BigInt object from an Int in Julia, we simply call the BigInt constructor:","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"n = BigInt(123)","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"Note that a number literal too big to fit in an Int or Int128 automatically creates a BigInt:","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"julia> typeof(12345678765456787654567890987654567898765678909876567890)\nBigInt","category":"page"},{"location":"constructors/#How-we-construct-objects-in-AbstractAlgebra.jl","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"How we construct objects in AbstractAlgebra.jl","text":"","category":"section"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"As we explain in Elements and parents, Julia types don't contain enough information to properly model groups, rings, fields, etc. Instead of using types to construct objects, we use special objects that we refer to as parent objects. They behave a lot like Julia types.","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"Consider the following simple example, to create a multiprecision integer:","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"n = ZZ(12345678765456787654567890987654567898765678909876567890)","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"Here ZZ is not a Julia type, but a callable object. However, for most purposes one can think of such a parent object as though it were a type.","category":"page"},{"location":"constructors/#Constructing-parent-objects","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing parent objects","text":"","category":"section"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"For more complicated groups, rings, fields, etc., one first needs to construct the parent object before one can use it to construct element objects.","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"AbstractAlgebra.jl provides a set of functions for constructing such parent objects. For example, to create a parent object for univariate polynomials over the integers, we use the polynomial_ring parent object constructor.","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"R, x = polynomial_ring(ZZ, :x)\nf = x^3 + 3x + 1\ng = R(12)","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"In this example, R is the parent object and we use it to convert the Int value 12 to an element of the polynomial ring mathbbZx.","category":"page"},{"location":"constructors/#List-of-parent-object-constructors","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"List of parent object constructors","text":"","category":"section"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"For convenience, we provide a list of all the parent object constructors in AbstractAlgebra.jl and explain what mathematical domains they represent.","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"Mathematics AbstractAlgebra.jl constructor\nR = mathbbZ R = ZZ\nR = mathbbQ R = QQ\nR = mathbbF_p R = GF(p)\nR = mathbbZnmathbbZ R, = residue_ring(ZZ, n)\nS = Rx S, x = polynomial_ring(R, :x)\nS = Rx y S, (x, y) = polynomial_ring(R, [:x, :y])\nS = Rlangle x yrangle S, (x, y) = free_associative_algebra(R, [:x, :y])\nS = K(x) S, x = rational_function_field(K, :x)\nS = K(x y) S, (x, y) = rational_function_field(K, [:x, :y])\nS = Rx (to precision n) S, x = power_series_ring(R, n, :x)\nS = Rx y (to precision n) S, (x, y) = power_series_ring(R, n, [:x, :y])\nS = R((x)) (to precision n) S, x = laurent_series_ring(R, n, :x)\nS = K((x)) (to precision n) S, x = laurent_series_field(K, n, :x)\nS = R((x y)) (to precision n) S, (x, y) = laurent_polynomial_ring(R, n, [:x, :y])\nPuiseux series ring to precision n S, x = puiseux_series_ring(R, n, :x)\nPuiseux series field to precision n S, x = puiseux_series_field(R, n, :x)\nS = K(x)(y)(f) S, y = function_field(f, :y) with fin K(x)t\nS = mathrmFrac_R S = fraction_field(R)\nS = R(f) S, = residue_ring(R, f)\nS = R(f) (with (f) maximal) S, = residue_field(R, f)\nS = mathrmMat_mtimes n(R) S = matrix_space(R, m, n)","category":"page"},{"location":"constructors/#Parent-objects-with-variable-names","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Parent objects with variable names","text":"","category":"section"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"The multivariate parent object constructors (polynomial_ring, power_series_ring, free_associative_algebra, laurent_polynomial_ring, and rational_function_field) share a common interface for specifying the variable names, which is provided by @varnames_interface.","category":"page"},{"location":"constructors/","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"Constructing mathematical objects in AbstractAlgebra.jl","text":"AbstractAlgebra.@varnames_interface\nAbstractAlgebra.variable_names\nAbstractAlgebra.reshape_to_varnames","category":"page"},{"location":"constructors/#AbstractAlgebra.@varnames_interface","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"AbstractAlgebra.@varnames_interface","text":"@varnames_interface [M.]f(args..., varnames) macros=:yes n=n range=1:n\n\nAdd methods X, vars = f(args..., varnames...) and macro X = @f(args..., varnames...) to current scope.\n\nCreated methods\n\nX, gens::Vector{T} = f(args..., varnames::Vector{Symbol})\n\nBase method, called by everything else defined below. If a module M is specified, this is implemented as a call to M.f. Otherwise, a method f with this signature must already exist.\n\n\n\nX, gens... = f(args..., varnames...; kv...)\nX, gens... = f(args..., varnames::Tuple; kv...)\n\nCompute X and gens via the base method. Then reshape gens into the shape defined by varnames according to variable_names.\n\nThe vararg varnames... method needs at least one argument to avoid confusion. Moreover a single VarName argument will be dispatched to use a univariate method of f if it exists (e.g. polynomial_ring(R, :x)). If you need those cases, use the Tuple method.\n\nKeyword arguments are passed on to the base method.\n\n\n\nX, x::Vector{T} = f(args..., n::Int, s::VarName = :x; kv...)\n\nShorthand for X, x = f(args..., \"$s#\" => 1:n; kv...). The name of the argument n can be changed via the n option. The range 1:n is given via the range option.\n\nSetting n=:no disables creation of this method.\n\n\n\nX = @f(args..., varnames...; kv...)\nX = @f(args..., varnames::Tuple; kv...)\nX = @f(args..., varname::VarName; kv...)\n\nThese macros behave like their f(args..., varnames; kv...) counterparts but also introduce the indexed varnames into the current scope. The first version needs at least one varnames argument. The third version calls the univariate method base method if it exists (e.g. polynomial_ring(R, varname)).\n\nSetting macros=:no disables macro creation.\n\nwarning: Warning\nTurning varnames into a vector of symbols happens by evaluating variable_names(varnames) in the global scope of the current module. For interactive usage in the REPL this is fine, but in general you have no access to local variables and should not use any side effects in varnames.\n\nExamples\n\njulia> f(a, s::Vector{Symbol}) = a, String.(s)\nf (generic function with 1 method)\n\njulia> AbstractAlgebra.@varnames_interface f(a, s)\n@f (macro with 1 method)\n\njulia> f\nf (generic function with 5 methods)\n\njulia> f(\"hello\", [:x, :y, :z])\n(\"hello\", [\"x\", \"y\", \"z\"])\n\njulia> f(\"hello\", :x => (1:1, 1:2), :y => 1:2, [:z])\n(\"hello\", [\"x[1, 1]\" \"x[1, 2]\"], [\"y[1]\", \"y[2]\"], [\"z\"])\n\njulia> f(\"projective\", [\"x$i$j\" for i in 0:1, j in 0:1], [:y0, :y1], [:z])\n(\"projective\", [\"x00\" \"x01\"; \"x10\" \"x11\"], [\"y0\", \"y1\"], [\"z\"])\n\njulia> f(\"fun inputs\", 'a':'g', Symbol.('x':'z', [0 1]))\n(\"fun inputs\", [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\"], [\"x0\" \"x1\"; \"y0\" \"y1\"; \"z0\" \"z1\"])\n\njulia> @f(\"hello\", \"x#\" => (1:1, 1:2), \"y#\" => (1:2), [:z])\n\"hello\"\n\njulia> (x11, x12, y1, y2, z)\n(\"x11\", \"x12\", \"y1\", \"y2\", \"z\")\n\n\n\n\n\n","category":"macro"},{"location":"constructors/#AbstractAlgebra.variable_names","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"AbstractAlgebra.variable_names","text":"variable_names(a...) -> Vector{Symbol}\nvariable_names(a::Tuple) -> Vector{Symbol}\n\nCreate a vector of variable names from a variable name specification.\n\nEach argument can be either an Array of VarNames, or of the form s::VarName => iter, or of the form s::VarName => (iter...). Here iter is supposed to be any iterable, typically a range like 1:5. The :s => iter specification is shorthand for [\"s[$i]\" for i in iter]. Similarly :s => (iter1, iter2) is shorthand for [\"s[$i,$j]\" for i in iter1, j in iter2], and likewise for three and more iterables.\n\nAs an alternative \"s#\" => iter is shorthand for [\"s$i\" for i in iter]. This also works for multiple iterators in that\"s#\" => (iter1, iter2) is shorthand for [\"s$i$j\" for i in iter1, j in iter2].\n\nExamples\n\njulia> AbstractAlgebra.variable_names([:x, :y])\n2-element Vector{Symbol}:\n :x\n :y\n\njulia> AbstractAlgebra.variable_names(:x => (0:0, 0:1), :y => 0:1, [:z])\n5-element Vector{Symbol}:\n Symbol(\"x[0, 0]\")\n Symbol(\"x[0, 1]\")\n Symbol(\"y[0]\")\n Symbol(\"y[1]\")\n :z\n\njulia> AbstractAlgebra.variable_names(\"x#\" => (0:0, 0:1), \"y#\" => 0:1)\n4-element Vector{Symbol}:\n :x00\n :x01\n :y0\n :y1\n\njulia> AbstractAlgebra.variable_names(\"x#\" => 9:11)\n3-element Vector{Symbol}:\n :x9\n :x10\n :x11\n\njulia> AbstractAlgebra.variable_names([\"x$i$i\" for i in 1:3])\n3-element Vector{Symbol}:\n :x11\n :x22\n :x33\n\njulia> AbstractAlgebra.variable_names('a':'c', ['z'])\n4-element Vector{Symbol}:\n :a\n :b\n :c\n :z\n\n\n\n\n\n","category":"function"},{"location":"constructors/#AbstractAlgebra.reshape_to_varnames","page":"Constructing mathematical objects in AbstractAlgebra.jl","title":"AbstractAlgebra.reshape_to_varnames","text":"reshape_to_varnames(vec::Vector{T}, varnames...) :: Tuple{Array{<:Any, T}}\nreshape_to_varnames(vec::Vector{T}, varnames::Tuple) :: Tuple{Array{<:Any, T}}\n\nTurn vec into the shape of varnames. Reverse flattening from variable_names.\n\nExamples\n\njulia> s = ([:a, :b], \"x#\" => (1:1, 1:2), \"y#\" => 1:2, [:z]);\n\njulia> AbstractAlgebra.reshape_to_varnames(AbstractAlgebra.variable_names(s...), s...)\n([:a, :b], [:x11 :x12], [:y1, :y2], [:z])\n\njulia> R, v = polynomial_ring(ZZ, AbstractAlgebra.variable_names(s...))\n(Multivariate polynomial ring in 7 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[a, b, x11, x12, y1, y2, z])\n\njulia> (a, b), x, y, z = AbstractAlgebra.reshape_to_varnames(v, s...)\n(AbstractAlgebra.Generic.MPoly{BigInt}[a, b], AbstractAlgebra.Generic.MPoly{BigInt}[x11 x12], AbstractAlgebra.Generic.MPoly{BigInt}[y1, y2], AbstractAlgebra.Generic.MPoly{BigInt}[z])\n\njulia> R, (a, b), x, y, z = polynomial_ring(ZZ, s...)\n(Multivariate polynomial ring in 7 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[a, b], AbstractAlgebra.Generic.MPoly{BigInt}[x11 x12], AbstractAlgebra.Generic.MPoly{BigInt}[y1, y2], AbstractAlgebra.Generic.MPoly{BigInt}[z])\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/#Extending-the-interface-of-AbstractAlgebra.jl","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"","category":"section"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"In this section we will discuss on how to extend the interface of AbstractAlgebra.jl.","category":"page"},{"location":"extending_abstractalgebra/#Elements-and-parents","page":"Extending the interface of AbstractAlgebra.jl","title":"Elements and parents","text":"","category":"section"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"Any implementation with elements and parents should implement the following interface:","category":"page"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"parent\nelem_type\nparent_type","category":"page"},{"location":"extending_abstractalgebra/#Base.parent","page":"Extending the interface of AbstractAlgebra.jl","title":"Base.parent","text":"parent(a)\n\nReturn parent object of given element a.\n\nExamples\n\njulia> G = SymmetricGroup(5); g = Perm([3,4,5,2,1])\n(1,3,5)(2,4)\n\njulia> parent(g) == G\ntrue\n\njulia> S, x = laurent_series_ring(ZZ, 3, \"x\")\n(Laurent series ring in x over integers, x + O(x^4))\n\njulia> parent(x) == S\ntrue\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/#AbstractAlgebra.elem_type","page":"Extending the interface of AbstractAlgebra.jl","title":"AbstractAlgebra.elem_type","text":"elem_type(parent)\nelem_type(parent_type)\n\nGiven a parent object (or its type), return the type of its elements.\n\nExamples\n\njulia> S, x = power_series_ring(QQ, 2, \"x\")\n(Univariate power series ring over rationals, x + O(x^3))\n\njulia> elem_type(S) == typeof(x)\ntrue\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/#AbstractAlgebra.parent_type","page":"Extending the interface of AbstractAlgebra.jl","title":"AbstractAlgebra.parent_type","text":"parent_type(element)\nparent_type(element_type)\n\nGiven an element (or its type), return the type of its parent object.\n\nExamples\n\njulia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S = matrix_space(R, 2, 2)\nMatrix space of 2 rows and 2 columns\n over univariate polynomial ring in x over integers\n\njulia> a = rand(S, 0:1, 0:1);\n\njulia> parent_type(a) == typeof(S)\ntrue\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/#Acquiring-associated-elements-and-parents","page":"Extending the interface of AbstractAlgebra.jl","title":"Acquiring associated elements and parents","text":"","category":"section"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"Further, if one has a base ring, like polynomials over the integers mathbbZx, then one should implement","category":"page"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"base_ring","category":"page"},{"location":"extending_abstractalgebra/#AbstractAlgebra.base_ring","page":"Extending the interface of AbstractAlgebra.jl","title":"AbstractAlgebra.base_ring","text":"base_ring(a)\n\nReturn base ring R of given element or parent a.\n\nExamples\n\njulia> S, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> base_ring(S) == QQ\ntrue\n\njulia> R = GF(7)\nFinite field F_7\n\njulia> base_ring(R)\nUnion{}\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/#Special-elements","page":"Extending the interface of AbstractAlgebra.jl","title":"Special elements","text":"","category":"section"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"For rings, one has to extend the following methods:","category":"page"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"one\nzero","category":"page"},{"location":"extending_abstractalgebra/#Base.one","page":"Extending the interface of AbstractAlgebra.jl","title":"Base.one","text":"one(a)\n\nReturn the multiplicative identity in the algebraic structure of a, which can be either an element or parent.\n\nExamples\n\njulia> S = matrix_space(ZZ, 2, 2)\nMatrix space of 2 rows and 2 columns\n over integers\n\njulia> one(S)\n[1 0]\n[0 1]\n\njulia> R, x = puiseux_series_field(QQ, 4, \"x\")\n(Puiseux series field in x over rationals, x + O(x^5))\n\njulia> one(x)\n1 + O(x^4)\n\njulia> G = GF(5)\nFinite field F_5\n\njulia> one(G)\n1\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/#Base.zero","page":"Extending the interface of AbstractAlgebra.jl","title":"Base.zero","text":"zero(a)\n\nReturn the additive identity in the algebraic structure of a, which can be either an element or parent.\n\nExamples\n\njulia> S = matrix_ring(QQ, 2)\nMatrix ring of degree 2\n over rationals\n\njulia> zero(S)\n[0//1 0//1]\n[0//1 0//1]\n\njulia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> zero(x^3 + 2)\n0\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"Groups should only extend at least one of these. The one that is required depends on if the group is additive (commutative) or multiplicative.","category":"page"},{"location":"extending_abstractalgebra/#Basic-manipulation","page":"Extending the interface of AbstractAlgebra.jl","title":"Basic manipulation","text":"","category":"section"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"If one would like to implement a ring, these are the basic manipulation methods that all rings should extend:","category":"page"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"isone\niszero\nis_unit","category":"page"},{"location":"extending_abstractalgebra/#Base.isone","page":"Extending the interface of AbstractAlgebra.jl","title":"Base.isone","text":"isone(a)\n\nReturn true if a is the multiplicative identity, else return false.\n\nExamples\n\njulia> S = matrix_space(ZZ, 2, 2); T = matrix_space(ZZ, 2, 3); U = matrix_space(ZZ, 3, 2);\n\njulia> isone(S([1 0; 0 1]))\ntrue\n\njulia> isone(T([1 0 0; 0 1 0]))\nfalse\n\njulia> isone(U([1 0; 0 1; 0 0]))\nfalse\n\njulia> T, x = puiseux_series_field(QQ, 10, \"x\")\n(Puiseux series field in x over rationals, x + O(x^11))\n\njulia> isone(x), isone(T(1))\n(false, true)\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/#Base.iszero","page":"Extending the interface of AbstractAlgebra.jl","title":"Base.iszero","text":"iszero(a)\n\nReturn true if a is the additative identity, else return false.\n\nExamples\n\njulia> T, x = puiseux_series_field(QQ, 10, \"x\")\n(Puiseux series field in x over rationals, x + O(x^11))\n\njulia> a = T(0)\nO(x^10)\n\njulia> iszero(a)\ntrue\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/#AbstractAlgebra.is_unit","page":"Extending the interface of AbstractAlgebra.jl","title":"AbstractAlgebra.is_unit","text":"is_unit(a::T) where {T <: NCRingElem}\n\nReturn true if a is invertible, else return false.\n\nExamples\n\njulia> S, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> is_unit(x), is_unit(S(1)), is_unit(S(4))\n(false, true, true)\n\njulia> is_unit(ZZ(-1)), is_unit(ZZ(4))\n(true, false)\n\n\n\n\n\n","category":"function"},{"location":"extending_abstractalgebra/","page":"Extending the interface of AbstractAlgebra.jl","title":"Extending the interface of AbstractAlgebra.jl","text":"With the same logic as earlier, groups only need to extend one of the methods isone and iszero.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"module_interface/#Module-Interface","page":"Module Interface","title":"Module Interface","text":"","category":"section"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"note: Note\nThe module infrastructure in AbstractAlgebra should be considered experimental at this stage. This means that the interface may change in the future.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"AbstractAlgebra allows the construction of finitely presented modules (i.e. with finitely many generators and relations), starting from free modules. The generic code provided by AbstractAlgebra will only work for modules over euclidean domains, however there is nothing preventing a library from implementing more general modules using the same interface.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"All finitely presented module types in AbstractAlgebra follow the following interface which is a loose interface of functions, without much generic infrastructure built on top.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Free modules can be built over both commutative and noncommutative rings. Other types of module are restricted to fields and euclidean rings.","category":"page"},{"location":"module_interface/#Abstract-types","page":"Module Interface","title":"Abstract types","text":"","category":"section"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"AbstractAlgebra provides two abstract types for finitely presented modules and their elements:","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"FPModule{T} is the abstract type for finitely presented module parent","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"types","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"FPModuleElem{T} is the abstract type for finitely presented module","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"element types","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Note that the abstract types are parameterised. The type T should usually be the type of elements of the ring the module is over.","category":"page"},{"location":"module_interface/#Required-functionality-for-modules","page":"Module Interface","title":"Required functionality for modules","text":"","category":"section"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"We suppose that R is a fictitious base ring and that S is a module over R with parent object S of type MyModule{T}. We also assume the elements in the module have type MyModuleElem{T}, where T is the type of elements of the ring the module is over.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Note that the type T must (transitively) belong to the abstract type RingElement or NCRingElem.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"We describe the functionality below for modules over commutative rings, i.e. with element type belonging to RingElement, however similar constructors should be available for element types belonging to NCRingElem instead, for free modules over a noncommutative ring.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Although not part of the module interface, implementations of modules that wish to follow our interface should use the same function names for submodules, quotient modules, direct sums and module homomorphisms if they wish to remain compatible with our module generics in the future.","category":"page"},{"location":"module_interface/#Basic-manipulation","page":"Module Interface","title":"Basic manipulation","text":"","category":"section"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"iszero(m::MyModuleElem{T}) where T <: RingElement","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Return true if the given module element is zero.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"number_of_generators(M::MyModule{T}) where T <: RingElement","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Return the number of generators of the module M in its current representation.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"gen(M::MyModule{T}, i::Int) where T <: RingElement","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Return the i-th generator (indexed from 1) of the module M.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"gens(M::MyModule{T}) where T <: RingElement","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Return a Julia array of the generators of the module M.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"rels(M::MyModule{T}) where T <: RingElement","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Return a Julia vector of all the relations between the generators of M. Each relation is given as an AbstractAlgebra row matrix.","category":"page"},{"location":"module_interface/#Element-constructors","page":"Module Interface","title":"Element constructors","text":"","category":"section"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"We can construct elements of a module M by specifying linear combinations of the generators of M. This is done by passing a vector of ring elements.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"(M::Module{T})(v::Vector{T}) where T <: RingElement","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Construct the element of the module M corresponding to sum_i givi where gi are the generators of the module M. The resulting element will lie in the module M.","category":"page"},{"location":"module_interface/#Coercions","page":"Module Interface","title":"Coercions","text":"","category":"section"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Given a module M and an element n of a module N, it is possible to coerce n into M using the notation M(n) in certain circumstances.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"In particular the element n will be automatically coerced along any canonical injection of a submodule map and along any canonical projection of a quotient map. There must be a path from N to M along such maps.","category":"page"},{"location":"module_interface/#Arithmetic-operators","page":"Module Interface","title":"Arithmetic operators","text":"","category":"section"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"Elements of a module can be added, subtracted or multiplied by an element of the ring the module is defined over and compared for equality.","category":"page"},{"location":"module_interface/","page":"Module Interface","title":"Module Interface","text":"In the case of a noncommutative ring, both left and right scalar multiplication are defined.","category":"page"},{"location":"ncring_interface/#Noncommutative-ring-Interface","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"","category":"section"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"AbstractAlgebra.jl supports commutative rings through its Ring interface. In this section we describe the corresponding interface for noncommutative rings. The two interfaces are very similar in terms of required functionality, and so we mainly document the differences here.","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"Noncommutative rings can be supported through the abstract types NCRing and NCRingElem. Note that we have Ring <: NCRing, etc., so the interface here should more correctly be called the Not-necessarily-Commutative-ring interface.","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"However, the fact remains that if one wishes to implement a noncommutative ring, one should make its type belong to NCRing but not to Ring. Therefore it is not too much of a mistake to think of the NCRing interface as being for noncommutative rings.","category":"page"},{"location":"ncring_interface/#Types","page":"Noncommutative ring Interface","title":"Types","text":"","category":"section"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"As for the Ring interface, most noncommutative rings must supply two types:","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"a type for the parent object (representing the ring itself)\na type for elements of that ring","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"The parent type must belong to NCRing and the element type must belong to NCRingElem. Of course, the types may belong to these abstract types transitively via an intermediate abstract type.","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"Also as for the Ring interface, it is advised to make the types of generic parameterised rings that belong to NCRing and NCRingElem depend on the type of the elements of that parameter ring.","category":"page"},{"location":"ncring_interface/#NCRingElement-type-union","page":"Noncommutative ring Interface","title":"NCRingElement type union","text":"","category":"section"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"As for the Ring interface, the NCRing interface provides a union type NCRingElement in src/julia/JuliaTypes.jl which is a union of NCRingElem and the Julia types Integer, Rational and AbstractFloat.","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"Most of the generic code in AbstractAlgebra for general rings makes use of the union type NCRingElement instead of NCRingElem so that the generic functions also accept the Julia Base ring types.","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"As per usual, one may need to implement one ad hoc binary operation for each concrete type belonging to NCRingElement to avoid ambiguity warnings.","category":"page"},{"location":"ncring_interface/#Parent-object-caches","page":"Noncommutative ring Interface","title":"Parent object caches","text":"","category":"section"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"Parent object caches for the NCRing interface operate as per the Ring interface.","category":"page"},{"location":"ncring_interface/#Required-functions-for-all-rings","page":"Noncommutative ring Interface","title":"Required functions for all rings","text":"","category":"section"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"Generic functions may only rely on required functionality for the NCRing interface, which must be implemented by all noncommutative rings.","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"Most of this required functionality is the same as for the Ring interface, so we refer the reader there for details, with the following modifications.","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"We give this interface for fictitious types MyParent for the type of the ring parent object R and MyElem for the type of the elements of the ring.","category":"page"},{"location":"ncring_interface/#Exact-division","page":"Noncommutative ring Interface","title":"Exact division","text":"","category":"section"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"divexact_left(f::MyElem, g::MyElem)\ndivexact_right(f::MyElem, g::MyElem)","category":"page"},{"location":"ncring_interface/","page":"Noncommutative ring Interface","title":"Noncommutative ring Interface","text":"If f = ga for some a in the ring, the function divexact_left(f, g) returns a. If f = ag then divexact_right(f, g) returns a. A DivideError() should be thrown if division is by zero. If no exact quotient exists or an impossible inverse is unavoidably encountered, an error should be thrown.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"map_with_inverse/#Map-with-inverse","page":"Map with inverse","title":"Map with inverse","text":"","category":"section"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"It is not possible to provide generic functionality to invert a map. However, sometimes one knows an inverse map explicitly and would like to keep track of this.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"Recall that as map composition is not commutative, there is a notion of a left inverse and a right inverse for maps.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"To keep track of such inverse maps, AbstractAlgebra provides data types Generic.MapWithRetraction and Generic.MapWithSection.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"Given a map f X to Y, a retraction of f is a map g Y to X such that g(f(x)) = x for all x in X.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"Given a map f X to Y, a section of f is a map g Y to X such that f(g(x)) = x for all y in Y.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"In AbstractAlgebra, a map with retraction/section is an object containing a pair of maps, the second of which is a retraction/section of the first.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"Maps with retraction/section can be composed, and we also define the inverse of such a pair to be the map with the pair swapped. Thus the inverse of a map with retraction is a map with section.","category":"page"},{"location":"map_with_inverse/#Map-with-inverse-constructors","page":"Map with inverse","title":"Map with inverse constructors","text":"","category":"section"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"To construct a map with retraction/section from a pair of maps, we have the following functions:","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"map_with_retraction(m::Map{D, C}, r::Map{C, D}) where {D, C}\nmap_with_section(m::Map{D, C}, s::Map{C, D}) where {D, C}","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"Construct the map with retraction/section given a known retraction/section r or s respectively, of m.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"For convenience we allow construction of maps with retraction/section from a pair of Julia functions/closures.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"map_with_retraction_from_func(f::Function, r::Function, R, S)\nmap_with_section_from_func(f::Function, s::Function, R, S)","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"Construct the map with retraction/section such that the map is given by the function f and the retraction/section is given by the function r or s respectively. Here R is the parent object representing the domain and S is the parent object representing the codomain of f.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"Examples","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"julia> f = map_with_retraction_from_func(x -> x + 1, x -> x - 1, ZZ, ZZ)\nMap with retraction\n from integers\n to integers\n\njulia> a = f(ZZ(1))\n2","category":"page"},{"location":"map_with_inverse/#Functionality-for-maps-with-inverses","page":"Map with inverse","title":"Functionality for maps with inverses","text":"","category":"section"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"The following functionality is provided for maps with inverses.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"inv(M::Generic.MapWithRetraction)\ninv(M::Generic.MapWithSection)","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"Return the map with the two maps contained in M swapped. In the first case, a MapWithSection is returned. In the second case a MapWithRetraction is returned.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"To access the two maps stored in a map with retraction/section, we have the following:","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"image_map(M::Generic.MapWithRetraction)\nimage_map(M::Generic.MapWithSection)\nretraction_map(M::Generic.MapWithRetraction)\nsection_map(M::Generic.MapWithSection)","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"The first two of these functions return the first map in a map with retraction/section, the second two functions return the corresponding second maps.","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"Examples","category":"page"},{"location":"map_with_inverse/","page":"Map with inverse","title":"Map with inverse","text":"julia> f = map_with_retraction_from_func(x -> x + 1, x -> x - 1, ZZ, ZZ)\nMap with retraction\n from integers\n to integers\n\njulia> g = inv(f)\nMap with section\n from integers\n to integers\n\njulia> h = f*g\nComposite map\n from integers\n to integers\nwhich is the composite of\n Map: integers -> integers\n Map: integers -> integers\n\njulia> a = h(ZZ(1))\n1\n","category":"page"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"finfield/#Finite-fields","page":"Finite fields","title":"Finite fields","text":"","category":"section"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"AbstractAlgebra.jl provides a module, implemented in src/julia/GF.jl for finite fields. The module is a naive implementation that supports only fields of degree 1 (prime fields). They are modelled as mathbbZpmathbbZ for p a prime.","category":"page"},{"location":"finfield/#Types-and-parent-objects","page":"Finite fields","title":"Types and parent objects","text":"","category":"section"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"Finite fields have type GFField{T} where T is either Int or BigInt.","category":"page"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"Elements of such a finite field have type GFElem{T}.","category":"page"},{"location":"finfield/#Finite-field-constructors","page":"Finite fields","title":"Finite field constructors","text":"","category":"section"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"In order to construct finite fields in AbstractAlgebra.jl, one must first construct the field itself. This is accomplished with the following constructors.","category":"page"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"GF(p::T) where T <: Integer","category":"page"},{"location":"finfield/#AbstractAlgebra.GF-Tuple{T} where T<:Integer","page":"Finite fields","title":"AbstractAlgebra.GF","text":"GF(p::T; check::Bool=true) where T <: Integer\n\nReturn the finite field mathbbF_p, where p is a prime. By default, the integer p is checked with a probabilistic algorithm for primality. When check == false, no check is made, but the behaviour of the resulting object is undefined if p is composite.\n\n\n\n\n\n","category":"method"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"Here are some examples of creating a finite field and making use of the resulting parent object to coerce various elements into the field.","category":"page"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"Examples","category":"page"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"julia> F = GF(13)\nFinite field F_13\n\njulia> g = F(3)\n3\n\njulia> h = F(g)\n3\n\njulia> GF(4)\nERROR: DomainError with 4:\nCharacteristic is not prime in GF(p)\nStacktrace:\n[...]","category":"page"},{"location":"finfield/#Basic-field-functionality","page":"Finite fields","title":"Basic field functionality","text":"","category":"section"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"The finite field module in AbstractAlgebra.jl implements the full Field interface.","category":"page"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"We give some examples of such functionality.","category":"page"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"Examples","category":"page"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"julia> F = GF(13)\nFinite field F_13\n\njulia> f = F(7)\n7\n\njulia> h = zero(F)\n0\n\njulia> k = one(F)\n1\n\njulia> isone(k)\ntrue\n\njulia> iszero(h)\ntrue\n\njulia> T = parent(h)\nFinite field F_13\n\njulia> h == deepcopy(h)\ntrue\n\njulia> h = h + 2\n2\n\njulia> m = inv(k)\n1\n","category":"page"},{"location":"finfield/#Basic-manipulation-of-fields-and-elements","page":"Finite fields","title":"Basic manipulation of fields and elements","text":"","category":"section"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"data(::GFElem)\nlift(::GFElem)","category":"page"},{"location":"finfield/#AbstractAlgebra.data-Tuple{AbstractAlgebra.GFElem}","page":"Finite fields","title":"AbstractAlgebra.data","text":"data(R::GFElem)\n\nReturn the internal data used to represent the finite field element. This coincides with lift except where the internal data ids a machine integer.\n\n\n\n\n\n","category":"method"},{"location":"finfield/#AbstractAlgebra.lift-Tuple{AbstractAlgebra.GFElem}","page":"Finite fields","title":"AbstractAlgebra.lift","text":"lift(R::GFElem)\n\nLift the finite field element to the integers. The result will be a multiprecision integer regardless of how the field element is represented internally.\n\n\n\n\n\n","category":"method"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"gen{T <: Integer}(F::GFField{T})","category":"page"},{"location":"finfield/#AbstractAlgebra.gen-Union{Tuple{AbstractAlgebra.GFField{T}}, Tuple{T}} where T<:Integer","page":"Finite fields","title":"AbstractAlgebra.gen","text":"gen(R::GFField{T}) where T <: Integer\n\nReturn a generator of the field. Currently this returns 1.\n\n\n\n\n\n","category":"method"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"order(F::GFField)","category":"page"},{"location":"finfield/#AbstractAlgebra.order-Tuple{AbstractAlgebra.GFField}","page":"Finite fields","title":"AbstractAlgebra.order","text":"order(R::GFField)\n\nReturn the order, i.e. the number of element in the given finite field.\n\n\n\n\n\n","category":"method"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"degree(F::GFField)","category":"page"},{"location":"finfield/#AbstractAlgebra.degree-Tuple{AbstractAlgebra.GFField}","page":"Finite fields","title":"AbstractAlgebra.degree","text":"degree(R::GFField)\n\nReturn the degree of the given finite field.\n\n\n\n\n\n","category":"method"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"Examples","category":"page"},{"location":"finfield/","page":"Finite fields","title":"Finite fields","text":"julia> F = GF(13)\nFinite field F_13\n\njulia> d = degree(F)\n1\n\njulia> n = order(F)\n13\n\njulia> g = gen(F)\n1\n","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"functional_map/#Functional-maps","page":"Functional maps","title":"Functional maps","text":"","category":"section"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"A functional map in AbstractAlgebra is a map which can be applied by evaluating a Julia function or closure. It is represented by a map object that contains such a function/closure, usually in a field called image_fn.","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"All functional maps belong to the map class FunctionalMap.","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"A generic concrete type Generic.FunctionalMap is provided by the Generic module to implement a generic functional map type. This allows for functional maps that contain no extra data, other than a Julia function/closure.","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"Custom map types can also be defined which have map class FunctionalMap.","category":"page"},{"location":"functional_map/#Functional-map-interface","page":"Functional maps","title":"Functional map interface","text":"","category":"section"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"All functional map types must define their supertypes as in the following example:","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"mutable struct MyFunctionalMap{D, C} <: Map{D, C, FunctionalMap, MyFunctionalMap}\n # some fields\n image_fn::Function\nend","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"Of course MyFunctionalMap need not be parameterised if the types D and C of the domain and codomain objects are known.","category":"page"},{"location":"functional_map/#Required-functions-for-functional-maps","page":"Functional maps","title":"Required functions for functional maps","text":"","category":"section"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"The following functions must be defined for all functional map types or classes:","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"image_fn(M::Map(MyFunctionalMap))","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"Return the Julia function or closure that corresponds to application of the map M. This function only needs to be provided if this function is not stored in an image_fn field of the MyFunctionalMap type.","category":"page"},{"location":"functional_map/#Generic-functional-maps","page":"Functional maps","title":"Generic functional maps","text":"","category":"section"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"The Generic module provides a concrete type FunctionalMap which merely keeps track of a Julia function/closure implementing the map.","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"Such maps can be constructed using the following function:","category":"page"},{"location":"functional_map/","page":"Functional maps","title":"Functional maps","text":"map_from_func(f::Function, R, S)","category":"page"},{"location":"functional_map/#AbstractAlgebra.map_from_func-Tuple{Function, Any, Any}","page":"Functional maps","title":"AbstractAlgebra.map_from_func","text":"map_from_func(image_fn::Function, domain, codomain)\n\nConstruct the generic functional map with domain and codomain given by the parent objects R and S corresponding to the Julia function f.\n\nExamples\n\njulia> f = map_from_func(x -> x + 1, ZZ, ZZ)\nMap defined by a Julia function\n from integers\n to integers\n\njulia> f(ZZ(2))\n3\n\n\n\n\n\n","category":"method"},{"location":"matrix_introduction/#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"matrix_introduction/","page":"Introduction","title":"Introduction","text":"AbstractAlgebra provides matrix spaces (mxn matrices) and matrix algebras (nxn matrices) over a ring. Whilst both types of matrix provide matrix multiplication for matrices whose dimensions are compatible for multiplication, only the latter kind of matrices form rings in the system.","category":"page"},{"location":"matrix_introduction/","page":"Introduction","title":"Introduction","text":"Matrix spaces provide a large number of linear algebra operations, including linear solving, elementary row operations, various canonical forms. The system also provides characteristic and minimal polynomial computations, LU decomposition, determinant, matrix inverse, kernel computations.","category":"page"},{"location":"matrix_introduction/","page":"Introduction","title":"Introduction","text":"There is also code for computation of the Hermite and Smith normal forms over Euclidean domains and Popov form for matrices over polynomial rings over a field.","category":"page"},{"location":"matrix_introduction/","page":"Introduction","title":"Introduction","text":"Most of this generic functionality is provided for arbitrary matrix types that satisfy the AbstractAlgebra matrix interface.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"matrix_algebras/#Generic-matrix-algebras","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"","category":"section"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"AbstractAlgebra.jl allows the creation of an algebra (ring) of mtimes m matrices over a computable, commutative ring.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Functions specific to generic matrix algebras of mtimes m matrices are implemented in src/generic/MatRing.jl. The remaining functionality is in the file src/generic/Matrix.jl.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"As well as implementing the entire Matrix interface, including the optional functionality, there are many additional generic algorithms implemented for matrix algebras.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Almost all of the functionality specified for generic matrices is available for matrix algebras. The exceptions are functions such as solve and nullspace which may return non-square matrices, or which don't accept square matrices.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"All of the generic functionality is part of the Generic submodule of AbstractAlgebra.jl. This is exported by default, so it is not necessary to qualify names of functions.","category":"page"},{"location":"matrix_algebras/#Types-and-parent-objects","page":"Generic matrix algebras","title":"Types and parent objects","text":"","category":"section"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Generic matrices in AbstractAlgebra.jl have type Generic.MatRingElem{T} for matrices in a matrix algebra, where T is the type of elements of the matrix. Internally, generic matrices are implemented using an object wrapping a Julia two dimensional array, though they are not themselves Julia arrays. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Parents of generic matrices in a matrix algebra have type Generic.MatRing{T}.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Note that matrix algebras are noncommutative rings. Thus their types belong to NCRing and NCRingElem. They cannot be used in constructions which require a commutative ring (Ring and RingElem respectively).","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"The generic matrix algebra matrix types belong to the abstract type MatRingElem{T} and the parent types belong to MatRing{T} Note that both of these require disambiguation from the concrete types in Generic of the same name.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"The degree and base ring R of a generic matrix are stored in its parent object, however to allow creation of matrices without first creating the matrix space parent, generic matrices in Julia do not contain a reference to their parent. They contain the row and column numbers (or degree, in the case of matrix algebras) and the base ring on a per matrix basis. The parent object can then be reconstructed from this data on demand.","category":"page"},{"location":"matrix_algebras/#Matrix-algebra-constructors","page":"Generic matrix algebras","title":"Matrix algebra constructors","text":"","category":"section"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"A matrix algebra in AbstractAlgebra.jl represents a collection of all matrices with given degree and base ring.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"In order to construct matrices in AbstractAlgebra.jl, one must construct the matrix algebra itself. This is accomplished with the following constructor.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"matrix_ring(R::Ring, degree::Int)","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Construct the algebra of matrices with the given degree over the given base ring.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Here are some examples of creating matrix algebras and making use of the resulting parent objects to coerce various elements into the matrix algebra.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Examples","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"julia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_ring(R, 3)\nMatrix ring of degree 3\n over univariate polynomial ring in t over rationals\n\njulia> A = S()\n[0 0 0]\n[0 0 0]\n[0 0 0]\n\njulia> B = S(12)\n[12 0 0]\n[ 0 12 0]\n[ 0 0 12]\n\njulia> C = S(R(11))\n[11 0 0]\n[ 0 11 0]\n[ 0 0 11]\n","category":"page"},{"location":"matrix_algebras/#Matrix-algebra-element-constructors","page":"Generic matrix algebras","title":"Matrix algebra element constructors","text":"","category":"section"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"The following additional constructors are provided for constructing various kinds of matrices in a matrix algebra.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"identity_matrix(::Generic.MatRingElem{T}) where T <: RingElement","category":"page"},{"location":"matrix_algebras/#AbstractAlgebra.identity_matrix-Union{Tuple{AbstractAlgebra.Generic.MatRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Generic matrix algebras","title":"AbstractAlgebra.identity_matrix","text":"identity_matrix(M::MatElem{T}) where T <: NCRingElement\n\nConstruct the identity matrix in the same matrix space as M, i.e. with ones down the diagonal and zeroes elsewhere. M must be square. This is an alias for one(M).\n\n\n\n\n\nidentity_matrix(M::MatRingElem{T}) where T <: RingElement\n\nReturn the identity matrix over the same base ring as M and with the same dimensions.\n\n\n\n\n\n","category":"method"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Examples","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"S = matrix_ring(ZZ, 2)\nM = zero(S)\n\nP = identity_matrix(M)","category":"page"},{"location":"matrix_algebras/#Matrix-algebra-functionality-provided-by-AbstractAlgebra.jl","page":"Generic matrix algebras","title":"Matrix algebra functionality provided by AbstractAlgebra.jl","text":"","category":"section"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Most of the generic matrix functionality described in the generic matrix section of the documentation is available for both matrix spaces and matrix algebras. Exceptions include functions that do not return or accept square matrices or which cannot specify a parent. Such functions include solve and nullspace which can't be provided for matrix algebras.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"In addition to the functionality described for matrix spaces, matrix algebras support all noncommutative ring operations, and matrix algebras can be used as a base ring for other generic constructs that accept a noncommutative base ring (NCRing).","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"In this section we describe functionality provided for matrix algebras only.","category":"page"},{"location":"matrix_algebras/#Basic-matrix-functionality","page":"Generic matrix algebras","title":"Basic matrix functionality","text":"","category":"section"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"As well as the Ring and Matrix interfaces, the following functions are provided to manipulate matrices.","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"degree(::Generic.MatRingElem)","category":"page"},{"location":"matrix_algebras/#AbstractAlgebra.degree-Tuple{AbstractAlgebra.Generic.MatRingElem}","page":"Generic matrix algebras","title":"AbstractAlgebra.degree","text":"degree(a::MatRingElem{T}) where T <: RingElement\n\nReturn the degree n of the given matrix algebra.\n\n\n\n\n\n","category":"method"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"Examples","category":"page"},{"location":"matrix_algebras/","page":"Generic matrix algebras","title":"Generic matrix algebras","text":"julia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S = matrix_ring(R, 3)\nMatrix ring of degree 3\n over univariate polynomial ring in t over rationals\n\njulia> A = S([t + 1 t R(1); t^2 t t; R(-2) t + 2 t^2 + t + 1])\n[t + 1 t 1]\n[ t^2 t t]\n[ -2 t + 2 t^2 + t + 1]\n\njulia> n = degree(A)\n3\n","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"puiseux/#Generic-Puiseux-series","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"AbstractAlgebra.jl allows the creation of Puiseux series over any computable commutative ring R.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Puiseux series are power series of the form a_jx^jm + a_j+1x^(j+1)m + cdots + a_k-1x^(k-1)m + O(x^km) for some integer m 0 where i geq 0, a_i in R and the relative precision k - j is at most equal to some specified precision n.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"The generic Puiseux series module is implemented in src/generic/PuiseuxSeries.jl.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"As well as implementing the Series Ring interface, the Puiseux series module in AbstractAlgebra.jl implements the generic algorithms described below.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"All of the generic functionality is part of the Generic submodule of AbstractAlgebra.jl. This is exported by default so that it is not necessary to qualify function names.","category":"page"},{"location":"puiseux/#Types-and-parent-objects","page":"Generic Puiseux series","title":"Types and parent objects","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"The types of generic Puiseux series implemented by AbstractAlgebra.jl are Generic.PuiseuxSeriesRingElem{T} and Generic.PuiseuxSeriesFieldElem{T}.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Both series element types belong to the union type Generic.PuiseuxSeriesElem.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Puiseux series elements belong directly to either RingElem or FieldElem since it is more useful to be able to distinguish whether they belong to a ring or field than it is to distinguish that they are Puiseux series.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"The parent types for Puiseux series, Generic.PuiseuxSeriesRing{T} and Generic.PuiseuxSeriesField{T} respectively, belong to Ring and Field respectively.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"The default precision, string representation of the variable and base ring R of a generic Puiseux series are stored in its parent object.","category":"page"},{"location":"puiseux/#Puiseux-series-ring-constructors","page":"Generic Puiseux series","title":"Puiseux series ring constructors","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"In order to construct Puiseux series in AbstractAlgebra.jl, one must first construct the ring itself. This is accomplished with any of the following constructors.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"puiseux_series_ring(R::Ring, prec_max::Int, s::VarName; cached::Bool = true)","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"puiseux_series_ring(R::Field, prec_max::Int, s::VarName; cached::Bool = true)","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"puiseux_series_field(R::Field, prec_max::Int, s::VarName; cached::Bool = true)","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Given a base ring R, a maximum relative precision and a string s specifying how the generator (variable) should be printed, return a tuple S, x representing the Puiseux series ring and its generator.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"By default, S will depend only on S, x and the maximum precision and will be cached. Setting the optional argument cached to false will prevent this.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Here are some examples of constructing various kinds of Puiseux series rings and coercing various elements into those rings.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Examples","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"julia> R, x = puiseux_series_ring(ZZ, 10, \"x\")\n(Puiseux series ring in x over integers, x + O(x^11))\n\njulia> S, y = puiseux_series_field(QQ, 10, \"y\")\n(Puiseux series field in y over rationals, y + O(y^11))\n\njulia> f = R()\nO(x^10)\n\njulia> g = S(123)\n123 + O(y^10)\n\njulia> h = R(BigInt(1234))\n1234 + O(x^10)\n\njulia> k = S(y + 1)\n1 + y + O(y^10)\n","category":"page"},{"location":"puiseux/#Big-oh-notation","page":"Generic Puiseux series","title":"Big-oh notation","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Series elements can be given a precision using the big-oh notation. This is provided by a function of the following form, (or something equivalent for Laurent series):","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"O(x::SeriesElem)","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Examples","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"julia> R, x = puiseux_series_ring(ZZ, 10, \"x\")\n(Puiseux series ring in x over integers, x + O(x^11))\n\njulia> f = 1 + 2x + O(x^5)\n1 + 2*x + O(x^5)\n\njulia> g = 2x^(1//3) + 7x^(2//3) + O(x^(7//3))\n2*x^(1//3) + 7*x^(2//3) + O(x^(7//3))","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"What is happening here in practice is that O(x^n) is creating the series 0 + O(x^n) and the rules for addition of series dictate that if this is added to a series of greater precision, then the lower of the two precisions must be used.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Of course it may be that the precision of the series that O(x^n) is added to is already lower than n, in which case adding O(x^n) has no effect. This is the case if the default precision is too low, since x on its own has the default precision.","category":"page"},{"location":"puiseux/#Puiseux-series-implementation","page":"Generic Puiseux series","title":"Puiseux series implementation","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Puiseux series have their maximum relative precision capped at some value prec_max. This refers to the internal Laurent series used to store the Puiseux series, i.e. the series without denominators in the exponents.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"The Puiseux series type stores such a Laurent series and a scale or denominator for the exponents. For example, f(x) = 1 + x^13 + 2x^23 + O(x^73) would be stored as a Laurent series 1 + x + 2x^2 + O(x^7) and a scale of 3..","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"The maximum precision is also used as a default (Laurent) precision in the case of coercing coefficients into the ring and for any computation where the result could mathematically be given to infinite precision.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"In all models we say that two Puiseux series are equal if they agree up to the minimum absolute precision of the two power series.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Thus, for example, x^5 + O(x^10) == 0 + O(x^5), since the minimum absolute precision is 5.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Sometimes it is necessary to compare Puiseux series not just for arithmetic equality, as above, but to see if they have precisely the same precision and terms. For this purpose we introduce the isequal function.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"For example, if f = x^2 + O(x^7) and g = x^2 + O(x^8) and h = 0 + O(x^2) then f == g, f == h and g == h, but isequal(f, g), isequal(f, h) and isequal(g, h) would all return false. However, if k = x^2 + O(x^7) then isequal(f, k) would return true.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"There are a number of technicalities that must be observed when working with Puiseux series. As these are the same as for the other series rings in AbstractAlgebra.jl, we refer the reader to the documentation of series rings for information about these issues.","category":"page"},{"location":"puiseux/#Basic-ring-functionality","page":"Generic Puiseux series","title":"Basic ring functionality","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"All Puiseux series provide the functionality described in the Ring and Series Ring interfaces with the exception of the pol_length and polcoeff functions. Naturally the set_precision!, set_valuation! and coeff functions can take a rational exponent.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Examples","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"julia> S, x = puiseux_series_ring(ZZ, 10, \"x\")\n(Puiseux series ring in x over integers, x + O(x^11))\n\njulia> f = 1 + 3x + x^3 + O(x^10)\n1 + 3*x + x^3 + O(x^10)\n\njulia> g = 1 + 2x^(1//3) + x^(2//3) + O(x^(7//3))\n1 + 2*x^(1//3) + x^(2//3) + O(x^(7//3))\n\njulia> h = zero(S)\nO(x^10)\n\njulia> k = one(S)\n1 + O(x^10)\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> coeff(g, 1//3)\n2\n\njulia> U = base_ring(S)\nIntegers\n\njulia> v = var(S)\n:x\n\njulia> T = parent(x + 1)\nPuiseux series ring in x over integers\n\njulia> g == deepcopy(g)\ntrue\n\njulia> t = divexact(2g, 2)\n1 + 2*x^(1//3) + x^(2//3) + O(x^(7//3))\n\njulia> p = precision(f)\n10//1\n","category":"page"},{"location":"puiseux/#Puiseux-series-functionality-provided-by-AbstractAlgebra.jl","page":"Generic Puiseux series","title":"Puiseux series functionality provided by AbstractAlgebra.jl","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"The functionality below is automatically provided by AbstractAlgebra.jl for any Puiseux series.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Of course, modules are encouraged to provide specific implementations of the functions described here, that override the generic implementation.","category":"page"},{"location":"puiseux/#Basic-functionality","page":"Generic Puiseux series","title":"Basic functionality","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"coeff(a::Generic.PuiseuxSeriesElem, n::Int)","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"coeff(a::Generic.PuiseuxSeriesElem, n::Rational{Int})","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Return the coefficient of the term of exponent n of the given power series. If n exceeds the current precision of the power series or does not correspond to a nonzero term of the Puiseux series, the function returns a zero coefficient.","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"modulus{T <: ResElem}(::Generic.PuiseuxSeriesElem{T})","category":"page"},{"location":"puiseux/#AbstractAlgebra.modulus-Union{Tuple{Union{AbstractAlgebra.Generic.PuiseuxSeriesFieldElem{T}, AbstractAlgebra.Generic.PuiseuxSeriesRingElem{T}}}, Tuple{T}} where T<:ResElem","page":"Generic Puiseux series","title":"AbstractAlgebra.modulus","text":"modulus(a::Generic.PuiseuxSeriesElem{T}) where {T <: ResElem}\n\nReturn the modulus of the coefficients of the given Puiseux series.\n\n\n\n\n\n","category":"method"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"is_gen(::Generic.PuiseuxSeriesElem)","category":"page"},{"location":"puiseux/#AbstractAlgebra.is_gen-Tuple{Union{AbstractAlgebra.Generic.PuiseuxSeriesFieldElem{T}, AbstractAlgebra.Generic.PuiseuxSeriesRingElem{T}} where T<:RingElement}","page":"Generic Puiseux series","title":"AbstractAlgebra.is_gen","text":"is_gen(a::Generic.PuiseuxSeriesElem)\n\nReturn true if the given Puiseux series is arithmetically equal to the generator of its Puiseux series ring to its current precision, otherwise return false.\n\n\n\n\n\n","category":"method"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Examples","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"julia> R, t = puiseux_series_ring(QQ, 10, \"t\")\n(Puiseux series field in t over rationals, t + O(t^11))\n\njulia> S, x = puiseux_series_ring(R, 30, \"x\")\n(Puiseux series field in x over puiseux series field, x + O(x^31))\n\njulia> a = O(x^4)\nO(x^4)\n\njulia> b = (t + 3)*x + (t^2 + 1)*x^2 + O(x^4)\n(3 + t + O(t^10))*x + (1 + t^2 + O(t^10))*x^2 + O(x^4)\n\njulia> k = is_gen(gen(R))\ntrue\n\njulia> m = is_unit(-1 + x^(1//3) + 2x^2)\ntrue\n\njulia> n = valuation(a)\n4//1\n\njulia> p = valuation(b)\n1//1\n\njulia> c = coeff(b, 2)\n1 + t^2 + O(t^10)\n","category":"page"},{"location":"puiseux/#Division","page":"Generic Puiseux series","title":"Division","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Base.inv(::Generic.PuiseuxSeriesElem)","category":"page"},{"location":"puiseux/#Base.inv-Tuple{Union{AbstractAlgebra.Generic.PuiseuxSeriesFieldElem{T}, AbstractAlgebra.Generic.PuiseuxSeriesRingElem{T}} where T<:RingElement}","page":"Generic Puiseux series","title":"Base.inv","text":"inv(M::MatrixElem{T}) where {T <: RingElement}\n\nGiven a non-singular ntimes n matrix over a ring, return an ntimes n matrix X such that MX = I_n, where I_n is the ntimes n identity matrix. If M is not invertible over the base ring an exception is raised.\n\n\n\n\n\nBase.inv(a::PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the inverse of the power series a, i.e. 1a, if it exists. Otherwise an exception is raised.\n\n\n\n\n\n inv(a::LocalizedEuclideanRingElem{T}, checked::Bool = true) where {T <: RingElem}\n\nReturns the inverse element of a if a is a unit. If 'checked = false' the invertibility of a is not checked and the corresponding inverse element of the Fraction Field is returned.\n\n\n\n\n\n","category":"method"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Examples","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"julia> R, x = puiseux_series_ring(QQ, 30, \"x\")\n(Puiseux series field in x over rationals, x + O(x^31))\n\njulia> a = 1 + x + 2x^2 + O(x^5)\n1 + x + 2*x^2 + O(x^5)\n\njulia> b = R(-1)\n-1 + O(x^30)\n\njulia> c = inv(a)\n1 - x - x^2 + 3*x^3 - x^4 + O(x^5)\n\njulia> d = inv(b)\n-1 + O(x^30)\n","category":"page"},{"location":"puiseux/#Derivative-and-integral","page":"Generic Puiseux series","title":"Derivative and integral","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"derivative(a::Generic.PuiseuxSeriesElem)\nintegral(a::Generic.PuiseuxSeriesElem)","category":"page"},{"location":"puiseux/#AbstractAlgebra.derivative-Tuple{Union{AbstractAlgebra.Generic.PuiseuxSeriesFieldElem{T}, AbstractAlgebra.Generic.PuiseuxSeriesRingElem{T}} where T<:RingElement}","page":"Generic Puiseux series","title":"AbstractAlgebra.derivative","text":"derivative(f::AbsPowerSeriesRingElem{T})\n\nReturn the derivative of the power series f.\n\n\n\n\n\nderivative(f::RelPowerSeriesRingElem{T})\n\nReturn the derivative of the power series f.\n\njulia> R, x = power_series_ring(QQ, 10, \"x\")\n(Univariate power series ring in x over Rationals, x + O(x^11))\n\njulia> f = 2 + x + 3x^3\n2 + x + 3*x^3 + O(x^10)\n\njulia> derivative(f)\n1 + 9*x^2 + O(x^9)\n\n\n\n\n\nderivative(f::MPolyRingElem{T}, j::Int) where {T <: RingElement}\n\nReturn the partial derivative of f with respect to j-th variable of the polynomial ring.\n\n\n\n\n\nderivative(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement\n\nReturn the partial derivative of f with respect to x. The value x must be a generator of the polynomial ring of f.\n\n\n\n\n\nderivative(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the derivative of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"puiseux/#AbstractAlgebra.integral-Tuple{Union{AbstractAlgebra.Generic.PuiseuxSeriesFieldElem{T}, AbstractAlgebra.Generic.PuiseuxSeriesRingElem{T}} where T<:RingElement}","page":"Generic Puiseux series","title":"AbstractAlgebra.integral","text":"integral(f::AbsPowerSeriesRingElem{T})\n\nReturn the integral of the power series f.\n\n\n\n\n\nintegral(f::RelPowerSeriesRingElem{T})\n\nReturn the integral of the power series f.\n\njulia> R, x = power_series_ring(QQ, 10, \"x\")\n(Univariate power series ring in x over Rationals, x + O(x^11))\n\njulia> f = 2 + x + 3x^3\n2 + x + 3*x^3 + O(x^10)\n\njulia> integral(f)\n2*x + 1//2*x^2 + 3//4*x^4 + O(x^11)\n\n\n\n\n\nintegral(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the integral of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Examples","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"julia> R, x = puiseux_series_ring(QQ, 10, \"x\")\n(Puiseux series field in x over rationals, x + O(x^11))\n\njulia> f = x^(5//3) + x^(7//3) + x^(11//3)\nx^(5//3) + x^(7//3) + x^(11//3) + O(x^5)\n\njulia> derivative(f)\n5//3*x^(2//3) + 7//3*x^(4//3) + 11//3*x^(8//3) + O(x^4)\n\njulia> derivative(integral(f)) == f\ntrue","category":"page"},{"location":"puiseux/#Special-functions","page":"Generic Puiseux series","title":"Special functions","text":"","category":"section"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Base.log(a::Generic.PuiseuxSeriesElem)\nBase.exp(a::Generic.PuiseuxSeriesElem)","category":"page"},{"location":"puiseux/#Base.log-Tuple{Union{AbstractAlgebra.Generic.PuiseuxSeriesFieldElem{T}, AbstractAlgebra.Generic.PuiseuxSeriesRingElem{T}} where T<:RingElement}","page":"Generic Puiseux series","title":"Base.log","text":"log(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the logarithm of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"puiseux/#Base.exp-Tuple{Union{AbstractAlgebra.Generic.PuiseuxSeriesFieldElem{T}, AbstractAlgebra.Generic.PuiseuxSeriesRingElem{T}} where T<:RingElement}","page":"Generic Puiseux series","title":"Base.exp","text":"exp(a::AbsPowerSeriesRingElem)\n\nReturn the exponential of the power series a.\n\n\n\n\n\nexp(a::RelPowerSeriesRingElem)\n\nReturn the exponential of the power series a.\n\n\n\n\n\nexp(a::Generic.LaurentSeriesElem)\n\nReturn the exponential of the power series a.\n\n\n\n\n\nexp(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the exponential of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Base.sqrt(a::Generic.PuiseuxSeriesElem)","category":"page"},{"location":"puiseux/#Base.sqrt-Tuple{Union{AbstractAlgebra.Generic.PuiseuxSeriesFieldElem{T}, AbstractAlgebra.Generic.PuiseuxSeriesRingElem{T}} where T<:RingElement}","page":"Generic Puiseux series","title":"Base.sqrt","text":"Base.sqrt(f::PolyRingElem{T}; check::Bool=true) where T <: RingElement\n\nReturn the square root of f. By default the function checks the input is square and raises an exception if not. If check=false this check is omitted.\n\n\n\n\n\nBase.sqrt(a::FracElem{T}; check::Bool=true) where T <: RingElem\n\nReturn the square root of a. By default the function will throw an exception if the input is not square. If check=false this test is omitted.\n\n\n\n\n\nsqrt(a::Generic.PuiseuxSeriesElem{T}; check::Bool=true) where T <: RingElement\n\nReturn the square root of the given Puiseux series a. By default the function will throw an exception if the input is not square. If check=false this test is omitted.\n\n\n\n\n\n","category":"method"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"Examples","category":"page"},{"location":"puiseux/","page":"Generic Puiseux series","title":"Generic Puiseux series","text":"julia> R, t = polynomial_ring(QQ, \"t\")\n(Univariate polynomial ring in t over rationals, t)\n\njulia> S, x = puiseux_series_ring(R, 30, \"x\")\n(Puiseux series ring in x over univariate polynomial ring, x + O(x^31))\n\njulia> T, z = puiseux_series_ring(QQ, 30, \"z\")\n(Puiseux series field in z over rationals, z + O(z^31))\n\njulia> a = 1 + z + 3z^2 + O(z^5)\n1 + z + 3*z^2 + O(z^5)\n\njulia> b = z + 2z^2 + 5z^3 + O(z^5)\nz + 2*z^2 + 5*z^3 + O(z^5)\n\njulia> c = exp(x + O(x^40))\n1 + x + 1//2*x^2 + 1//6*x^3 + 1//24*x^4 + 1//120*x^5 + 1//720*x^6 + 1//5040*x^7 + 1//40320*x^8 + 1//362880*x^9 + 1//3628800*x^10 + 1//39916800*x^11 + 1//479001600*x^12 + 1//6227020800*x^13 + 1//87178291200*x^14 + 1//1307674368000*x^15 + 1//20922789888000*x^16 + 1//355687428096000*x^17 + 1//6402373705728000*x^18 + 1//121645100408832000*x^19 + 1//2432902008176640000*x^20 + 1//51090942171709440000*x^21 + 1//1124000727777607680000*x^22 + 1//25852016738884976640000*x^23 + 1//620448401733239439360000*x^24 + 1//15511210043330985984000000*x^25 + 1//403291461126605635584000000*x^26 + 1//10888869450418352160768000000*x^27 + 1//304888344611713860501504000000*x^28 + 1//8841761993739701954543616000000*x^29 + 1//265252859812191058636308480000000*x^30 + O(x^31)\n\njulia> d = divexact(x, exp(x + O(x^40)) - 1)\n1 - 1//2*x + 1//12*x^2 - 1//720*x^4 + 1//30240*x^6 - 1//1209600*x^8 + 1//47900160*x^10 - 691//1307674368000*x^12 + 1//74724249600*x^14 - 3617//10670622842880000*x^16 + 43867//5109094217170944000*x^18 - 174611//802857662698291200000*x^20 + 77683//14101100039391805440000*x^22 - 236364091//1693824136731743669452800000*x^24 + 657931//186134520519971831808000000*x^26 - 3392780147//37893265687455865519472640000000*x^28 + O(x^29)\n\njulia> f = exp(b)\n1 + z + 5//2*z^2 + 43//6*z^3 + 193//24*z^4 + O(z^5)\n\njulia> h = sqrt(a)\n1 + 1//2*z + 11//8*z^2 - 11//16*z^3 - 77//128*z^4 + O(z^5)\n","category":"page"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"CurrentModule = AbstractAlgebra.Solve","category":"page"},{"location":"linear_solving/#Linear-solving","page":"Linear solving","title":"Linear solving","text":"","category":"section"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"note: Note\nThis functionality is experimental and subject to change.","category":"page"},{"location":"linear_solving/#Overview-of-the-functionality","page":"Linear solving","title":"Overview of the functionality","text":"","category":"section"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"The module AbstractAlgebra.Solve provides the following four functions for solving linear systems:","category":"page"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"solve\ncan_solve\ncan_solve_with_solution\ncan_solve_with_solution_and_kernel","category":"page"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"All of these take the same set of arguments, namely:","category":"page"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"a matrix A of type MatElem{T};\na vector or matrix B of type Vector{T} or MatElem{T};\na keyword argument side which can be either :left (default) or :right.","category":"page"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"If side is :left, the system xA = B is solved, otherwise the system Ax = B is solved. For matrices defined over a field, the functions internally rely on rref. If the matrices are defined over a ring, the function hnf_with_transform is required internally.","category":"page"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"The functionality of the functions can be summarized as follows.","category":"page"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"solve: return a solution, if it exists, otherwise throw an error.\ncan_solve: return true, if a solution exists, false otherwise.\ncan_solve_with_solution: return true and a solution, if this exists, and false and an empty vector or matrix otherwise.\ncan_solve_with_solution_and_kernel: like can_solve_with_solution and additionally return a matrix whose columns (respectively rows) give a basis of the kernel of A.","category":"page"},{"location":"linear_solving/#Solving-with-several-right-hand-sides","page":"Linear solving","title":"Solving with several right hand sides","text":"","category":"section"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"Systems Ax = b_1dots Ax = b_k with the same matrix A, but several right hand sides b_i can be solved more efficiently, by first initializing a \"context object\" C of type SolveCtx.","category":"page"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"solve_init","category":"page"},{"location":"linear_solving/#AbstractAlgebra.Solve.solve_init","page":"Linear solving","title":"AbstractAlgebra.Solve.solve_init","text":"solve_init(A::MatElem)\n\nReturn a context object C that allows to efficiently solve linear systems Ax = b or xA = b for different b.\n\n\n\n\n\n","category":"function"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"Now the functions solve, can_solve, etc. can be used with C in place of A. This way the time-consuming part of the solving (i.e. computing a reduced form of A) is only done once and the result cached in C to be reused.","category":"page"},{"location":"linear_solving/#Detailed-documentation","page":"Linear solving","title":"Detailed documentation","text":"","category":"section"},{"location":"linear_solving/","page":"Linear solving","title":"Linear solving","text":"solve\ncan_solve\ncan_solve_with_solution\ncan_solve_with_solution_and_kernel\nkernel","category":"page"},{"location":"linear_solving/#AbstractAlgebra.Solve.solve","page":"Linear solving","title":"AbstractAlgebra.Solve.solve","text":"solve(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T\nsolve(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T\nsolve(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T\nsolve(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T\n\nReturn x of same type as b solving the linear system xA = b, if side == :left (default), or Ax = b, if side == :right.\n\nIf no solution exists, an error is raised.\n\nIf a context object C is supplied, then the above applies for A = matrix(C).\n\nSee also can_solve_with_solution.\n\n\n\n\n\n","category":"function"},{"location":"linear_solving/#AbstractAlgebra.Solve.can_solve","page":"Linear solving","title":"AbstractAlgebra.Solve.can_solve","text":"can_solve(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T\ncan_solve(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T\ncan_solve(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T\ncan_solve(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T\n\nReturn true if the linear system xA = b or Ax = b with side == :left (default) or side == :right, respectively, has a solution and false otherwise.\n\nIf a context object C is supplied, then the above applies for A = matrix(C).\n\nSee also can_solve_with_solution.\n\n\n\n\n\n","category":"function"},{"location":"linear_solving/#AbstractAlgebra.Solve.can_solve_with_solution","page":"Linear solving","title":"AbstractAlgebra.Solve.can_solve_with_solution","text":"can_solve_with_solution(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T\ncan_solve_with_solution(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T\ncan_solve_with_solution(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T\ncan_solve_with_solution(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T\n\nReturn true and x of same type as b solving the linear system xA = b, if such a solution exists. Return false and an empty vector or matrix, if the system has no solution.\n\nIf side == :right, the system Ax = b is solved.\n\nIf a context object C is supplied, then the above applies for A = matrix(C).\n\nSee also solve.\n\n\n\n\n\n","category":"function"},{"location":"linear_solving/#AbstractAlgebra.Solve.can_solve_with_solution_and_kernel","page":"Linear solving","title":"AbstractAlgebra.Solve.can_solve_with_solution_and_kernel","text":"can_solve_with_solution_and_kernel(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T\ncan_solve_with_solution_and_kernel(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T\ncan_solve_with_solution_and_kernel(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T\ncan_solve_with_solution_and_kernel(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T\n\nReturn true, x of same type as b solving the linear system xA = b, together with a matrix K giving the kernel of A (i.e. KA = 0), if such a solution exists. Return false, an empty vector or matrix and an empty matrix, if the system has no solution.\n\nIf side == :right, the system Ax = b is solved.\n\nIf a context object C is supplied, then the above applies for A = matrix(C).\n\nSee also solve and kernel.\n\n\n\n\n\n","category":"function"},{"location":"linear_solving/#AbstractAlgebra.Solve.kernel","page":"Linear solving","title":"AbstractAlgebra.Solve.kernel","text":"kernel([R::Ring], A::MatElem; side::Symbol = :left)\nkernel(C::SolveCtx; side::Symbol = :left)\n\nReturn a matrix K whose rows give a basis for the left kernel of A, that is, KA is the zero matrix.\n\nIf side == :right, the columns of K give a basis for the right kernel of A, that is, AK is the zero matrix.\n\nIf a ring R is supplied as a first argument, the kernel is computed over R.\n\nIf a context object C is supplied, then the above applies for A = matrix(C).\n\n\n\n\n\n","category":"function"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"integer/#Integer-ring","page":"Integer ring","title":"Integer ring","text":"","category":"section"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"AbstractAlgebra.jl provides a module, implemented in src/julia/Integer.jl for making Julia BigInts conform to the AbstractAlgebra.jl Ring interface.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"In addition to providing a parent object ZZ for Julia BigInts, we implement any additional functionality required by AbstractAlgebra.jl.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"Because BigInt cannot be directly included in the AbstractAlgebra.jl abstract type hierarchy, we achieve integration of Julia BigInts by introducing a type union, called RingElement, which is a union of RingElem and a number of Julia types, including BigInt. Everywhere that RingElem is notionally used in AbstractAlgebra.jl, we are in fact using RingElement, with additional care being taken to avoid ambiguities.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"The details of how this is done are technical, and we refer the reader to the implementation for details. For most intents and purposes, one can think of the Julia BigInt type as belonging to RingElem.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"One other technicality is that Julia defines certain functions for BigInt, such as sqrt and exp differently to what AbstractAlgebra.jl requires. To get around this, we redefine these functions internally to AbstractAlgebra.jl, without redefining them for users of AbstractAlgebra.jl. This allows the internals of AbstractAlgebra.jl to function correctly, without broadcasting pirate definitions of already defined Julia functions to the world.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"To access the internal definitions, one can use AbstractAlgebra.sqrt and AbstractAlgebra.exp, etc.","category":"page"},{"location":"integer/#Types-and-parent-objects","page":"Integer ring","title":"Types and parent objects","text":"","category":"section"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"Integers have type BigInt, as in Julia itself. We simply supplement the functionality for this type as required for computer algebra.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"The parent objects of such integers has type Integers{BigInt}.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"For convenience, we also make Int a part of the AbstractAlgebra.jl type hierarchy and its parent object (accessible as zz) has type Integers{Int}. But we caution that this type is not particularly useful as a model of the integers and may not function as expected within AbstractAlgebra.jl.","category":"page"},{"location":"integer/#Integer-constructors","page":"Integer ring","title":"Integer constructors","text":"","category":"section"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"In order to construct integers in AbstractAlgebra.jl, one can first construct the integer ring itself. This is accomplished using the following constructor.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"Integers{BigInt}()","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"This gives the unique object of type Integers{BigInt} representing the ring of integers in AbstractAlgebra.jl.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"In practice, one simply uses ZZ which is assigned to be the return value of the above constructor. There is no need to call the constructor in practice.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"Here are some examples of creating the integer ring and making use of the resulting parent object to coerce various elements into the ring.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"Examples","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"julia> f = ZZ()\n0\n\njulia> g = ZZ(123)\n123\n\njulia> h = ZZ(BigInt(1234))\n1234\n","category":"page"},{"location":"integer/#Basic-ring-functionality","page":"Integer ring","title":"Basic ring functionality","text":"","category":"section"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"The integer ring in AbstractAlgebra.jl implements the full Ring interface and the Euclidean Ring interface.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"We give some examples of such functionality.","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"Examples","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"julia> f = ZZ(12)\n12\n\njulia> h = zero(ZZ)\n0\n\njulia> k = one(ZZ)\n1\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> T = parent(f)\nIntegers\n\njulia> f == deepcopy(f)\ntrue\n\njulia> g = f + 12\n24\n\njulia> h = powermod(f, 12, ZZ(17))\n4\n\njulia> flag, q = divides(f, ZZ(3))\n(true, 4)\n","category":"page"},{"location":"integer/#Integer-functionality-provided-by-AbstractAlgebra.jl","page":"Integer ring","title":"Integer functionality provided by AbstractAlgebra.jl","text":"","category":"section"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"The functionality below supplements that provided by Julia itself for its BigInt type.","category":"page"},{"location":"integer/#Basic-functionality","page":"Integer ring","title":"Basic functionality","text":"","category":"section"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"Examples","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"julia> r = ZZ(-1)\n-1\n\njulia> is_unit(r)\ntrue\n","category":"page"},{"location":"integer/#Divisibility-testing","page":"Integer ring","title":"Divisibility testing","text":"","category":"section"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"is_divisible_by(a::BigInt, b::BigInt)","category":"page"},{"location":"integer/#AbstractAlgebra.Generic.is_divisible_by-Tuple{BigInt, BigInt}","page":"Integer ring","title":"AbstractAlgebra.Generic.is_divisible_by","text":"is_divisible_by(a::Integer, b::Integer)\n\nReturn true if a is divisible by b, i.e. if there exists c such that a = bc.\n\n\n\n\n\n","category":"method"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"** Examples **","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"julia> r = ZZ(6)\n6\n\njulia> s = ZZ(3)\n3\n\njulia> is_divisible_by(r, s)\ntrue","category":"page"},{"location":"integer/#Square-root","page":"Integer ring","title":"Square root","text":"","category":"section"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"AbstractAlgebra.sqrt(a::BigInt)","category":"page"},{"location":"integer/#AbstractAlgebra.sqrt-Tuple{BigInt}","page":"Integer ring","title":"AbstractAlgebra.sqrt","text":"sqrt(a::T; check::Bool=true) where T <: Integer\n\nReturn the square root of a. By default the function will throw an exception if the input is not square. If check=false this test is omitted.\n\n\n\n\n\n","category":"method"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"is_square(a::BigInt)\nis_square_with_sqrt(a::BigInt)","category":"page"},{"location":"integer/#AbstractAlgebra.is_square-Tuple{BigInt}","page":"Integer ring","title":"AbstractAlgebra.is_square","text":"is_square(f::PolyRingElem{T}) where T <: RingElement\n\nReturn true if f is a perfect square.\n\n\n\n\n\nis_square(a::ResFieldElem{T}) where T <: Integer\n\nReturn true if a is a square.\n\n\n\n\n\nis_square(a::T) where T <: Integer\n\nReturn true if a is a square.\n\n\n\n\n\n","category":"method"},{"location":"integer/#AbstractAlgebra.is_square_with_sqrt-Tuple{BigInt}","page":"Integer ring","title":"AbstractAlgebra.is_square_with_sqrt","text":"is_square_with_sqrt(a::T) where T <: Integer\n\nReturn (true, s) if a is a perfect square, where s^2 = a. Otherwise return (false, 0).\n\n\n\n\n\n","category":"method"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"root(a::BigInt)\niroot(a::BigInt)","category":"page"},{"location":"integer/#AbstractAlgebra.root-Tuple{BigInt}","page":"Integer ring","title":"AbstractAlgebra.root","text":"root(a::T, n::Int; check::Bool=true) where T <: Integer\n\nReturn the n-th root of a. If check=true the function will test if the input was a perfect n-th power, otherwise an exception will be raised. We require n 0.\n\n\n\n\n\n","category":"method"},{"location":"integer/#AbstractAlgebra.iroot-Tuple{BigInt}","page":"Integer ring","title":"AbstractAlgebra.iroot","text":"iroot(a::T, n::Int) where T <: Integer\n\nReturn the truncated integer part of the n-th root of a (round towards zero). We require n 0 and also a geq 0 if n is even.\n\n\n\n\n\n","category":"method"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"is_power(a::T, n::Int) where T <: Integer","category":"page"},{"location":"integer/#AbstractAlgebra.Generic.is_power-Union{Tuple{T}, Tuple{T, Int64}} where T<:Integer","page":"Integer ring","title":"AbstractAlgebra.Generic.is_power","text":"is_power(a::T, n::Int) where T <: Integer\n\nReturn true, q if a is a perfect n-th power with a = q^n. Otherwise return false, 0. We require n 0.\n\n\n\n\n\n","category":"method"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"AbstractAlgebra.exp(a::BigInt)","category":"page"},{"location":"integer/#AbstractAlgebra.exp-Tuple{BigInt}","page":"Integer ring","title":"AbstractAlgebra.exp","text":"exp(a::T) where T <: Integer\n\nReturn 1 if a = 0, otherwise throw an exception. This function is not generally of use to the user, but is used internally in AbstractAlgebra.jl.\n\n\n\n\n\nexp(a::Rational{T}) where T <: Integer\n\nReturn 1 if a = 0, otherwise throw an exception.\n\n\n\n\n\n","category":"method"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"Examples","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"julia> d = AbstractAlgebra.sqrt(ZZ(36))\n6\n\njulia> is_square(ZZ(9))\ntrue\n\njulia> m = AbstractAlgebra.exp(ZZ(0))\n1","category":"page"},{"location":"integer/#Coprime-bases","page":"Integer ring","title":"Coprime bases","text":"","category":"section"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"ppio(a::BigInt, b::BigInt)","category":"page"},{"location":"integer/#AbstractAlgebra.ppio-Tuple{BigInt, BigInt}","page":"Integer ring","title":"AbstractAlgebra.ppio","text":"ppio(a::T, b::T)\n\nReturn a pair (cd) such that a=c*d and c = gcd(a b^infty) if aneq 0, and c=b, d=0 if a=0.\n\n\n\n\n\n","category":"method"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"Examples","category":"page"},{"location":"integer/","page":"Integer ring","title":"Integer ring","text":"julia> c, n = ppio(ZZ(12), ZZ(26))\n(4, 3)\n","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"mpolynomial/#Sparse-distributed-multivariate-polynomials","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"AbstractAlgebra.jl provides a module, implemented in src/MPoly.jl for sparse distributed multivariate polynomials over any commutative ring belonging to the AbstractAlgebra abstract type hierarchy.","category":"page"},{"location":"mpolynomial/#Generic-sparse-distributed-multivariable-polynomial-types","page":"Sparse distributed multivariate polynomials","title":"Generic sparse distributed multivariable polynomial types","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"AbstractAlgebra provides a generic multivariate polynomial type Generic.MPoly{T} where T is the type of elements of the coefficient ring.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The polynomials are implemented using a Julia array of coefficients and a 2-dimensional Julia array of UInts for the exponent vectors. Note that exponent n is represented by the n-th column of the exponent array, not the n-th row. This is because Julia uses a column major representation. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The top bit of each UInt is reserved for overflow detection.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Parent objects of such polynomials have type Generic.MPolyRing{T}.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The string representation of the variables of the polynomial ring and the base/coefficient ring R and the ordering are stored in the parent object.","category":"page"},{"location":"mpolynomial/#Abstract-types","page":"Sparse distributed multivariate polynomials","title":"Abstract types","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The polynomial element types belong to the abstract type MPolyRingElem{T} and the polynomial ring types belong to the abstract type MPolyRing{T}.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"note: Note\nNote that both the generic polynomial ring type Generic.MPolyRing{T} and the abstract type it belongs to, MPolyRing{T} are both called MPolyRing. The former is a (parameterised) concrete type for a polynomial ring over a given base ring whose elements have type T. The latter is an abstract type representing all multivariate polynomial ring types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).","category":"page"},{"location":"mpolynomial/#Polynomial-ring-constructors","page":"Sparse distributed multivariate polynomials","title":"Polynomial ring constructors","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"In order to construct multivariate polynomials in AbstractAlgebra.jl, one must first construct the polynomial ring itself. This is accomplished with the following constructors.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"polynomial_ring(::Ring, ::Vector{Symbol})\npolynomial_ring(::Ring, ::Vararg)\npolynomial_ring(::Ring, ::Int)\n@polynomial_ring","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.polynomial_ring-Tuple{Ring, Vector{Symbol}}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.polynomial_ring","text":"polynomial_ring(R::Ring, varnames::Vector{Symbol}; cached=true, ordering=:lex)\n\nGiven a coefficient ring R and variable names, say varnames = [:x1, :x2, ...], return a tuple S, [x1, x2, ...] of the polynomial ring S = Rx1 x2 dots and its generators x1 x2 dots.\n\nBy default (cached=true), the output S will be cached, i.e. if polynomial_ring is invoked again with the same arguments, the same (identical) ring is returned. Setting cached to false ensures a distinct new ring is returned, and will also prevent it from being cached.\n\nThe ordering of the polynomial ring can be one of :lex, :deglex or :degrevlex.\n\nSee also: polynomial_ring(::Ring, ::Vararg), @polynomial_ring.\n\nExample\n\njulia> S, generators = polynomial_ring(ZZ, [:x, :y, :z])\n(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y, z])\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.polynomial_ring-Tuple{Ring, Vararg}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.polynomial_ring","text":"polynomial_ring(R::Ring, varnames...; cached=true, ordering=:lex)\npolynomial_ring(R::Ring, varnames::Tuple; cached=true, ordering=:lex)\n\nLike polynomial_ring(::Ring, ::Vector{Symbol}) with more ways to give varnames as specified in variable_names.\n\nReturn a tuple S, generators... with generators[i] corresponding to varnames[i].\n\nnote: Note\nIn the first method, varnames must not be empty, and if it consists of only one name, the univariate polynomial_ring(R::NCRing, s::VarName) method is called instead.\n\nExamples\n\njulia> S, (a, b, c) = polynomial_ring(ZZ, [:a, :b, :c])\n(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[a, b, c])\n\njulia> S, x, y = polynomial_ring(ZZ, :x => (1:2, 1:2), :y => 1:3);\n\njulia> S\nMultivariate polynomial ring in 7 variables x[1, 1], x[2, 1], x[1, 2], x[2, 2], ..., y[3]\n over integers\n\njulia> x\n2×2 Matrix{AbstractAlgebra.Generic.MPoly{BigInt}}:\n x[1, 1] x[1, 2]\n x[2, 1] x[2, 2]\n\njulia> y\n3-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:\n y[1]\n y[2]\n y[3]\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.polynomial_ring-Tuple{Ring, Int64}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.polynomial_ring","text":"polynomial_ring(R::Ring, varnames...; cached=true, ordering=:lex)\npolynomial_ring(R::Ring, varnames::Tuple; cached=true, ordering=:lex)\n\nLike polynomial_ring(::Ring, ::Vector{Symbol}) with more ways to give varnames as specified in variable_names.\n\nReturn a tuple S, generators... with generators[i] corresponding to varnames[i].\n\nnote: Note\nIn the first method, varnames must not be empty, and if it consists of only one name, the univariate polynomial_ring(R::NCRing, s::VarName) method is called instead.\n\nExamples\n\njulia> S, (a, b, c) = polynomial_ring(ZZ, [:a, :b, :c])\n(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[a, b, c])\n\njulia> S, x, y = polynomial_ring(ZZ, :x => (1:2, 1:2), :y => 1:3);\n\njulia> S\nMultivariate polynomial ring in 7 variables x[1, 1], x[2, 1], x[1, 2], x[2, 2], ..., y[3]\n over integers\n\njulia> x\n2×2 Matrix{AbstractAlgebra.Generic.MPoly{BigInt}}:\n x[1, 1] x[1, 2]\n x[2, 1] x[2, 2]\n\njulia> y\n3-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:\n y[1]\n y[2]\n y[3]\n\n\n\n\n\npolynomial_ring(R::Ring, n::Int, s::Symbol=:x; cached=true, ordering=:lex)\n\nSame as polynomial_ring(::Ring, [\"s$i\" for i in 1:n]).\n\nExample\n\njulia> S, x = polynomial_ring(ZZ, 3)\n(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x1, x2, x3])\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.@polynomial_ring","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.@polynomial_ring","text":"@polynomial_ring(R::Ring, varnames...; cached=true, ordering=:lex)\n\nReturn polynomial ring from polynomial_ring(::Ring, ::Vararg) and introduce the generators into the current scope.\n\nExamples\n\njulia> S = @polynomial_ring(ZZ, \"x#\" => (1:2, 1:2), \"y#\" => 1:3)\nMultivariate polynomial ring in 7 variables x11, x21, x12, x22, ..., y3\n over integers\n\njulia> x11, x21, x12, x22\n(x11, x21, x12, x22)\n\njulia> y1, y2, y3\n(y1, y2, y3)\n\njulia> (S, [x11 x12; x21 x22], [y1, y2, y3]) == polynomial_ring(ZZ, \"x#\" => (1:2, 1:2), \"y#\" => 1:3)\ntrue\n\n\n\n\n\n","category":"macro"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Like for univariate polynomials, a shorthand constructor is provided when the number of generators is greater than 1: given a base ring R, we abbreviate the constructor as follows:","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"R[\"x\", \"y\", ...]","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Here are some examples of creating multivariate polynomial rings and making use of the resulting parent objects to coerce various elements into the polynomial ring.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"]; ordering=:deglex)\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> T, (z, t) = QQ[\"z\", \"t\"]\n(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[z, t])\n\njulia> f = R()\n0\n\njulia> g = R(123)\n123\n\njulia> h = R(BigInt(1234))\n1234\n\njulia> k = R(x + 1)\nx + 1\n\njulia> m = R(x + y + 1)\nx + y + 1\n\njulia> derivative(k, 1)\n1\n\njulia> derivative(k, 2)\n0\n\njulia> R, x = polynomial_ring(ZZ, 10); R\nMultivariate polynomial ring in 10 variables x1, x2, x3, x4, ..., x10\n over integers\n","category":"page"},{"location":"mpolynomial/#Polynomial-constructors","page":"Sparse distributed multivariate polynomials","title":"Polynomial constructors","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Multivariate polynomials can be constructed from the generators in the usual way using arithmetic operations.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Also, all of the standard ring element constructors may be used to construct multivariate polynomials.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"(R::MPolyRing{T})() where T <: RingElement\n(R::MPolyRing{T})(c::Integer) where T <: RingElement\n(R::MPolyRing{T})(a::elem_type(R)) where T <: RingElement\n(R::MPolyRing{T})(a::T) where T <: RingElement","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"For more efficient construction of multivariate polynomial, one can use the MPoly build context, where terms (coefficient followed by an exponent vector) are pushed onto a context one at a time and then the polynomial constructed from those terms in one go using the finish function.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"MPolyBuildCtx(R::MPolyRing)\npush_term!(M::MPolyBuildCtx, c::RingElem, v::Vector{Int})\nfinish(M::MPolyBuildCtx)","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.Generic.MPolyBuildCtx-Tuple{MPolyRing}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.Generic.MPolyBuildCtx","text":"MPolyBuildCtx(R::MPolyRing)\n\nReturn a build context for creating polynomials in the given ring.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.Generic.push_term!-Tuple{MPolyBuildCtx, RingElem, Vector{Int64}}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.Generic.push_term!","text":"push_term!(M::MPolyBuildCtx, c::RingElem, v::Vector{Int})\n\nAdd the term with coefficient c and exponent vector v to the polynomial under construction in the build context M.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.Generic.finish-Tuple{MPolyBuildCtx}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.Generic.finish","text":"finish(M::MPolyBuildCtx)\n\nFinish construction of the polynomial, sort the terms, remove duplicate and zero terms and return the created polynomial.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Note that the finish function resets the build context so that it can be used to construct multiple polynomials..","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"When a multivariate polynomial type has a representation that allows constant time access (e.g. it is represented internally by arrays), the following additional constructor is available. It takes and array of coefficients and and array of exponent vectors.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"(S::MPolyRing{T})(A::Vector{T}, m::Vector{Vector{Int}}) where T <: RingElem","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Create the polynomial in the given ring with nonzero coefficients specified by the elements of A and corresponding exponent vectors given by the elements of m.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> C = MPolyBuildCtx(R)\nBuilder for an element of Multivariate polynomial ring in 2 variables over integers\n\njulia> push_term!(C, ZZ(3), [1, 2]);\n\n\njulia> push_term!(C, ZZ(2), [1, 1]);\n\n\njulia> push_term!(C, ZZ(4), [0, 0]);\n\n\njulia> f = finish(C)\n3*x*y^2 + 2*x*y + 4\n\njulia> push_term!(C, ZZ(4), [1, 1]);\n\n\njulia> f = finish(C)\n4*x*y\n\njulia> S, (x, y) = polynomial_ring(QQ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])\n\njulia> f = S(Rational{BigInt}[2, 3, 1], [[3, 2], [1, 0], [0, 1]])\n2*x^3*y^2 + 3*x + y","category":"page"},{"location":"mpolynomial/#Functions-for-types-and-parents-of-multivariate-polynomial-rings","page":"Sparse distributed multivariate polynomials","title":"Functions for types and parents of multivariate polynomial rings","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"base_ring(R::MPolyRing)\nbase_ring(a::MPolyRingElem)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Return the coefficient ring of the given polynomial ring or polynomial, respectively.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"parent(a::MPolyRingElem)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Return the polynomial ring of the given polynomial.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"characteristic(R::MPolyRing)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Return the characteristic of the given polynomial ring. If the characteristic is not known, an exception is raised.","category":"page"},{"location":"mpolynomial/#Polynomial-functions","page":"Sparse distributed multivariate polynomials","title":"Polynomial functions","text":"","category":"section"},{"location":"mpolynomial/#Basic-manipulation","page":"Sparse distributed multivariate polynomials","title":"Basic manipulation","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"All the standard ring functions are available, including the following.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"zero(R::MPolyRing)\none(R::MPolyRing)\niszero(a::MPolyRingElem)\nisone(a::MPolyRingElem)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"divexact(a::T, b::T) where T <: MPolyRingElem","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"All basic functions from the Multivariate Polynomial interface are provided.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"symbols(S::MPolyRing)\nnumber_of_variables(f::MPolyRing)\ngens(S::MPolyRing)\ngen(S::MPolyRing, i::Int)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"ordering(S::MPolyRing{T})","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Note that the currently supported orderings are :lex, :deglex and :degrevlex.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"length(f::MPolyRingElem)\ndegrees(f::MPolyRingElem)\ntotal_degree(f::MPolyRingElem)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"is_gen(x::MPolyRingElem)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"divexact(f::T, g::T) where T <: MPolyRingElem","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"For multivariate polynomial types that allow constant time access to coefficients, the following are also available, allowing access to the given coefficient, monomial or term. Terms are numbered from the most significant first.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"coeff(f::MPolyRingElem, n::Int)\ncoeff(a::MPolyRingElem, exps::Vector{Int})","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Access a coefficient by term number or exponent vector.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"monomial(f::MPolyRingElem, n::Int)\nmonomial!(m::T, f::T, n::Int) where T <: MPolyRingElem","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The second version writes the result into a preexisting polynomial object to save an allocation.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"term(f::MPolyRingElem, n::Int)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"exponent(f::MyMPolyRingElem, i::Int, j::Int)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Return the exponent of the j-th variable in the i-th term of the polynomial f.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"exponent_vector(a::MPolyRingElem, i::Int)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"setcoeff!(a::MPolyRingElem{T}, exps::Vector{Int}, c::T) where T <: RingElement","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Although multivariate polynomial rings are not usually Euclidean, the following functions from the Euclidean interface are often provided.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"divides(f::T, g::T) where T <: MPolyRingElem\nremove(f::T, g::T) where T <: MPolyRingElem\nvaluation(f::T, g::T) where T <: MPolyRingElem","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"divrem(f::T, g::T) where T <: MPolyRingElem\ndiv(f::T, g::T) where T <: MPolyRingElem","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Compute a tuple (q r) such that f = qg + r, where the coefficients of terms of r whose monomials are divisible by the leading monomial of g are reduced modulo the leading coefficient of g (according to the Euclidean function on the coefficients). The divrem version returns both quotient and remainder whilst the div version only returns the quotient.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Note that the result of these functions depend on the ordering of the polynomial ring.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"gcd(f::T, g::T) where T <: MPolyRingElem","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The following functionality is also provided for all multivariate polynomials.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"is_univariate(::MPolyRing{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.is_univariate-Union{Tuple{MPolyRing{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.is_univariate","text":"is_univariate(R::MPolyRing)\n\nReturns true if R is a univariate polynomial ring, i.e. has exactly one variable, and false otherwise.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"vars(p::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.vars-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.vars","text":"vars(p::MPolyRingElem{T}) where {T <: RingElement}\n\nReturn the variables actually occurring in p.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"var_index(::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.var_index-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.var_index","text":"var_index(p::MPolyRingElem{T}) where {T <: RingElement}\n\nReturn the index of the given variable x. If x is not a variable in a multivariate polynomial ring, an exception is raised.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"degree(::MPolyRingElem{T}, ::Int) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.degree-Union{Tuple{T}, Tuple{MPolyRingElem{T}, Int64}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.degree","text":"degree(f::MPolyRingElem{T}, i::Int) where T <: RingElement\n\nReturn the degree of the polynomial f in terms of the i-th variable.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"degree(::MPolyRingElem{T}, ::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.degree-Union{Tuple{T}, Tuple{MPolyRingElem{T}, MPolyRingElem{T}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.degree","text":"degree(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement\n\nReturn the degree of the polynomial f in terms of the variable x.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"degrees(::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.degrees-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.degrees","text":"degrees(f::MPolyRingElem{T}) where T <: RingElement\n\nReturn an array of the degrees of the polynomial f in terms of each variable.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"is_constant(::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.is_constant-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.is_constant","text":"is_constant(x::MPolyRingElem{T}) where T <: RingElement\n\nReturn true if x is a degree zero polynomial or the zero polynomial, i.e. a constant polynomial.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"is_term(::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.is_term-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.is_term","text":"is_term(x::MPolyRingElem)\n\nReturn true if the given polynomial has precisely one term.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"is_monomial(::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.is_monomial-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.is_monomial","text":"is_monomial(x::MPolyRingElem)\n\nReturn true if the given polynomial has precisely one term whose coefficient is one.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"is_univariate(::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.is_univariate-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.is_univariate","text":"is_univariate(p::MPolyRingElem)\n\nReturns true if p is a univariate polynomial, i.e. involves at most one variable (thus constant polynomials are considered univariate), and false otherwise. The result depends on the terms of the polynomial, not simply on the number of variables in the polynomial ring.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"coeff(::MPolyRingElem{T}, ::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.coeff-Union{Tuple{T}, Tuple{MPolyRingElem{T}, MPolyRingElem{T}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.coeff","text":"coeff(f::MPolyRingElem{T}, m::MPolyRingElem{T}) where T <: RingElement\n\nReturn the coefficient of the monomial m of the polynomial f. If there is no such monomial, zero is returned.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = x^2 + 2x + 1\nx^2 + 2*x + 1\n\njulia> V = vars(f)\n1-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:\n x\n\njulia> var_index(y) == 2\ntrue\n\njulia> degree(f, x) == 2\ntrue\n\njulia> degree(f, 2) == 0\ntrue\n\njulia> d = degrees(f)\n2-element Vector{Int64}:\n 2\n 0\n\njulia> is_constant(R(1))\ntrue\n\njulia> is_term(2x)\ntrue\n\njulia> is_monomial(y)\ntrue\n\njulia> is_unit(R(1))\ntrue\n\njulia> S, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = x^3*y + 3x*y^2 + 1\nx^3*y + 3*x*y^2 + 1\n\njulia> c1 = coeff(f, 1)\n1\n\njulia> c2 = coeff(f, x^3*y)\n1\n\njulia> m = monomial(f, 2)\nx*y^2\n\njulia> e1 = exponent(f, 1, 1)\n3\n\njulia> v1 = exponent_vector(f, 1)\n2-element Vector{Int64}:\n 3\n 1\n\njulia> t1 = term(f, 1)\nx^3*y\n\njulia> setcoeff!(f, [3, 1], 12)\n12*x^3*y + 3*x*y^2 + 1\n\njulia> S, (x, y) = polynomial_ring(QQ, [\"x\", \"y\"]; ordering=:deglex)\n(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])\n\njulia> V = symbols(S)\n2-element Vector{Symbol}:\n :x\n :y\n\njulia> X = gens(S)\n2-element Vector{AbstractAlgebra.Generic.MPoly{Rational{BigInt}}}:\n x\n y\n\njulia> ord = ordering(S)\n:deglex\n\njulia> S, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = x^3*y + 3x*y^2 + 1\nx^3*y + 3*x*y^2 + 1\n\njulia> n = length(f)\n3\n\njulia> is_gen(y)\ntrue\n\njulia> number_of_variables(S) == 2\ntrue\n\njulia> d = total_degree(f)\n4\n\njulia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = 2x^2*y + 2x + y + 1\n2*x^2*y + 2*x + y + 1\n\njulia> g = x^2*y^2 + 1\nx^2*y^2 + 1\n\njulia> flag, q = divides(f*g, f)\n(true, x^2*y^2 + 1)\n\njulia> d = divexact(f*g, f)\nx^2*y^2 + 1\n\njulia> v, q = remove(f*g^3, g)\n(3, 2*x^2*y + 2*x + y + 1)\n\njulia> n = valuation(f*g^3, g)\n3\n\njulia> R, (x, y) = polynomial_ring(QQ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])\n\njulia> f = 3x^2*y^2 + 2x + 1\n3*x^2*y^2 + 2*x + 1\n\njulia> f1 = divexact(f, 5)\n3//5*x^2*y^2 + 2//5*x + 1//5\n\njulia> f2 = divexact(f, QQ(2, 3))\n9//2*x^2*y^2 + 3*x + 3//2","category":"page"},{"location":"mpolynomial/#Square-root","page":"Sparse distributed multivariate polynomials","title":"Square root","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Over rings for which an exact square root is available, it is possible to take the square root of a polynomial or test whether it is a square.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"sqrt(f::MPolyRingElem, check::bool=true)\nis_square(::MPolyRingElem)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = -4*x^5*y^4 + 5*x^5*y^3 + 4*x^4 - x^3*y^4\n-4*x^5*y^4 + 5*x^5*y^3 + 4*x^4 - x^3*y^4\n\njulia> sqrt(f^2)\n4*x^5*y^4 - 5*x^5*y^3 - 4*x^4 + x^3*y^4\n\njulia> is_square(f)\nfalse","category":"page"},{"location":"mpolynomial/#Iterators","page":"Sparse distributed multivariate polynomials","title":"Iterators","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The following iterators are provided for multivariate polynomials.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"coefficients(p::MPoly)\nmonomials(p::MPoly)\nterms(p::MPoly)\nexponent_vectors(a::MPoly)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> S, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = x^3*y + 3x*y^2 + 1\nx^3*y + 3*x*y^2 + 1\n\njulia> C = collect(coefficients(f))\n3-element Vector{BigInt}:\n 1\n 3\n 1\n\njulia> M = collect(monomials(f))\n3-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:\n x^3*y\n x*y^2\n 1\n\njulia> T = collect(terms(f))\n3-element Vector{AbstractAlgebra.Generic.MPoly{BigInt}}:\n x^3*y\n 3*x*y^2\n 1\n\njulia> V = collect(exponent_vectors(f))\n3-element Vector{Vector{Int64}}:\n [3, 1]\n [1, 2]\n [0, 0]","category":"page"},{"location":"mpolynomial/#Changing-base-(coefficient)-rings","page":"Sparse distributed multivariate polynomials","title":"Changing base (coefficient) rings","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"In order to substitute the variables of a polynomial f over a ring T by elements in a T-algebra S, you first have to change the base ring of f using the following function, where g is a function representing the structure homomorphism of the T-algebra S.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"change_base_ring(::Ring, p::MPolyRingElem{T}) where {T <: RingElement}\nchange_coefficient_ring(::Ring, p::MPolyRingElem{T}) where {T <: RingElement}\nmap_coefficients(::Any, p::MPolyRingElem)","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.change_base_ring-Union{Tuple{T}, Tuple{Ring, MPolyRingElem{T}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.change_base_ring","text":"change_base_ring(R::Ring, p::MPolyRingElem{<: RingElement}; parent::MPolyRing, cached::Bool=true)\n\nReturn the polynomial obtained by coercing the non-zero coefficients of p into R.\n\nIf the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.change_coefficient_ring-Union{Tuple{T}, Tuple{Ring, MPolyRingElem{T}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.change_coefficient_ring","text":"change_coefficient_ring(R::Ring, p::MPolyRingElem{<: RingElement}; parent::MPolyRing, cached::Bool=true)\n\nReturn the polynomial obtained by coercing the non-zero coefficients of p into R.\n\nIf the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.map_coefficients-Tuple{Any, MPolyRingElem}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.map_coefficients","text":"map_coefficients(f, p::MPolyRingElem{<: RingElement}; parent::MPolyRing)\n\nTransform the polynomial p by applying f on each non-zero coefficient.\n\nIf the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> fz = x^2*y^2 + x + 1\nx^2*y^2 + x + 1\n\njulia> fq = change_base_ring(QQ, fz)\nx^2*y^2 + x + 1\n\njulia> fq = change_coefficient_ring(QQ, fz)\nx^2*y^2 + x + 1\n","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"In case a specific parent ring is constructed, it can also be passed to the function.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> S, = polynomial_ring(QQ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over rationals, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}[x, y])\n\njulia> fz = x^5 + y^3 + 1\nx^5 + y^3 + 1\n\njulia> fq = change_base_ring(QQ, fz, parent=S)\nx^5 + y^3 + 1","category":"page"},{"location":"mpolynomial/#Multivariate-coefficients","page":"Sparse distributed multivariate polynomials","title":"Multivariate coefficients","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"In order to return the \"coefficient\" (as a multivariate polynomial in the same ring), of a given monomial (in which some of the variables may not appear and others may be required to appear to exponent zero), we can use the following function.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"coeff(a::MPolyRingElem{T}, vars::Vector{Int}, exps::Vector{Int}) where T <: RingElement\ncoeff(a::T, vars::Vector{T}, exps::Vector{Int}) where T <: MPolyRingElem","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.coeff-Union{Tuple{T}, Tuple{MPolyRingElem{T}, Vector{Int64}, Vector{Int64}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.coeff","text":"coeff(a::MPolyRingElem{T}, vars::Vector{Int}, exps::Vector{Int}) where T <: RingElement\n\nReturn the \"coefficient\" of a (as a multivariate polynomial in the same ring) of the monomial consisting of the product of the variables of the given indices raised to the given exponents (note that not all variables need to appear and the exponents can be zero). E.g. coeff(f, [1, 3], [0, 2]) returns the coefficient of x^0*z^2 in the polynomial f (assuming variables x y z in that order).\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.coeff-Union{Tuple{T}, Tuple{T, Vector{T}, Vector{Int64}}} where T<:MPolyRingElem","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.coeff","text":"coeff(a::T, vars::Vector{T}, exps::Vector{Int}) where T <: MPolyRingElem\n\nReturn the \"coefficient\" of a (as a multivariate polynomial in the same ring) of the monomial consisting of the product of the given variables to the given exponents (note that not all variables need to appear and the exponents can be zero). E.g. coeff(f, [x, z], [0, 2]) returns the coefficient of x^0*z^2 in the polynomial f.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y, z) = polynomial_ring(ZZ, [\"x\", \"y\", \"z\"])\n(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y, z])\n\njulia> f = x^4*y^2*z^2 - 2x^4*y*z^2 + 4x^4*z^2 + 2x^2*y^2 + x + 1\nx^4*y^2*z^2 - 2*x^4*y*z^2 + 4*x^4*z^2 + 2*x^2*y^2 + x + 1\n\njulia> coeff(f, [1, 3], [4, 2]) == coeff(f, [x, z], [4, 2])\ntrue\n","category":"page"},{"location":"mpolynomial/#Inflation/deflation","page":"Sparse distributed multivariate polynomials","title":"Inflation/deflation","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"deflation(f::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.deflation-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.deflation","text":"deflation(f::MPolyRingElem{T}) where T <: RingElement\n\nCompute deflation parameters for the exponents of the polynomial f. This is a pair of arrays of integers, the first array of which (the shift) gives the minimum exponent for each variable of the polynomial, and the second of which (the deflation) gives the gcds of all the exponents after subtracting the shift, again per variable. This functionality is used by gcd (and can be used by factorisation algorithms).\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"deflate(f::MPolyRingElem{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: RingElement\ndeflate(f::MPolyRingElem{T}, defl::Vector{Int}) where T <: RingElement\ndeflate(f::MPolyRingElem{T}) where T <: RingElement\ndeflate(f::MPolyRingElem, vars::Vector{Int}, shift::Vector{Int}, defl::Vector{Int})\ndeflate(f::T, vars::Vector{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: MPolyRingElem","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.deflate-Union{Tuple{T}, Tuple{MPolyRingElem{T}, Vector{Int64}, Vector{Int64}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.deflate","text":"deflate(f::MPolyRingElem{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: RingElement\n\nReturn a polynomial with the same coefficients as f but whose exponents have been reduced by the given shifts (supplied as an array of shifts, one for each variable), then deflated (divided) by the given exponents (again supplied as an array of deflation factors, one for each variable). The algorithm automatically replaces a deflation of 0 by 1, to avoid division by 0.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.deflate-Union{Tuple{T}, Tuple{MPolyRingElem{T}, Vector{Int64}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.deflate","text":"deflate(f::MPolyRingElem{T}, defl::Vector{Int}) where T <: RingElement\n\nReturn a polynomial with the same coefficients as f but whose exponents have been deflated (divided) by the given exponents (supplied as an array of deflation factors, one for each variable).\n\nThe algorithm automatically replaces a deflation of 0 by 1, to avoid division by 0.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.deflate-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.deflate","text":"deflate(f::MPolyRingElem{T}, defl::Vector{Int}) where T <: RingElement\n\nReturn a polynomial with the same coefficients as f but whose exponents have been deflated maximally, i.e. with each exponent divide by the largest integer which divides the degrees of all exponents of that variable in f.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.deflate-Tuple{MPolyRingElem, Vector{Int64}, Vector{Int64}, Vector{Int64}}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.deflate","text":"deflate(f::MPolyRingElem, vars::Vector{Int}, shift::Vector{Int}, defl::Vector{Int})\n\nReturn a polynomial with the same coefficients as f but where exponents of some variables (supplied as an array of variable indices) have been reduced by the given shifts (supplied as an array of shifts), then deflated (divided) by the given exponents (again supplied as an array of deflation factors). The algorithm automatically replaces a deflation of 0 by 1, to avoid division by 0.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.deflate-Union{Tuple{T}, Tuple{T, Vector{T}, Vector{Int64}, Vector{Int64}}} where T<:MPolyRingElem","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.deflate","text":"deflate(f::T, vars::Vector{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: MPolyRingElem\n\nReturn a polynomial with the same coefficients as f but where the exponents of the given variables have been reduced by the given shifts (supplied as an array of shifts), then deflated (divided) by the given exponents (again supplied as an array of deflation factors). The algorithm automatically replaces a deflation of 0 by 1, to avoid division by 0.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"inflate(f::MPolyRingElem{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: RingElement\ninflate(f::MPolyRingElem{T}, defl::Vector{Int}) where T <: RingElement\ninflate(f::MPolyRingElem, vars::Vector{Int}, shift::Vector{Int}, defl::Vector{Int})\ninflate(f::T, vars::Vector{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: MPolyRingElem","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.inflate-Union{Tuple{T}, Tuple{MPolyRingElem{T}, Vector{Int64}, Vector{Int64}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.inflate","text":"inflate(f::MPolyRingElem{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: RingElement\n\nReturn a polynomial with the same coefficients as f but whose exponents have been inflated (multiplied) by the given deflation exponents (supplied as an array of inflation factors, one for each variable) and then increased by the given shifts (again supplied as an array of shifts, one for each variable).\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.inflate-Union{Tuple{T}, Tuple{MPolyRingElem{T}, Vector{Int64}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.inflate","text":"inflate(f::MPolyRingElem{T}, defl::Vector{Int}) where T <: RingElement\n\nReturn a polynomial with the same coefficients as f but whose exponents have been inflated (multiplied) by the given deflation exponents (supplied as an array of inflation factors, one for each variable).\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.inflate-Tuple{MPolyRingElem, Vector{Int64}, Vector{Int64}, Vector{Int64}}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.inflate","text":"inflate(f::MPolyRingElem, vars::Vector{Int}, shift::Vector{Int}, defl::Vector{Int})\n\nReturn a polynomial with the same coefficients as f but where exponents of some variables (supplied as an array of variable indices) have been inflated (multiplied) by the given deflation exponents (supplied as an array of inflation factors) and then increased by the given shifts (again supplied as an array of shifts).\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.inflate-Union{Tuple{T}, Tuple{T, Vector{T}, Vector{Int64}, Vector{Int64}}} where T<:MPolyRingElem","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.inflate","text":"inflate(f::T, vars::Vector{T}, shift::Vector{Int}, defl::Vector{Int}) where T <: MPolyRingElem\n\nReturn a polynomial with the same coefficients as f but where the exponents of the given variables have been inflated (multiplied) by the given deflation exponents (supplied as an array of inflation factors) and then increased by the given shifts (again supplied as an array of shifts).\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = x^7*y^8 + 3*x^4*y^8 - x^4*y^2 + 5x*y^5 - x*y^2\nx^7*y^8 + 3*x^4*y^8 - x^4*y^2 + 5*x*y^5 - x*y^2\n\njulia> def, shift = deflation(f)\n([1, 2], [3, 3])\n\njulia> f1 = deflate(f, def, shift)\nx^2*y^2 + 3*x*y^2 - x + 5*y - 1\n\njulia> f2 = inflate(f1, def, shift)\nx^7*y^8 + 3*x^4*y^8 - x^4*y^2 + 5*x*y^5 - x*y^2\n\njulia> f2 == f\ntrue\n\njulia> g = (x+y+1)^2\nx^2 + 2*x*y + 2*x + y^2 + 2*y + 1\n\njulia> g0 = coeff(g, [y], [0])\nx^2 + 2*x + 1\n\njulia> g1 = deflate(g - g0, [y], [1], [1])\n2*x + y + 2\n\njulia> g == g0 + y * g1\ntrue\n","category":"page"},{"location":"mpolynomial/#Conversions","page":"Sparse distributed multivariate polynomials","title":"Conversions","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"to_univariate(R::PolyRing{T}, p::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.to_univariate-Union{Tuple{T}, Tuple{PolyRing{T}, MPolyRingElem{T}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.to_univariate","text":"to_univariate(R::PolyRing{T}, p::MPolyRingElem{T}) where T <: RingElement\n\nAssuming the polynomial p is actually a univariate polynomial, convert the polynomial to a univariate polynomial in the given univariate polynomial ring R. An exception is raised if the polynomial p involves more than one variable.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> S, z = polynomial_ring(ZZ, \"z\")\n(Univariate polynomial ring in z over integers, z)\n\njulia> f = 2x^5 + 3x^4 - 2x^2 - 1\n2*x^5 + 3*x^4 - 2*x^2 - 1\n\njulia> g = to_univariate(S, f)\n2*z^5 + 3*z^4 - 2*z^2 - 1\n","category":"page"},{"location":"mpolynomial/#Evaluation","page":"Sparse distributed multivariate polynomials","title":"Evaluation","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The following function allows evaluation of a polynomial at all its variables. The result is always in the ring that a product of a coefficient and one of the values belongs to, i.e. if all the values are in the coefficient ring, the result of the evaluation will be too.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"evaluate(::MPolyRingElem{T}, ::Vector{U}) where {T <: RingElement, U <: RingElement}","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.evaluate-Union{Tuple{U}, Tuple{T}, Tuple{MPolyRingElem{T}, Vector{U}}} where {T<:RingElement, U<:RingElement}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.evaluate","text":"evaluate(a::MPolyRingElem{T}, vals::Vector{U}) where {T <: RingElement, U <: RingElement}\n\nEvaluate the polynomial expression by substituting in the array of values for each of the variables. The evaluation will succeed if multiplication is defined between elements of the coefficient ring of a and elements of the supplied vector.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The following functions allow evaluation of a polynomial at some of its variables. Note that the result will be a product of values and an element of the polynomial ring, i.e. even if all the values are in the coefficient ring and all variables are given values, the result will be a constant polynomial, not a coefficient.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"evaluate(::MPolyRingElem{T}, ::Vector{Int}, ::Vector{U}) where {T <: RingElement, U <: RingElement}","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.evaluate-Union{Tuple{U}, Tuple{T}, Tuple{MPolyRingElem{T}, Vector{Int64}, Vector{U}}} where {T<:RingElement, U<:RingElement}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.evaluate","text":"evaluate(a::MPolyRingElem{T}, vars::Vector{Int}, vals::Vector{U}) where {T <: RingElement, U <: RingElement}\n\nEvaluate the polynomial expression by substituting in the supplied values in the array vals for the corresponding variables with indices given by the array vars. The evaluation will succeed if multiplication is defined between elements of the coefficient ring of a and elements of vals.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"evaluate(::S, ::Vector{S}, ::Vector{U}) where {S <: MPolyRingElem{T}, U <: RingElement} where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.evaluate-Union{Tuple{U}, Tuple{S}, Tuple{T}, Tuple{S, Vector{S}, Vector{U}}} where {T<:RingElement, S<:MPolyRingElem{T}, U<:RingElement}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.evaluate","text":"evaluate(a::S, vars::Vector{S}, vals::Vector{U}) where {S <: MPolyRingElem{T}, U <: RingElement} where T <: RingElement\n\nEvaluate the polynomial expression by substituting in the supplied values in the array vals for the corresponding variables (supplied as polynomials) given by the array vars. The evaluation will succeed if multiplication is defined between elements of the coefficient ring of a and elements of vals.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The following function allows evaluation of a polynomial at values in a not necessarily commutative ring, e.g. elements of a matrix algebra.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"evaluate(::MPolyRingElem{T}, ::Vector{U}) where {T <: RingElement, U <: NCRingElem}","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.evaluate-Union{Tuple{U}, Tuple{T}, Tuple{MPolyRingElem{T}, Vector{U}}} where {T<:RingElement, U<:NCRingElem}","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.evaluate","text":"evaluate(a::MPolyRingElem{T}, vals::Vector{U}) where {T <: RingElement, U <: NCRingElem}\n\nEvaluate the polynomial expression at the supplied values, which may be any ring elements, commutative or non-commutative, but in the same ring. Evaluation always proceeds in the order of the variables as supplied when creating the polynomial ring to which a belongs. The evaluation will succeed if a product of a coefficient of the polynomial by one of the values is defined.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = 2x^2*y^2 + 3x + y + 1\n2*x^2*y^2 + 3*x + y + 1\n\njulia> evaluate(f, BigInt[1, 2])\n14\n\njulia> evaluate(f, [QQ(1), QQ(2)])\n14//1\n\njulia> evaluate(f, [1, 2])\n14\n\njulia> f(1, 2) == 14\ntrue\n\njulia> evaluate(f, [x + y, 2y - x])\n2*x^4 - 4*x^3*y - 6*x^2*y^2 + 8*x*y^3 + 2*x + 8*y^4 + 5*y + 1\n\njulia> f(x + y, 2y - x)\n2*x^4 - 4*x^3*y - 6*x^2*y^2 + 8*x*y^3 + 2*x + 8*y^4 + 5*y + 1\n\njulia> R, (x, y, z) = polynomial_ring(ZZ, [\"x\", \"y\", \"z\"])\n(Multivariate polynomial ring in 3 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y, z])\n\njulia> f = x^2*y^2 + 2x*z + 3y*z + z + 1\nx^2*y^2 + 2*x*z + 3*y*z + z + 1\n\njulia> evaluate(f, [1, 3], [3, 4])\n9*y^2 + 12*y + 29\n\njulia> evaluate(f, [x, z], [3, 4])\n9*y^2 + 12*y + 29\n\njulia> evaluate(f, [1, 2], [x + z, x - z])\nx^4 - 2*x^2*z^2 + 5*x*z + z^4 - z^2 + z + 1\n\njulia> S = matrix_ring(ZZ, 2)\nMatrix ring of degree 2\n over integers\n\njulia> M1 = S([1 2; 3 4])\n[1 2]\n[3 4]\n\njulia> M2 = S([2 3; 1 -1])\n[2 3]\n[1 -1]\n\njulia> M3 = S([-1 1; 1 1])\n[-1 1]\n[ 1 1]\n\njulia> evaluate(f, [M1, M2, M3])\n[ 64 83]\n[124 149]","category":"page"},{"location":"mpolynomial/#Leading-and-constant-coefficients,-leading-monomials-and-leading-terms","page":"Sparse distributed multivariate polynomials","title":"Leading and constant coefficients, leading monomials and leading terms","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The leading and trailing coefficient, constant coefficient, leading monomial and leading term of a polynomial p are returned by the following functions:","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"leading_coefficient(::MPolyRingElem{T}) where T <: RingElement\ntrailing_coefficient(p::MPolyRingElem{T}) where T <: RingElement\nleading_monomial(::MPolyRingElem{T}) where T <: RingElement\nleading_term(::MPolyRingElem{T}) where T <: RingElement\nconstant_coefficient(::MPolyRingElem{T}) where T <: RingElement\ntail(::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.leading_coefficient-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.leading_coefficient","text":"leading_coefficient(p::MPolyRingElem)\n\nReturn the leading coefficient of the polynomial p.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.trailing_coefficient-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.trailing_coefficient","text":"trailing_coefficient(p::MPolyRingElem)\n\nReturn the trailing coefficient of the polynomial p, i.e. the coefficient of the last nonzero term, or zero if the polynomial is zero.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.leading_monomial-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.leading_monomial","text":"leading_monomial(p::MPolyRingElem)\n\nReturn the leading monomial of p. This function throws an ArgumentError if p is zero.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.leading_term-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.leading_term","text":"leading_term(p::MPolyRingElem)\n\nReturn the leading term of the polynomial p. This function throws an ArgumentError if p is zero.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.constant_coefficient-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.constant_coefficient","text":"constant_coefficient(p::MPolyRingElem)\n\nReturn the constant coefficient of the polynomial p or zero if it doesn't have one.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#AbstractAlgebra.tail-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.tail","text":"tail(p::MPolyRingElem)\n\nReturn the tail of the polynomial p, i.e. the polynomial without its leading term (if any).\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"using AbstractAlgebra\nR,(x,y) = polynomial_ring(ZZ, [\"x\", \"y\"], ordering=:deglex)\np = 2*x*y + 3*y^3 + 1\nleading_term(p)\nleading_monomial(p)\nleading_coefficient(p)\nleading_term(p) == leading_coefficient(p) * leading_monomial(p)\nconstant_coefficient(p)\ntail(p)","category":"page"},{"location":"mpolynomial/#Least-common-multiple,-greatest-common-divisor","page":"Sparse distributed multivariate polynomials","title":"Least common multiple, greatest common divisor","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"The greatest common divisor of two polynomials a and b is returned by","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"gcd(a::Generic.MPoly{T}, b::Generic.MPoly{T}) where {T <: RingElement}","category":"page"},{"location":"mpolynomial/#Base.gcd-Union{Tuple{T}, Tuple{AbstractAlgebra.Generic.MPoly{T}, AbstractAlgebra.Generic.MPoly{T}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"Base.gcd","text":"gcd(a::MPoly{T}, a::MPoly{T}) where {T <: RingElement}\n\nReturn the greatest common divisor of a and b in parent(a).\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Note that this functionality is currently only provided for AbstractAlgebra generic polynomials. It is not automatically provided for all multivariate rings that implement the multivariate interface.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"However, if such a gcd is provided, the least common multiple of two polynomials a and b is returned by","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"lcm(a::MPolyRingElem{T}, b::MPolyRingElem{T}) where {T <: RingElement}","category":"page"},{"location":"mpolynomial/#Base.lcm-Union{Tuple{T}, Tuple{MPolyRingElem{T}, MPolyRingElem{T}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"Base.lcm","text":"lcm(a::AbstractAlgebra.MPolyRingElem{T}, a::AbstractAlgebra.MPolyRingElem{T}) where {T <: RingElement}\n\nReturn the least common multiple of a and b in parent(a).\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> using AbstractAlgebra\n\njulia> R,(x,y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> a = x*y + 2*y\nx*y + 2*y\n\njulia> b = x^3*y + y\nx^3*y + y\n\njulia> gcd(a,b)\ny\n\njulia> lcm(a,b)\nx^4*y + 2*x^3*y + x*y + 2*y\n\njulia> lcm(a,b) == a * b // gcd(a,b)\ntrue\n","category":"page"},{"location":"mpolynomial/#Derivations","page":"Sparse distributed multivariate polynomials","title":"Derivations","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"derivative(::MPolyRingElem{T}, ::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.derivative-Union{Tuple{T}, Tuple{MPolyRingElem{T}, MPolyRingElem{T}}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.derivative","text":"derivative(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement\n\nReturn the partial derivative of f with respect to x. The value x must be a generator of the polynomial ring of f.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = AbstractAlgebra.polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = x*y + x + y + 1\nx*y + x + y + 1\n\njulia> derivative(f, x)\ny + 1\n\njulia> derivative(f, y)\nx + 1\n\njulia> derivative(f, 1)\ny + 1\n\njulia> derivative(f, 2)\nx + 1","category":"page"},{"location":"mpolynomial/#Homogeneous-polynomials","page":"Sparse distributed multivariate polynomials","title":"Homogeneous polynomials","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"It is possible to test whether a polynomial is homogeneous with respect to the standard grading using the function","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"is_homogeneous(x::MPolyRingElem{T}) where T <: RingElement","category":"page"},{"location":"mpolynomial/#AbstractAlgebra.Generic.is_homogeneous-Union{Tuple{MPolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Sparse distributed multivariate polynomials","title":"AbstractAlgebra.Generic.is_homogeneous","text":"is_homogeneous(x::MPoly{T}) where {T <: RingElement}\n\nReturn true if the given polynomial is homogeneous with respect to the standard grading and false otherwise.\n\n\n\n\n\n","category":"method"},{"location":"mpolynomial/#Random-generation","page":"Sparse distributed multivariate polynomials","title":"Random generation","text":"","category":"section"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Random multivariate polynomials in a given ring can be constructed by passing a range of degrees for the variables and a range on the number of terms. Additional parameters are used to generate the coefficients of the polynomial.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Note that zero coefficients may currently be generated, leading to less than the requested number of terms.","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"rand(R::MPolyRing, exp_range::AbstractUnitRange{Int}, term_range::AbstractUnitRange{Int}, v...)","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"Examples","category":"page"},{"location":"mpolynomial/","page":"Sparse distributed multivariate polynomials","title":"Sparse distributed multivariate polynomials","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> f = rand(R, -1:2, 3:5, -10:10)\n4*x^4*y^4\n\njulia> S, (s, t) = polynomial_ring(GF(7), [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over finite field F_7, AbstractAlgebra.Generic.MPoly{AbstractAlgebra.GFElem{Int64}}[x, y])\n\njulia> g = rand(S, -1:2, 3:5)\n4*x^3*y^4","category":"page"},{"location":"#AbstractAlgebra.jl","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"","category":"section"},{"location":"#Introduction","page":"AbstractAlgebra.jl","title":"Introduction","text":"","category":"section"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"AbstractAlgebra.jl is a computer algebra package for the Julia programming language, maintained by William Hart, Tommy Hofmann, Claus Fieker and Fredrik Johansson and other interested contributors.","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"Source code","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"AbstractAlgebra.jl grew out of the Nemo project after a number of requests from the community for the pure Julia part of Nemo to be split off into a separate project. See the Nemo repository for more details about Nemo.","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"Nemo repository","category":"page"},{"location":"#Features","page":"AbstractAlgebra.jl","title":"Features","text":"","category":"section"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"The features of AbstractAlgebra.jl include:","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"Use of Julia multiprecision integers and rationals\nFinite fields (prime order, naive implementation only)\nNumber fields (naive implementation only)\nUnivariate polynomials\nMultivariate polynomials\nRelative and absolute power series\nLaurent series\nFraction fields\nResidue rings, including mathbbZnmathbbZ\nMatrices and linear algebra","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"All implementations are fully recursive and generic, so that one can build matrices over polynomial rings, over a finite field, for example.","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"AbstractAlgebra.jl also provides a set of abstract types for Groups, Rings, Fields, Modules and elements thereof, which allow external types to be made part of the AbstractAlgebra.jl type hierarchy.","category":"page"},{"location":"#Installation","page":"AbstractAlgebra.jl","title":"Installation","text":"","category":"section"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"To use AbstractAlgebra we require Julia 1.6 or higher. Please see https://julialang.org/downloads/ for instructions on how to obtain Julia for your system.","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"At the Julia prompt simply type","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"julia> using Pkg; Pkg.add(\"AbstractAlgebra\")","category":"page"},{"location":"#Quick-start","page":"AbstractAlgebra.jl","title":"Quick start","text":"","category":"section"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"Here are some examples of using AbstractAlgebra.jl.","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"This example makes use of multivariate polynomials.","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"using AbstractAlgebra\n\nR, (x, y, z) = polynomial_ring(ZZ, [\"x\", \"y\", \"z\"])\n\nf = x + y + z + 1\n\np = f^20;\n\n@time q = p*(p+1);","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"Here is an example using generic recursive ring constructions.","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"using AbstractAlgebra\n\nR = GF(7)\n\nS, y = polynomial_ring(R, \"y\")\n\nT, = residue_ring(S, y^3 + 3y + 1)\n\nU, z = polynomial_ring(T, \"z\")\n\nf = (3y^2 + y + 2)*z^2 + (2*y^2 + 1)*z + 4y + 3;\n\ng = (7y^2 - y + 7)*z^2 + (3y^2 + 1)*z + 2y + 1;\n\ns = f^4;\n\nt = (s + g)^4;\n\n@time resultant(s, t)","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"Here is an example using matrices.","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"using AbstractAlgebra\n\nR, x = polynomial_ring(ZZ, \"x\")\n\nS = matrix_space(R, 10, 10)\n\nM = rand(S, 0:3, -10:10);\n\n@time det(M)","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"And here is an example with power series.","category":"page"},{"location":"","page":"AbstractAlgebra.jl","title":"AbstractAlgebra.jl","text":"using AbstractAlgebra\n\nR, x = QQ[\"x\"]\n\nS, t = power_series_ring(R, 30, \"t\")\n\nu = t + O(t^100)\n\n@time divexact((u*exp(x*u)), (exp(u)-1));","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"map_cache/#Cached-maps","page":"Cached maps","title":"Cached maps","text":"","category":"section"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"All basic map (i.e. those not built up from other maps) in AbstractAlgebra can be cached.","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"A cache is a dictionary that can be switched on and off at run time that keeps a cache of previous evaluations of the map. This can be useful if the map is extremely difficult to evaluate, e.g. a discrete logarithm map. Rather than evaluate the map afresh each time, the map first looks up the dictionary of previous known values of the map.","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"To facilitate caching of maps, the Generic module provides a type Generic.MapCache, which can be used to wrap any existing map object with a dictionary.","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"Importantly, the supertype of the resulting Generic.MapCache object is identical to that of the map being cached. This means that any functions that would accept the original map will also accept the cached version.","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"note: Note\nCaching of maps only works for maps that correctly abstract access to their fields using accessor functions, as described in the map interface.","category":"page"},{"location":"map_cache/#Cached-map-constructors","page":"Cached maps","title":"Cached map constructors","text":"","category":"section"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"To construct a cached map from an existing map object, we have the following function:","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"cached(M::Map; enabled=true, limit=100)","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"Return a cached map with the same supertype as M, caching up to limit values of the map M in a dictionary, assuming that the cache is enabled.","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"Caches can be disabled by setting the value of the parameter enabled to false. This allows for the user to quickly go through code and completely disable caches of maps that were previously enabled, for testing purposes, etc.","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"Caches can also be turned on and off at run time (see below).","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"Examples","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"julia> f = map_from_func(x -> x + 1, ZZ, ZZ)\nMap defined by a Julia function\n from integers\n to integers\n\njulia> g = cached(f);\n\njulia> f(ZZ(1)) == g(ZZ(1))\ntrue","category":"page"},{"location":"map_cache/#Functionality-for-cached-maps","page":"Cached maps","title":"Functionality for cached maps","text":"","category":"section"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"The following functions are provided for cached maps.","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"enable_cache!(M::MapCache)\ndisable_cache!(M::MapCache)","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"Temporarily enable or disable the cache for the given map. The values stored in the cache are not lost when it is disabled.","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"set_limit!(M::MapCache, limit::Int)","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"Set the limit on the number of values that can be cached in the dictionary, to the given value. Setting the value to 0 will effectively disable further caching for this map.","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"Examples","category":"page"},{"location":"map_cache/","page":"Cached maps","title":"Cached maps","text":"julia> f = cached(map_from_func(x -> x + 1, ZZ, ZZ));\n\njulia> a = f(ZZ(1))\n2\n\njulia> disable_cache!(f)\n\njulia> b = f(ZZ(1))\n2\n\njulia> enable_cache!(f)\n\njulia> c = f(ZZ(1))\n2\n\njulia> set_limit!(f, 200)\n200\n\njulia> d = f(ZZ(1))\n2","category":"page"},{"location":"types/#Type-interface-of-AbstractAlgebra.jl","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"","category":"section"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"Apart from how we usually think of types in programming, we shall in this section discuss why we do not use the typical type interface.","category":"page"},{"location":"types/#Why-types-aren't-enough","page":"Type interface of AbstractAlgebra.jl","title":"Why types aren't enough","text":"","category":"section"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"Naively, one might have expected that structures like rings in AbstractAlgebra.jl could be modeled as types and their elements as objects with the given type. But there are various reasons why this is not a good model.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"Consider the ring R = mathbbZnmathbbZ for a multiprecision integer n. If we were to model the ring R as a type, then the type would somehow need to contain the modulus n. This is not possible in Julia, and in fact it is not desirable, since the compiler would then recompile all the associated functions every time a different modulus n was used.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"We could attach the modulus n to the objects representing elements of the ring, rather than their type.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"But now we cannot create new elements of the ring mathbbZnmathbbZ given only their type, since the type no longer contains the modulus n.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"Instead, the way we get around this in AbstractAlgebra.jl is to have special (singleton) objects that act like types, but are really just ordinary Julia objects. These objects, called parent objects, can contain extra information, such as the modulus n. In return, we associate this parent object with so called element objects.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"In order to create new elements of mathbbZnmathbbZ as above, we overload the call operator for the parent object.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"In the following AbstractAlgebra.jl example, we create the parent object R corresponding to the ring mathbbZ7mathbbZ. We then create a new element a of this ring by calling the parent object R.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"R, = residue_ring(ZZ, 7)\na = R(3)","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"Here, R is the parent object, containing the modulus 7. So this example creates the element a = 3 pmod7.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"Objects known as parents which contain additional information about groups, rings, fields and modules, etc., that can't be stored in types alone.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"These details are technical and can be skipped or skimmed by new users of Julia/AbstractAlgebra.jl. Types are almost never dealt with directly when scripting AbstractAlgebra.jl to do mathematical computations.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"In contrast, AbstractAlgebra.jl developers will want to know how we model mathematical objects and their rings, fields, groups, etc.","category":"page"},{"location":"types/#The-abstract-type-hierarchy-in-AbstractAlgebra.jl","page":"Type interface of AbstractAlgebra.jl","title":"The abstract type hierarchy in AbstractAlgebra.jl","text":"","category":"section"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"In AbstractAlgebra.jl, we use the abstract type hierarchy in order to give structure when programming the mathematical structures. For example, abstract types in Julia can belong to one another in a hierarchy.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"For example, the Field abstract type belongs to the Ring abstract type. The full hierarchy can be seen in diagrams under the section on visualisation of the abstract types.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"In practice this is practical since it means that any generic function designed to work with ring objects will also work with field objects.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"In AbstractAlgebra.jl we also distinguish between the elements of a field, say, and the field itself.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"For example, we have an object of type Generic.PolyRing to model a generic polynomial ring, and elements of that polynomial ring would have type Generic.PolyRingElem.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"For this purpose, we also have a hierarchy of abstract types, such as FieldElem, that the types of element objects can belong to.","category":"page"},{"location":"types/#More-complex-example-of-parent-objects","page":"Type interface of AbstractAlgebra.jl","title":"More complex example of parent objects","text":"","category":"section"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"Here is some code which constructs a polynomial ring over the integers, a polynomial in that ring and then does some introspection to illustrate the various relations between the objects and types.","category":"page"},{"location":"types/","page":"Type interface of AbstractAlgebra.jl","title":"Type interface of AbstractAlgebra.jl","text":"julia> using AbstractAlgebra\n\njulia> R, x = ZZ[\"x\"]\n(Univariate polynomial ring in x over integers, x)\n\njulia> f = x^2 + 3x + 1\nx^2 + 3*x + 1\n\njulia> R isa PolyRing\ntrue\n\njulia> f isa PolyRingElem\ntrue\n\njulia> parent(f) == R\ntrue","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"polynomial/#Univariate-polynomial-functionality","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"AbstractAlgebra.jl provides a module, implemented in src/Poly.jl for polynomials over any commutative ring belonging to the AbstractAlgebra abstract type hierarchy. This functionality will work for any univariate polynomial type which follows the Univariate Polynomial Ring interface.","category":"page"},{"location":"polynomial/#Generic-univariate-polynomial-types","page":"Univariate polynomial functionality","title":"Generic univariate polynomial types","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"AbstractAlgebra.jl provides a generic polynomial type based on Julia arrays which is implemented in src/generic/Poly.jl.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"These generic polynomials have type Generic.Poly{T} where T is the type of elements of the coefficient ring. Internally they consist of a Julia array of coefficients and some additional fields for length and a parent object, etc. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Parent objects of such polynomials have type Generic.PolyRing{T}.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"The string representation of the variable of the polynomial ring and the base/coefficient ring R is stored in the parent object.","category":"page"},{"location":"polynomial/#Abstract-types","page":"Univariate polynomial functionality","title":"Abstract types","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"All univariate polynomial element types belong to the abstract type PolyRingElem{T} and the polynomial ring types belong to the abstract type PolyRing{T}. This enables one to write generic functions that can accept any AbstractAlgebra polynomial type.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"note: Note\nBoth the generic polynomial ring type Generic.PolyRing{T} and the abstract type it belongs to, PolyRing{T}, are called PolyRing. The former is a (parameterised) concrete type for a polynomial ring over a given base ring whose elements have type T. The latter is an abstract type representing all polynomial ring types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).","category":"page"},{"location":"polynomial/#Polynomial-ring-constructors","page":"Univariate polynomial functionality","title":"Polynomial ring constructors","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"In order to construct polynomials in AbstractAlgebra.jl, one must first construct the polynomial ring itself. This is accomplished with the following constructor.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"polynomial_ring(R::NCRing, s::VarName; cached::Bool = true)","category":"page"},{"location":"polynomial/#AbstractAlgebra.polynomial_ring-Tuple{NCRing, Union{Char, AbstractString, Symbol}}-polynomial","page":"Univariate polynomial functionality","title":"AbstractAlgebra.polynomial_ring","text":"polynomial_ring(R::NCRing, s::VarName = :x; cached::Bool = true)\n\nGiven a base ring R and symbol/string s specifying how the generator (variable) should be printed, return a tuple S, x representing the new polynomial ring S = Rx and the generator x of the ring.\n\nBy default the parent object S depends only on R and x and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.\n\nExamples\n\njulia> R, x = polynomial_ring(ZZ, :x)\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, :y)\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"A shorthand version of this function is provided: given a base ring R, we abbreviate the constructor as follows.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"R[:x]","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"It is also possible to create a polynomial ring with default symbol as follows. This is a lightweight constructor and should be used in generic algorithms wherever possible when creating polynomial rings where the symbol does not matter.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"PolyRing(R::Ring)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Given a base ring R return the polynomial ring S = Rx. Note that unlike the constructors above, the return type is not a tuple. Only the ring is returned and not the generator. The polynomial ring is not cached.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Here are some examples of creating polynomial rings and their associated generators.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> T, z = QQ[\"z\"]\n(Univariate polynomial ring in z over rationals, z)\n\njulia> U = PolyRing(ZZ)\nUnivariate polynomial ring in x over integers","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"All of the examples here are generic polynomial rings, but specialised implementations of polynomial rings provided by external modules will also usually provide a polynomial_ring constructor to allow creation of their polynomial rings.","category":"page"},{"location":"polynomial/#Polynomial-constructors","page":"Univariate polynomial functionality","title":"Polynomial constructors","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Once a polynomial ring is constructed, there are various ways to construct polynomials in that ring.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"The easiest way is simply using the generator returned by the polynomial_ring constructor and build up the polynomial using basic arithmetic.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"The Julia language has special syntax for the construction of polynomials in terms of a generator, e.g. we can write 2x instead of 2*x.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"A second way is to use the polynomial ring to construct a polynomial. There are the usual ways of constructing an element of a ring.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"(R::PolyRing)() # constructs zero\n(R::PolyRing)(c::Integer)\n(R::PolyRing)(c::elem_type(R))\n(R::PolyRing{T})(a::T) where T <: RingElement","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"For polynommials there is also the following more general constructor accepting an array of coefficients.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"(S::PolyRing{T})(A::Vector{T}) where T <: RingElem\n(S::PolyRing{T})(A::Vector{U}) where T <: RingElem, U <: RingElem\n(S::PolyRing{T})(A::Vector{U}) where T <: RingElem, U <: Integer","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Construct the polynomial in the ring S with the given array of coefficients, i.e. where A[1] is the constant coefficient.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"A third way of constructing polynomials is to construct them directly without creating the polynomial ring.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"polynomial(R::Ring, arr::Vector{T}, var::VarName=:x; cached::Bool=true)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Given an array of coefficients construct the polynomial with those coefficients over the given ring and with the given variable.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> f = x^3 + 3x + 21\nx^3 + 3*x + 21\n\njulia> g = (x + 1)*y^2 + 2x + 1\n(x + 1)*y^2 + 2*x + 1\n\njulia> R()\n0\n\njulia> S(1)\n1\n\njulia> S(y)\ny\n\njulia> S(x)\nx\n\njulia> S, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> f = S(Rational{BigInt}[2, 3, 1])\nx^2 + 3*x + 2\n\njulia> g = S(BigInt[1, 0, 4])\n4*x^2 + 1\n\njulia> h = S([4, 7, 2, 9])\n9*x^3 + 2*x^2 + 7*x + 4\n\njulia> p = polynomial(ZZ, [1, 2, 3])\n3*x^2 + 2*x + 1\n\njulia> f = polynomial(ZZ, [1, 2, 3], \"y\")\n3*y^2 + 2*y + 1","category":"page"},{"location":"polynomial/#Similar-and-zero","page":"Univariate polynomial functionality","title":"Similar and zero","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Another way of constructing polynomials is to construct one similar to an existing polynomial using either similar or zero. ","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"similar(x::MyPoly{T}, R::Ring=base_ring(x)) where T <: RingElem\nzero(x::MyPoly{T}, R::Ring=base_ring(x)) where T <: RingElem","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Construct the zero polynomial with the same variable as the given polynomial with coefficients in the given ring. Both functions behave the same way for polynomials.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"similar(x::MyPoly{T}, R::Ring, var::VarName=var(parent(x))) where T <: RingElem\nsimilar(x::MyPoly{T}, var::VarName=var(parent(x))) where T <: RingElem\nzero(x::MyPoly{T}, R::Ring, var::VarName=var(parent(x))) where T <: RingElem\nzero(x::MyPoly{T}, var::VarName=var(parent(x))) where T <: RingElem","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Construct the zero polynomial with the given variable and coefficients in the given ring, if specified, and in the coefficient ring of the given polynomial otherwise.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> f = 1 + 2x + 3x^2\n3*x^2 + 2*x + 1\n\njulia> g = similar(f)\n0\n\njulia> h = similar(f, QQ)\n0\n\njulia> k = similar(f, QQ, \"y\")\n0","category":"page"},{"location":"polynomial/#Functions-for-types-and-parents-of-polynomial-rings","page":"Univariate polynomial functionality","title":"Functions for types and parents of polynomial rings","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"base_ring(R::PolyRing)\nbase_ring(a::PolyRingElem)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Return the coefficient ring of the given polynomial ring or polynomial.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"parent(a::NCRingElement)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Return the polynomial ring of the given polynomial..","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"characteristic(R::NCRing)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Return the characteristic of the given polynomial ring. If the characteristic is not known, an exception is raised.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> U = base_ring(S)\nUnivariate polynomial ring in x over integers\n\njulia> V = base_ring(y + 1)\nUnivariate polynomial ring in x over integers\n\njulia> T = parent(y + 1)\nUnivariate polynomial ring in y over univariate polynomial ring","category":"page"},{"location":"polynomial/#Euclidean-polynomial-rings","page":"Univariate polynomial functionality","title":"Euclidean polynomial rings","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"For polynomials over a field, the Euclidean Ring Interface is implemented.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"mod(f::PolyRingElem, g::PolyRingElem)\ndivrem(f::PolyRingElem, g::PolyRingElem)\ndiv(f::PolyRingElem, g::PolyRingElem)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"mulmod(f::PolyRingElem, g::PolyRingElem, m::PolyRingElem)\npowermod(f::PolyRingElem, e::Int, m::PolyRingElem)\ninvmod(f::PolyRingElem, m::PolyRingElem)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"divides(f::PolyRingElem, g::PolyRingElem)\nremove(f::PolyRingElem, p::PolyRingElem)\nvaluation(f::PolyRingElem, p::PolyRingElem)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"gcd(f::PolyRingElem, g::PolyRingElem)\nlcm(f::PolyRingElem, g::PolyRingElem)\ngcdx(f::PolyRingElem, g::PolyRingElem)\ngcdinv(f::PolyRingElem, g::PolyRingElem)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S, = residue_ring(R, x^3 + 3x + 1);\n\njulia> T, y = polynomial_ring(S, \"y\")\n(Univariate polynomial ring in y over residue ring, y)\n\njulia> f = (3*x^2 + x + 2)*y + x^2 + 1\n(3*x^2 + x + 2)*y + x^2 + 1\n\njulia> g = (5*x^2 + 2*x + 1)*y^2 + 2x*y + x + 1\n(5*x^2 + 2*x + 1)*y^2 + 2*x*y + x + 1\n\njulia> h = (3*x^3 + 2*x^2 + x + 7)*y^5 + 2x*y + 1\n(2*x^2 - 8*x + 4)*y^5 + 2*x*y + 1\n\njulia> invmod(f, g)\n(707//3530*x^2 + 2151//1765*x + 123//3530)*y - 178//1765*x^2 - 551//3530*x + 698//1765\n\njulia> mulmod(f, g, h)\n(-30*x^2 - 43*x - 9)*y^3 + (-7*x^2 - 23*x - 7)*y^2 + (4*x^2 - 10*x - 3)*y + x^2 - 2*x\n\njulia> powermod(f, 3, h)\n(69*x^2 + 243*x + 79)*y^3 + (78*x^2 + 180*x + 63)*y^2 + (27*x^2 + 42*x + 18)*y + 3*x^2 + 3*x + 2\n\njulia> h = mod(f, g)\n(3*x^2 + x + 2)*y + x^2 + 1\n\njulia> q, r = divrem(f, g)\n(0, (3*x^2 + x + 2)*y + x^2 + 1)\n\njulia> div(g, f)\n(-5//11*x^2 + 2//11*x + 6//11)*y - 13//121*x^2 - 3//11*x - 78//121\n\njulia> d = gcd(f*h, g*h)\ny + 1//11*x^2 + 6//11\n\njulia> k = gcdinv(f, h)\n(y + 1//11*x^2 + 6//11, 0)\n\njulia> m = lcm(f, h)\n(-14*x^2 - 23*x - 2)*y - 4*x^2 - 5*x + 1\n\njulia> flag, q = divides(g^2, g)\n(true, (5*x^2 + 2*x + 1)*y^2 + 2*x*y + x + 1)\n\njulia> valuation(3g^3, g) == 3\ntrue\n\njulia> val, q = remove(5g^3, g)\n(3, 5)\n\njulia> r, s, t = gcdx(g, h)\n(1, 311//3530*x^2 - 2419//3530*x + 947//1765, (707//3530*x^2 + 2151//1765*x + 123//3530)*y - 178//1765*x^2 - 551//3530*x + 698//1765)\n","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Functions in the Euclidean Ring interface are supported over residue rings that are not fields, except that if an impossible inverse is encountered during the computation an error is thrown.","category":"page"},{"location":"polynomial/#Polynomial-functions","page":"Univariate polynomial functionality","title":"Polynomial functions","text":"","category":"section"},{"location":"polynomial/#Basic-functionality","page":"Univariate polynomial functionality","title":"Basic functionality","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"All basic ring functionality is provided for polynomials. The most important such functions are the following.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"zero(R::PolyRing)\none(R::PolyRing)\niszero(a::PolyRingElem)\nisone(a::PolyRingElem)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"divexact(a::T, b::T) where T <: PolyRingElem","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"All functions in the polynomial interface are provided. The most important are the following.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"var(S::PolyRing)\nsymbols(S::PolyRing{T}) where T <: RingElem","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Return a symbol or length 1 array of symbols, respectively, specifying the variable of the polynomial ring. This symbol is converted to a string when printing polynomials in that ring.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"In addition, the following basic functions are provided.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"modulus{T <: ResElem}(::PolyRingElem{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.modulus-Union{Tuple{PolyRingElem{T}}, Tuple{T}} where T<:ResElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.modulus","text":"modulus(a::PolyRingElem{T}) where {T <: ResElem}\n\nReturn the modulus of the coefficients of the given polynomial.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"leading_coefficient(::PolyRingElem)\ntrailing_coefficient(::PolyRingElem)\nconstant_coefficient(::PolynomialElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.leading_coefficient-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.leading_coefficient","text":"leading_coefficient(a::PolynomialElem)\n\nReturn the leading coefficient of the given polynomial. This will be the nonzero coefficient of the term with highest degree unless the polynomial in the zero polynomial, in which case a zero coefficient is returned.\n\n\n\n\n\nleading_coefficient(p::MPolyRingElem)\n\nReturn the leading coefficient of the polynomial p.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#AbstractAlgebra.trailing_coefficient-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.trailing_coefficient","text":"trailing_coefficient(a::PolynomialElem)\n\nReturn the trailing coefficient of the given polynomial. This will be the nonzero coefficient of the term with lowest degree unless the polynomial is the zero polynomial, in which case a zero coefficient is returned.\n\n\n\n\n\ntrailing_coefficient(p::MPolyRingElem)\n\nReturn the trailing coefficient of the polynomial p, i.e. the coefficient of the last nonzero term, or zero if the polynomial is zero.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#AbstractAlgebra.constant_coefficient-Tuple{PolynomialElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.constant_coefficient","text":"constant_coefficient(a::PolynomialElem)\n\nReturn the constant coefficient of the given polynomial. If the polynomial is the zero polynomial, the function will return zero.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"set_coefficient!(::PolynomialElem{T}, ::Int, c::T) where T <: RingElement","category":"page"},{"location":"polynomial/#AbstractAlgebra.set_coefficient!-Union{Tuple{T}, Tuple{PolynomialElem{T}, Int64, T}} where T<:RingElement","page":"Univariate polynomial functionality","title":"AbstractAlgebra.set_coefficient!","text":"set_coefficient!(c::PolynomialElem{T}, n::Int, a::T) where T <: RingElement\nset_coefficient!(c::PolynomialElem{T}, n::Int, a::U) where {T <: RingElement, U <: Integer}\n\nSet the coefficient of degree n to a.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"tail(::PolynomialElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.tail-Tuple{PolynomialElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.tail","text":"tail(a::PolynomialElem)\n\nReturn the tail of the given polynomial, i.e. the polynomial without its leading term (if any).\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"gen(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.gen-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.gen","text":"gen(a::MPolyRing{T}, i::Int) where {T <: RingElement}\n\nReturn the i-th generator (variable) of the given polynomial ring.\n\n\n\n\n\ngen(R::AbsPowerSeriesRing{T}) where T <: RingElement\n\nReturn the generator of the power series ring, i.e. x + O(x^n) where n is the precision of the power series ring R.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"is_gen(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.is_gen-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.is_gen","text":"is_gen(a::PolynomialElem)\n\nReturn true if the given polynomial is the constant generator of its polynomial ring, otherwise return false.\n\n\n\n\n\nis_gen(x::MPoly{T}) where {T <: RingElement}\n\nReturn true if the given polynomial is a generator (variable) of the polynomial ring it belongs to.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"is_monic(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.is_monic-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.is_monic","text":"is_monic(a::PolynomialElem)\n\nReturn true if the given polynomial is monic, i.e. has leading coefficient equal to one, otherwise return false.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"is_square(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.is_square-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.is_square","text":"is_square(f::PolyRingElem{T}) where T <: RingElement\n\nReturn true if f is a perfect square.\n\n\n\n\n\nis_square(a::FracElem{T}) where T <: RingElem\n\nReturn true if a is a square.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"length(::PolynomialElem)","category":"page"},{"location":"polynomial/#Base.length-Tuple{PolynomialElem}","page":"Univariate polynomial functionality","title":"Base.length","text":"length(a::PolynomialElem)\n\nReturn the length of the polynomial. The length of a univariate polynomial is defined to be the number of coefficients in its dense representation, including zero coefficients. Thus naturally the zero polynomial has length zero and additionally for nonzero polynomials the length is one more than the degree. (Note that the leading coefficient will always be nonzero.)\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"degree(::PolynomialElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.degree-Tuple{PolynomialElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.degree","text":"degree(a::PolynomialElem)\n\nReturn the degree of the given polynomial. This is defined to be one less than the length, even for constant polynomials.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"is_monomial(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.is_monomial-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.is_monomial","text":"is_monomial(a::PolynomialElem)\n\nReturn true if the given polynomial is a monomial.\n\n\n\n\n\nis_monomial(x::MPolyRingElem)\n\nReturn true if the given polynomial has precisely one term whose coefficient is one.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"is_monomial_recursive(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.is_monomial_recursive-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.is_monomial_recursive","text":"is_monomial_recursive(a::PolynomialElem)\n\nReturn true if the given polynomial is a monomial. This function is recursive, with all scalar types returning true.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"is_term(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.is_term-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.is_term","text":"is_term(a::PolynomialElem)\n\nReturn true if the given polynomial has one term.\n\n\n\n\n\nis_term(x::MPolyRingElem)\n\nReturn true if the given polynomial has precisely one term.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"is_term_recursive(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.is_term_recursive-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.is_term_recursive","text":"is_term_recursive(a::PolynomialElem)\n\nReturn true if the given polynomial has one term. This function is recursive, with all scalar types returning true.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"is_constant(::PolynomialElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.is_constant-Tuple{PolynomialElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.is_constant","text":"is_constant(a::PolynomialElem)\n\nReturn true if a is a degree zero polynomial or the zero polynomial, i.e. a constant polynomial.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> T, z = polynomial_ring(QQ, \"z\")\n(Univariate polynomial ring in z over rationals, z)\n\njulia> U, = residue_ring(ZZ, 17);\n\njulia> V, w = polynomial_ring(U, \"w\")\n(Univariate polynomial ring in w over residue ring, w)\n\njulia> var(R)\n:x\n\njulia> symbols(R)\n1-element Vector{Symbol}:\n :x\n\njulia> a = zero(S)\n0\n\njulia> b = one(S)\n1\n\njulia> isone(b)\ntrue\n\njulia> c = BigInt(1)//2*z^2 + BigInt(1)//3\n1//2*z^2 + 1//3\n\njulia> d = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + 3\n\njulia> f = leading_coefficient(d)\nx\n\njulia> y = gen(S)\ny\n\njulia> g = is_gen(w)\ntrue\n\njulia> divexact((2x + 1)*(x + 1), (x + 1))\n2*x + 1\n\njulia> m = is_unit(b)\ntrue\n\njulia> n = degree(d)\n2\n\njulia> r = modulus(w)\n17\n\njulia> is_term(2y^2)\ntrue\n\njulia> is_monomial(y^2)\ntrue\n\njulia> is_monomial_recursive(x*y^2)\ntrue\n\njulia> is_monomial(x*y^2)\nfalse\n\njulia> S, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> f = x^3 + 3x + 1\nx^3 + 3*x + 1\n\njulia> g = S(BigInt[1, 2, 0, 1, 0, 0, 0]);\n\njulia> n = length(f)\n4\n\njulia> c = coeff(f, 1)\n3\n\njulia> g = set_coefficient!(g, 2, ZZ(11))\nx^3 + 11*x^2 + 2*x + 1\n\njulia> g = set_coefficient!(g, 7, ZZ(4))\n4*x^7 + x^3 + 11*x^2 + 2*x + 1","category":"page"},{"location":"polynomial/#Iterators","page":"Univariate polynomial functionality","title":"Iterators","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"An iterator is provided to return the coefficients of a univariate polynomial. The iterator is called coefficients and allows iteration over the coefficients, starting with the term of degree zero (if there is one). Note that coefficients of each degree are given, even if they are zero. This is best illustrated by example.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> f = x^2 + 2\nx^2 + 2\n\njulia> C = collect(coefficients(f))\n3-element Vector{BigInt}:\n 2\n 0\n 1\n\njulia> for c in coefficients(f)\n println(c)\n end\n2\n0\n1","category":"page"},{"location":"polynomial/#Truncation","page":"Univariate polynomial functionality","title":"Truncation","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"truncate(::PolyRingElem, ::Int)","category":"page"},{"location":"polynomial/#Base.truncate-Tuple{PolyRingElem, Int64}","page":"Univariate polynomial functionality","title":"Base.truncate","text":"truncate(a::PolynomialElem, n::Int)\n\nReturn a truncated to n terms, i.e. the remainder upon division by x^n.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"mullow{T <: RingElem}(::PolyRingElem{T}, ::PolyRingElem{T}, ::Int)","category":"page"},{"location":"polynomial/#AbstractAlgebra.mullow-Union{Tuple{T}, Tuple{PolyRingElem{T}, PolyRingElem{T}, Int64}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.mullow","text":"mullow(a::PolyRingElem{T}, b::PolyRingElem{T}, n::Int) where T <: RingElement\n\nReturn atimes b truncated to n terms.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + 3\n\njulia> g = (x + 1)*y + (x^3 + 2x + 2)\n(x + 1)*y + x^3 + 2*x + 2\n\njulia> h = truncate(f, 1)\n3\n\njulia> k = mullow(f, g, 4)\n(x^2 + x)*y^3 + (x^4 + 3*x^2 + 4*x + 1)*y^2 + (x^4 + x^3 + 2*x^2 + 7*x + 5)*y + 3*x^3 + 6*x + 6\n","category":"page"},{"location":"polynomial/#Reversal","page":"Univariate polynomial functionality","title":"Reversal","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"reverse(::PolyRingElem, ::Int)\nreverse(::PolyRingElem)","category":"page"},{"location":"polynomial/#Base.reverse-Tuple{PolyRingElem, Int64}","page":"Univariate polynomial functionality","title":"Base.reverse","text":"reverse(x::PolynomialElem, len::Int)\n\nReturn the reverse of the polynomial x, thought of as a polynomial of the given length (the polynomial will be notionally truncated or padded with zeroes before the leading term if necessary to match the specified length). The resulting polynomial is normalised. If len is negative we throw a DomainError().\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#Base.reverse-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"Base.reverse","text":"reverse(x::PolynomialElem)\n\nReturn the reverse of the polynomial x, i.e. the leading coefficient of x becomes the constant coefficient of the result, etc. The resulting polynomial is normalised.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + 3\n\njulia> g = reverse(f, 7)\n3*y^6 + (x + 1)*y^5 + x*y^4\n\njulia> h = reverse(f)\n3*y^2 + (x + 1)*y + x\n","category":"page"},{"location":"polynomial/#Shifting","page":"Univariate polynomial functionality","title":"Shifting","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"shift_left(::PolyRingElem, ::Int)","category":"page"},{"location":"polynomial/#AbstractAlgebra.shift_left-Tuple{PolyRingElem, Int64}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.shift_left","text":"shift_left(f::PolynomialElem, n::Int)\n\nReturn the polynomial f shifted left by n terms, i.e. multiplied by x^n.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"shift_right(::PolyRingElem, ::Int)","category":"page"},{"location":"polynomial/#AbstractAlgebra.shift_right-Tuple{PolyRingElem, Int64}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.shift_right","text":"shift_right(f::PolynomialElem, n::Int)\n\nReturn the polynomial f shifted right by n terms, i.e. divided by x^n.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + 3\n\njulia> g = shift_left(f, 7)\nx*y^9 + (x + 1)*y^8 + 3*y^7\n\njulia> h = shift_right(f, 2)\nx\n","category":"page"},{"location":"polynomial/#Inflation-and-deflation","page":"Univariate polynomial functionality","title":"Inflation and deflation","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"deflation(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.deflation-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.deflation","text":"deflation(p::PolyRingElem)\n\nReturn a tuple (shift, defl) where shift is the exponent of the trailing term of p and defl is the gcd of the distance between the exponents of the nonzero terms of p. If p = 0, both shift and defl will be zero.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"inflate(::PolyRingElem, ::Int, ::Int)\ninflate(::PolyRingElem, ::Int)","category":"page"},{"location":"polynomial/#AbstractAlgebra.inflate-Tuple{PolyRingElem, Int64, Int64}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.inflate","text":"inflate(f::PolyRingElem, shift::Int64, n::Int64) -> PolyRingElem\n\nGiven a polynomial f in x, return f(x^n)*x^j, i.e. multiply all exponents by n and shift f left by j.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#AbstractAlgebra.inflate-Tuple{PolyRingElem, Int64}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.inflate","text":"inflate(f::PolyRingElem, n::Int64) -> PolyRingElem\n\nGiven a polynomial f in x, return f(x^n), i.e. multiply all exponents by n.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"deflate(::PolyRingElem, ::Int, ::Int)\ndeflate(::PolyRingElem, ::Int)\ndeflate(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.deflate-Tuple{PolyRingElem, Int64, Int64}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.deflate","text":"deflate(f::PolyRingElem, shift::Int64, n::Int64) -> PolyRingElem\n\nGiven a polynomial g in x^n such that f = g(x)*x^{shift}, write f as a polynomial in x, i.e. divide all exponents of g by n.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#AbstractAlgebra.deflate-Tuple{PolyRingElem, Int64}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.deflate","text":"deflate(f::PolyRingElem, n::Int64) -> PolyRingElem\n\nGiven a polynomial f in x^n, write it as a polynomial in x, i.e. divide all exponents by n.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#AbstractAlgebra.deflate-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.deflate","text":"deflate(x::PolyRingElem) -> PolyRingElem, Int\n\nDeflate the polynomial f maximally, i.e. find the largest n s.th. f can be deflated by n, i.e. f is actually a polynomial in x^n. Return g n where g is the deflation of f.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#Square-root","page":"Univariate polynomial functionality","title":"Square root","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Base.sqrt(::PolyRingElem{T}; check::Bool) where T <: RingElement","category":"page"},{"location":"polynomial/#Base.sqrt-Union{Tuple{PolyRingElem{T}}, Tuple{T}} where T<:RingElement","page":"Univariate polynomial functionality","title":"Base.sqrt","text":"Base.sqrt(f::PolyRingElem{T}; check::Bool=true) where T <: RingElement\n\nReturn the square root of f. By default the function checks the input is square and raises an exception if not. If check=false this check is omitted.\n\n\n\n\n\nsqrt(a::Generic.PuiseuxSeriesElem{T}; check::Bool=true) where T <: RingElement\n\nReturn the square root of the given Puiseux series a. By default the function will throw an exception if the input is not square. If check=false this test is omitted.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"R, x = polynomial_ring(ZZ, \"x\")\ng = x^2+6*x+1\nsqrt(g^2)","category":"page"},{"location":"polynomial/#Change-of-base-ring","page":"Univariate polynomial functionality","title":"Change of base ring","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"change_base_ring(::Ring, ::PolyRingElem{T}) where T <: RingElement\nchange_coefficient_ring(::Ring, ::PolyRingElem{T}) where T <: RingElement\nmap_coefficients(::Any, ::PolyRingElem{<:RingElement})","category":"page"},{"location":"polynomial/#AbstractAlgebra.change_base_ring-Union{Tuple{T}, Tuple{Ring, PolyRingElem{T}}} where T<:RingElement","page":"Univariate polynomial functionality","title":"AbstractAlgebra.change_base_ring","text":"change_base_ring(R::Ring, p::PolyRingElem{<: RingElement}; parent::PolyRing)\n\nReturn the polynomial obtained by coercing the non-zero coefficients of p into R.\n\nIf the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#AbstractAlgebra.change_coefficient_ring-Union{Tuple{T}, Tuple{Ring, PolyRingElem{T}}} where T<:RingElement","page":"Univariate polynomial functionality","title":"AbstractAlgebra.change_coefficient_ring","text":"change_coefficient_ring(R::Ring, p::PolyRingElem{<: RingElement}; parent::PolyRing)\n\nReturn the polynomial obtained by coercing the non-zero coefficients of p into R.\n\nIf the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#AbstractAlgebra.map_coefficients-Tuple{Any, PolyRingElem{<:RingElement}}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.map_coefficients","text":"map_coefficients(f, p::PolyRingElem{<: RingElement}; cached::Bool=true, parent::PolyRing)\n\nTransform the polynomial p by applying f on each non-zero coefficient.\n\nIf the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"R, x = polynomial_ring(ZZ, \"x\")\ng = x^3+6*x + 1\nchange_base_ring(GF(2), g)\nchange_coefficient_ring(GF(2), g)","category":"page"},{"location":"polynomial/#Pseudodivision","page":"Univariate polynomial functionality","title":"Pseudodivision","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Given two polynomials a b, pseudodivision computes polynomials q and r with length(r) length(b) such that L^d a = bq + r where d = length(a) - length(b) + 1 and L is the leading coefficient of b.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"We call q the pseudoquotient and r the pseudoremainder.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"pseudorem{T <: RingElem}(::PolyRingElem{T}, ::PolyRingElem{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.pseudorem-Union{Tuple{T}, Tuple{PolyRingElem{T}, PolyRingElem{T}}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.pseudorem","text":"pseudorem(f::PolyRingElem{T}, g::PolyRingElem{T}) where T <: RingElement\n\nReturn the pseudoremainder of f divided by g. If g = 0 we throw a DivideError().\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"pseudodivrem{T <: RingElem}(::PolyRingElem{T}, ::PolyRingElem{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.pseudodivrem-Union{Tuple{T}, Tuple{PolyRingElem{T}, PolyRingElem{T}}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.pseudodivrem","text":"pseudodivrem(f::PolyRingElem{T}, g::PolyRingElem{T}) where T <: RingElement\n\nReturn a tuple (q r) consisting of the pseudoquotient and pseudoremainder of f divided by g. If g = 0 we throw a DivideError().\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + 3\n\njulia> g = (x + 1)*y + (x^3 + 2x + 2)\n(x + 1)*y + x^3 + 2*x + 2\n\njulia> h = pseudorem(f, g)\nx^7 + 3*x^5 + 2*x^4 + x^3 + 5*x^2 + 4*x + 1\n\njulia> q, r = pseudodivrem(f, g)\n((x^2 + x)*y - x^4 - x^2 + 1, x^7 + 3*x^5 + 2*x^4 + x^3 + 5*x^2 + 4*x + 1)\n","category":"page"},{"location":"polynomial/#Content-and-primitive-part","page":"Univariate polynomial functionality","title":"Content and primitive part","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"content(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.content-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.content","text":"content(a::PolyRingElem)\n\nReturn the content of a, i.e. the greatest common divisor of its coefficients.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"primpart(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.primpart-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.primpart","text":"primpart(a::PolyRingElem)\n\nReturn the primitive part of a, i.e. the polynomial divided by its content.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"R, x = polynomial_ring(ZZ, \"x\")\nS, y = polynomial_ring(R, \"y\")\n\nk = x*y^2 + (x + 1)*y + 3\n\nn = content(k)\np = primpart(k*(x^2 + 1))","category":"page"},{"location":"polynomial/#Evaluation,-composition-and-substitution","page":"Univariate polynomial functionality","title":"Evaluation, composition and substitution","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"evaluate(::PolyRingElem, b::T) where T <: RingElement","category":"page"},{"location":"polynomial/#AbstractAlgebra.evaluate-Union{Tuple{T}, Tuple{PolyRingElem, T}} where T<:RingElement","page":"Univariate polynomial functionality","title":"AbstractAlgebra.evaluate","text":"evaluate(a::PolyRingElem, b::T) where T <: RingElement\n\nEvaluate the polynomial expression a at the value b and return the result.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"compose(::PolyRingElem, ::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.compose-Tuple{PolyRingElem, PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.compose","text":"compose(a::PolyRingElem, b::PolyRingElem)\n\nCompose the polynomial a with the polynomial b and return the result, i.e. return acirc b.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"subst{T <: RingElem}(::PolyRingElem{T}, ::Any)","category":"page"},{"location":"polynomial/#AbstractAlgebra.subst-Union{Tuple{T}, Tuple{PolyRingElem{T}, Any}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.subst","text":"subst(f::PolyRingElem{T}, a::Any) where T <: RingElement\n\nEvaluate the polynomial f at a. Note that a can be anything, whether a ring element or not.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"We also overload the functional notation so that the polynomial f can be evaluated at a by writing f(a).","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + 3\n\njulia> g = (x + 1)*y + (x^3 + 2x + 2)\n(x + 1)*y + x^3 + 2*x + 2\n\njulia> M = R[x + 1 2x; x - 3 2x - 1]\n[x + 1 2*x]\n[x - 3 2*x - 1]\n\njulia> k = evaluate(f, 3)\n12*x + 6\n\njulia> m = evaluate(f, x^2 + 2x + 1)\nx^5 + 4*x^4 + 7*x^3 + 7*x^2 + 4*x + 4\n\njulia> n = compose(f, g)\n(x^3 + 2*x^2 + x)*y^2 + (2*x^5 + 2*x^4 + 4*x^3 + 9*x^2 + 6*x + 1)*y + x^7 + 4*x^5 + 5*x^4 + 5*x^3 + 10*x^2 + 8*x + 5\n\njulia> p = subst(f, M)\n[3*x^3 - 3*x^2 + 3*x + 4 6*x^3 + 2*x^2 + 2*x]\n[3*x^3 - 8*x^2 - 2*x - 3 6*x^3 - 8*x^2 + 2*x + 2]\n\njulia> q = f(M)\n[3*x^3 - 3*x^2 + 3*x + 4 6*x^3 + 2*x^2 + 2*x]\n[3*x^3 - 8*x^2 - 2*x - 3 6*x^3 - 8*x^2 + 2*x + 2]\n\njulia> r = f(23)\n552*x + 26\n","category":"page"},{"location":"polynomial/#Derivative-and-integral","page":"Univariate polynomial functionality","title":"Derivative and integral","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"derivative(::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.derivative-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.derivative","text":"derivative(a::PolynomialElem)\n\nReturn the derivative of the polynomial a.\n\n\n\n\n\nderivative(f::AbsPowerSeriesRingElem{T})\n\nReturn the derivative of the power series f.\n\n\n\n\n\nderivative(f::RelPowerSeriesRingElem{T})\n\nReturn the derivative of the power series f.\n\njulia> R, x = power_series_ring(QQ, 10, \"x\")\n(Univariate power series ring in x over Rationals, x + O(x^11))\n\njulia> f = 2 + x + 3x^3\n2 + x + 3*x^3 + O(x^10)\n\njulia> derivative(f)\n1 + 9*x^2 + O(x^9)\n\n\n\n\n\nderivative(f::MPolyRingElem{T}, j::Int) where {T <: RingElement}\n\nReturn the partial derivative of f with respect to j-th variable of the polynomial ring.\n\n\n\n\n\nderivative(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement\n\nReturn the partial derivative of f with respect to x. The value x must be a generator of the polynomial ring of f.\n\n\n\n\n\nderivative(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the derivative of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"integral{T <: Union{ResElem, FieldElem}}(::PolyRingElem{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.integral-Union{Tuple{PolyRingElem{T}}, Tuple{T}} where T<:Union{FieldElem, ResElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.integral","text":"integral(x::PolyRingElem{T}) where {T <: Union{ResElem, FieldElement}}\n\nReturn the integral of the polynomial x.\n\n\n\n\n\nintegral(f::AbsPowerSeriesRingElem{T})\n\nReturn the integral of the power series f.\n\n\n\n\n\nintegral(f::RelPowerSeriesRingElem{T})\n\nReturn the integral of the power series f.\n\njulia> R, x = power_series_ring(QQ, 10, \"x\")\n(Univariate power series ring in x over Rationals, x + O(x^11))\n\njulia> f = 2 + x + 3x^3\n2 + x + 3*x^3 + O(x^10)\n\njulia> integral(f)\n2*x + 1//2*x^2 + 3//4*x^4 + O(x^11)\n\n\n\n\n\nintegral(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement\n\nReturn the integral of the given Puiseux series a.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> T, z = polynomial_ring(QQ, \"z\")\n(Univariate polynomial ring in z over rationals, z)\n\njulia> U, = residue_ring(T, z^3 + 3z + 1);\n\njulia> V, w = polynomial_ring(U, \"w\")\n(Univariate polynomial ring in w over residue ring, w)\n\njulia> f = x*y^2 + (x + 1)*y + 3\nx*y^2 + (x + 1)*y + 3\n\njulia> g = (z^2 + 2z + 1)*w^2 + (z + 1)*w - 2z + 4\n(z^2 + 2*z + 1)*w^2 + (z + 1)*w - 2*z + 4\n\njulia> h = derivative(f)\n2*x*y + x + 1\n\njulia> k = integral(g)\n(1//3*z^2 + 2//3*z + 1//3)*w^3 + (1//2*z + 1//2)*w^2 + (-2*z + 4)*w\n","category":"page"},{"location":"polynomial/#Resultant-and-discriminant","page":"Univariate polynomial functionality","title":"Resultant and discriminant","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"sylvester_matrix{T <: RingElem}(::PolyRingElem{T}, ::PolyRingElem{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.sylvester_matrix-Union{Tuple{T}, Tuple{PolyRingElem{T}, PolyRingElem{T}}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.sylvester_matrix","text":"sylvester_matrix(p::PolyRingElem, q::PolyRingElem)\n\nReturn the sylvester matrix of the given polynomials.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"resultant{T <: RingElem}(::PolyRingElem{T}, ::PolyRingElem{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.resultant-Union{Tuple{T}, Tuple{PolyRingElem{T}, PolyRingElem{T}}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.resultant","text":"resultant(p::PolyRingElem{T}, q::PolyRingElem{T}) where T <: RingElement\n\nReturn the resultant of the given polynomials.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"resx{T <: RingElem}(::PolyRingElem{T}, ::PolyRingElem{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.resx-Union{Tuple{T}, Tuple{PolyRingElem{T}, PolyRingElem{T}}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.resx","text":"resx(a::PolyRingElem{T}, b::PolyRingElem{T}) where T <: RingElement\n\nReturn a tuple (r s t) such that r is the resultant of a and b and such that r = atimes s + btimes t.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"discriminant(a::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.discriminant-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.discriminant","text":"discriminant(a::PolyRingElem)\n\nReturn the discriminant of the given polynomial.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> f = 3x*y^2 + (x + 1)*y + 3\n3*x*y^2 + (x + 1)*y + 3\n\njulia> g = 6(x + 1)*y + (x^3 + 2x + 2)\n(6*x + 6)*y + x^3 + 2*x + 2\n\njulia> S = sylvester_matrix(f, g)\n[ 3*x x + 1 3]\n[6*x + 6 x^3 + 2*x + 2 0]\n[ 0 6*x + 6 x^3 + 2*x + 2]\n\njulia> h = resultant(f, g)\n3*x^7 + 6*x^5 - 6*x^3 + 96*x^2 + 192*x + 96\n\njulia> k = discriminant(f)\nx^2 - 34*x + 1\n","category":"page"},{"location":"polynomial/#Newton-representation","page":"Univariate polynomial functionality","title":"Newton representation","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"monomial_to_newton!{T <: RingElem}(::Vector{T}, ::Vector{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.monomial_to_newton!-Union{Tuple{T}, Tuple{Vector{T}, Vector{T}}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.monomial_to_newton!","text":"monomial_to_newton!(P::Vector{T}, roots::Vector{T}) where T <: RingElement\n\nConverts a polynomial p, given as an array of coefficients, in-place from its coefficients given in the standard monomial basis to the Newton basis for the roots r_0 r_1 ldots r_n-2. In other words, this determines output coefficients c_i such that c_0 + c_1(x-r_0) + c_2(x-r_0)(x-r_1) + ldots + c_n-1(x-r_0)(x-r_1)cdots(x-r_n-2) is equal to the input polynomial.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"newton_to_monomial!{T <: RingElem}(::Vector{T}, ::Vector{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.newton_to_monomial!-Union{Tuple{T}, Tuple{Vector{T}, Vector{T}}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.newton_to_monomial!","text":"newton_to_monomial!(P::Vector{T}, roots::Vector{T}) where T <: RingElement\n\nConverts a polynomial p, given as an array of coefficients, in-place from its coefficients given in the Newton basis for the roots r_0 r_1 ldots r_n-2 to the standard monomial basis. In other words, this evaluates c_0 + c_1(x-r_0) + c_2(x-r_0)(x-r_1) + ldots + c_n-1(x-r_0)(x-r_1)cdots(x-r_n-2) where c_i are the input coefficients given by p.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> f = 3x*y^2 + (x + 1)*y + 3\n3*x*y^2 + (x + 1)*y + 3\n\njulia> g = deepcopy(f)\n3*x*y^2 + (x + 1)*y + 3\n\njulia> roots = [R(1), R(2), R(3)]\n3-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:\n 1\n 2\n 3\n\njulia> monomial_to_newton!(g.coeffs, roots)\n\njulia> newton_to_monomial!(g.coeffs, roots)","category":"page"},{"location":"polynomial/#Roots","page":"Univariate polynomial functionality","title":"Roots","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"roots(f::PolyRingElem)\nroots(R::Field, f::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.Generic.roots-Tuple{PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.Generic.roots","text":"roots(f::PolyRingElem)\n\nReturns the roots of the polynomial f in the base ring of f as an array.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#AbstractAlgebra.Generic.roots-Tuple{Field, PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.Generic.roots","text":"roots(R::Field, f::PolyRingElem)\n\nReturns the roots of the polynomial f in the field R as an array.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/#Interpolation","page":"Univariate polynomial functionality","title":"Interpolation","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"interpolate{T <: RingElem}(::PolyRing, ::Vector{T}, ::Vector{T})","category":"page"},{"location":"polynomial/#AbstractAlgebra.interpolate-Union{Tuple{T}, Tuple{PolyRing, Vector{T}, Vector{T}}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.interpolate","text":"interpolate(S::PolyRing, x::Vector{T}, y::Vector{T}) where T <: RingElement\n\nGiven two arrays of values xs and ys of the same length n, find the polynomial f in the polynomial ring R of length at most n such that f has the value ys at the points xs. The values in the arrays xs and ys must belong to the base ring of the polynomial ring R. If no such polynomial exists, an exception is raised.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> xs = [R(1), R(2), R(3), R(4)]\n4-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:\n 1\n 2\n 3\n 4\n\njulia> ys = [R(1), R(4), R(9), R(16)]\n4-element Vector{AbstractAlgebra.Generic.Poly{BigInt}}:\n 1\n 4\n 9\n 16\n\njulia> f = interpolate(S, xs, ys)\ny^2\n","category":"page"},{"location":"polynomial/#Power-sums","page":"Univariate polynomial functionality","title":"Power sums","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"polynomial_to_power_sums(::PolyRingElem{T}) where T <: RingElem","category":"page"},{"location":"polynomial/#AbstractAlgebra.polynomial_to_power_sums-Union{Tuple{PolyRingElem{T}}, Tuple{T}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.polynomial_to_power_sums","text":"polynomial_to_power_sums(f::PolyRingElem{T}, n::Int=degree(f)) where T <: RingElement -> Vector{T}\n\nUses Newton (or Newton-Girard) formulas to compute the first n sums of powers of the roots of f from the coefficients of f, starting with the sum of (first powers of) the roots. The input polynomial must be monic, at least degree 1 and have nonzero constant coefficient.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"power_sums_to_polynomial(::Vector{T}) where T <: RingElem","category":"page"},{"location":"polynomial/#AbstractAlgebra.power_sums_to_polynomial-Union{Tuple{Vector{T}}, Tuple{T}} where T<:RingElem","page":"Univariate polynomial functionality","title":"AbstractAlgebra.power_sums_to_polynomial","text":"power_sums_to_polynomial(P::Vector{T};\n parent::PolyRing{T}=PolyRing(parent(P[1])) where T <: RingElement -> PolyRingElem{T}\n\nUses the Newton (or Newton-Girard) identities to obtain the polynomial with given sums of powers of roots. The list must be nonempty and contain degree(f) entries where f is the polynomial to be recovered. The list must start with the sum of first powers of the roots.\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> f = x^4 - 2*x^3 + 10*x^2 + 7*x - 5\nx^4 - 2*x^3 + 10*x^2 + 7*x - 5\n\njulia> V = polynomial_to_power_sums(f)\n4-element Vector{BigInt}:\n 2\n -16\n -73\n 20\n\njulia> power_sums_to_polynomial(V)\nx^4 - 2*x^3 + 10*x^2 + 7*x - 5","category":"page"},{"location":"polynomial/#Special-functions","page":"Univariate polynomial functionality","title":"Special functions","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"The following special functions can be computed for any polynomial ring. Typically one uses the generator x of a polynomial ring to get the respective special polynomials expressed in terms of that generator.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"chebyshev_t(::Int, ::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.chebyshev_t-Tuple{Int64, PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.chebyshev_t","text":"chebyshev_t(n::Int, x::PolyRingElem)\n\nReturn the Chebyshev polynomial of the first kind T_n(x), defined by T_n(x) = cos(n cos^-1(x)).\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"chebyshev_u(::Int, ::PolyRingElem)","category":"page"},{"location":"polynomial/#AbstractAlgebra.chebyshev_u-Tuple{Int64, PolyRingElem}","page":"Univariate polynomial functionality","title":"AbstractAlgebra.chebyshev_u","text":"chebyshev_u(n::Int, x::PolyRingElem)\n\nReturn the Chebyshev polynomial of the first kind U_n(x), defined by (n+1) U_n(x) = T_n+1(x).\n\n\n\n\n\n","category":"method"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S, y = polynomial_ring(R, \"y\")\n(Univariate polynomial ring in y over univariate polynomial ring, y)\n\njulia> f = chebyshev_t(20, y)\n524288*y^20 - 2621440*y^18 + 5570560*y^16 - 6553600*y^14 + 4659200*y^12 - 2050048*y^10 + 549120*y^8 - 84480*y^6 + 6600*y^4 - 200*y^2 + 1\n\njulia> g = chebyshev_u(15, y)\n32768*y^15 - 114688*y^13 + 159744*y^11 - 112640*y^9 + 42240*y^7 - 8064*y^5 + 672*y^3 - 16*y\n","category":"page"},{"location":"polynomial/#Random-generation","page":"Univariate polynomial functionality","title":"Random generation","text":"","category":"section"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"One may generate random polynomials with degrees in a given range. Additional parameters are used to construct coefficients as elements of the coefficient ring.","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"rand(R::PolyRing, deg_range::AbstractUnitRange{Int}, v...)\nrand(R::PolyRing, deg::Int, v...)","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"Examples","category":"page"},{"location":"polynomial/","page":"Univariate polynomial functionality","title":"Univariate polynomial functionality","text":"R, x = polynomial_ring(ZZ, \"x\")\nf = rand(R, -1:3, -10:10)\n\nS, y = polynomial_ring(GF(7), \"y\")\ng = rand(S, 2:2)\n\nU, z = polynomial_ring(R, \"z\")\nh = rand(U, 3:3, -1:2, -10:10)","category":"page"},{"location":"module_introduction/#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"module_introduction/","page":"Introduction","title":"Introduction","text":"As with many generic constructions in AbstractAlgebra, the modules that are provided in AbstractAlgebra itself work over a Euclidean domain. Moreover, they are limited to finitely presented modules.","category":"page"},{"location":"module_introduction/","page":"Introduction","title":"Introduction","text":"Free modules and vector spaces are provided over Euclidean domains and fields respectively and then submodule, quotient module and direct sum module constructions are possible recursively over these.","category":"page"},{"location":"module_introduction/","page":"Introduction","title":"Introduction","text":"It's also possible to compute an invariant decomposition using the Smith Normal Form.","category":"page"},{"location":"module_introduction/","page":"Introduction","title":"Introduction","text":"The system also provides module homomorphisms and isomorphisms, building on top of the map interface.","category":"page"},{"location":"module_introduction/","page":"Introduction","title":"Introduction","text":"As for rings and fields, modules follow an interface which other modules are expected to follow. However, very little generic functionality is provided automatically once this interface is implemented by a new module type.","category":"page"},{"location":"module_introduction/","page":"Introduction","title":"Introduction","text":"The purpose of the module interface is simply to encourage uniformity in the module interfaces of systems that build on AbstractAlgebra. Of course modules are so diverse that this is a very loosely defined interface to accommodate the diversity of possible representations and implementations.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"mseries/#Multivariate-series","page":"Multivariate series","title":"Multivariate series","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"AbstractAlgebra.jl provide multivariate series over a commutative ring.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Series with capped absolute precision are provided with and without weights.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"For the unweighted case precision in each variable can be set per series, but is capped at some maximum precision which is set when defining the ring.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"For the weighted case, a single precision is set on the ring only. Terms are truncated at that precision (after applying weights).","category":"page"},{"location":"mseries/#Generic-multivariate-series","page":"Multivariate series","title":"Generic multivariate series","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Generic multivariate series over a commutative ring, AbsMSeries{T} is implemented in src/generic/AbsMSeries.jl.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Such series are capped absolute series and have type Generic.AbsMSeries{T} where T is the type of elements of the coefficient ring.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Internally they consist of a multivariate polynomial. For unweighted series they also contain a vector of precisions, one for each variable.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"For weighted series weights and a precision are stored on the ring only. The vector of precisions in the series objects is ignored.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"See the file src/generic/GenericTypes.jl for details of the type.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"The series are implemented in terms of multivariate polynomials which are used internally to keep track of the coefficients of the series.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Only lex ordering is provided at present both weighted and unweighted, though series print in reverse order to what multivariate polynomials would print, i.e. least significant term first, as would be expected for series.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Parent objects of such series have type Generic.AbsMSeriesRing{T}.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"The symbol representation of the variables and the multivariate polynomial ring is stored in the parent object.","category":"page"},{"location":"mseries/#Abstract-types","page":"Multivariate series","title":"Abstract types","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Multivariate series element types belong to the abstract type MSeriesElem{T} and the multivariate series ring types belong to the abstract type MSeriesRing{T}. This enables one to write generic functions that can accept any AbstractAlgebra multivariate series type.","category":"page"},{"location":"mseries/#Multivariate-series-ring-constructors","page":"Multivariate series","title":"Multivariate series ring constructors","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"In order to construct multivariate series in AbstractAlgebra.jl, one must first construct the series ring itself. This is accomplished with the following constructors.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"For the unweighted case:","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"power_series_ring(R::Ring, prec::Vector{Int}, s::AbstractVector{<:VarName}; cached::Bool = true)","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Given a base ring R and a vector of strings s specifying how the generators (variables) should be printed, along with a vector of precisions, one for each variable, return a tuple U, (x, y, ...) representing the new series ring S and the generators x y ldots of the ring as a tuple. By default the parent object S will depend on R, the precision vector and the variable names x, y, ... and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"In the weighted case:","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"power_series_ring(R::Ring, weights::Vector{Int}, s::AbstractVector{<:VarName}, prec::Int; cached::Bool = true)","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Given a base ring R and a vector of strings s specifying how the generators (variables) should be printed, along with a vector of weights, one for each variable and a bound on the (weighted) precision, return a tuple U, (x, y, ...) representing the new series ring S and the generators x y ldots of the ring as a tuple. By default the parent object S will depend on R, the precision, the vector of weights and the variable names x, y, ... and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Here are some examples of creating multivariate series rings and making use of the resulting parent objects to coerce various elements into the series ring.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Note that one can also use the function call O(x^n) with unweighted series to specify the precision in the variable x of a given series expression should be precision n.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"note: Note\nIt is not possible to use x^0 in the O() function, since there is no distinction between x^0 and y^0 as far as the system is concerned. If one wishes to set the precision of a variable to precision 0, one must use the set_precision! function described below.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"If one wants a series with the same precision in all variables, one can use O(R, n) where R is the series ring and n is the desired precision.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"If all the precisions are to be the same, the vector of integers for the precisions can be replaced by a single integer in the constructor.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Examples","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"julia> R, (x, y) = power_series_ring(ZZ, [2, 3], [\"x\", \"y\"])\n(Multivariate power series ring in 2 variables over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(y^3) + O(x^2), y + O(y^3) + O(x^2)])\n\njulia> f = R()\nO(y^3) + O(x^2)\n\njulia> g = R(123)\n123 + O(y^3) + O(x^2)\n\njulia> h = R(BigInt(1234))\n1234 + O(y^3) + O(x^2)\n\njulia> k = R(x + 1)\n1 + x + O(y^3) + O(x^2)\n\njulia> m = x + y + O(y^2)\ny + x + O(y^2) + O(x^2)\n\njulia> R, (x, y) = power_series_ring(ZZ, 3, [\"x\", \"y\"])\n(Multivariate power series ring in 2 variables over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(y^3) + O(x^3), y + O(y^3) + O(x^3)])\n\njulia> n = x + y + O(R, 2)\ny + x + O(y^2) + O(x^2)\n\njulia> R, (x, y) = power_series_ring(ZZ, [2, 3], 10, [\"x\", \"y\"])\n(Multivariate power series ring in 2 variables over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(10), y + O(10)])\n\njulia> R()\nO(10)\n\njulia> R(x)\nx + O(10)","category":"page"},{"location":"mseries/#Basic-ring-functionality","page":"Multivariate series","title":"Basic ring functionality","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Once a multivariate series ring is constructed, there are various ways to construct series in that ring.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"The easiest way is simply using the generators returned by the power_series_ring constructor and build up the power series using basic arithmetic, as described in the Ring interface.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"The power series rings in AbstractAlgebra.jl implement the full Ring interface.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"We give some examples of such functionality. ","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"note: Note\nThe divexact function can currently only divide by unit series (i.e. whose constant coefficient is invertible).","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"Examples","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"julia> R, (x,) = power_series_ring(ZZ, [5], [\"x\"])\n(Multivariate power series ring in 1 variable over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(x^5)])\n\njulia> f = x^3 + 3x + 21\n21 + 3*x + x^3 + O(x^5)\n\njulia> h = zero(R)\nO(x^5)\n\njulia> k = one(R)\n1 + O(x^5)\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> n = length(f)\n3\n\njulia> U = base_ring(R)\nIntegers\n\njulia> v = symbols(R)\n1-element Vector{Symbol}:\n :x\n\njulia> T = parent(x + 1)\nMultivariate power series ring in 1 variable x\n over integers\n\njulia> f == deepcopy(f)\ntrue\n\njulia> t = divexact(f*x, 1 + x)\n21*x - 18*x^2 + 18*x^3 - 17*x^4 + O(x^5)\n\njulia> R, (x, y) = power_series_ring(ZZ, [2, 3], 10, [\"x\", \"y\"])\n(Multivariate power series ring in 2 variables over integers, AbstractAlgebra.Generic.AbsMSeries{BigInt, AbstractAlgebra.Generic.MPoly{BigInt}}[x + O(10), y + O(10)])\n\njulia> f = 3x^2*y + 1\n1 + 3*y*x^2 + O(10)\n\njulia> one(R)\n1 + O(10)","category":"page"},{"location":"mseries/#Power-series-functionality-provided-by-AbstractAlgebra.jl","page":"Multivariate series","title":"Power series functionality provided by AbstractAlgebra.jl","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"The functionality listed below is automatically provided by AbstractAlgebra.jl for absolute series over any commutative ring.","category":"page"},{"location":"mseries/#Basic-functionality","page":"Multivariate series","title":"Basic functionality","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"The following are provided for weighted and unweighted series:","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"number_of_variables(::Generic.AbsMSeriesRing)","category":"page"},{"location":"mseries/#AbstractAlgebra.number_of_variables-Tuple{AbstractAlgebra.Generic.AbsMSeriesRing}","page":"Multivariate series","title":"AbstractAlgebra.number_of_variables","text":"number_of_variables(R::AbsMSeriesRing)\n\nReturn the number of variables in the series ring.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"symbols(::MSeriesRing)","category":"page"},{"location":"mseries/#AbstractAlgebra.symbols-Tuple{AbstractAlgebra.MSeriesRing}","page":"Multivariate series","title":"AbstractAlgebra.symbols","text":"symbols(R::MSeriesRing)\n\nReturn a vector of symbols, one for each of the variables of the series ring R.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"precision(::Generic.AbsMSeries)","category":"page"},{"location":"mseries/#Base.precision-Tuple{AbstractAlgebra.Generic.AbsMSeries}","page":"Multivariate series","title":"Base.precision","text":"precision(a::AbsMSeries)\n\nReturn a vector of precisions, one for each variable in the series ring. If the ring is weighted the weighted precision is returned instead.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"coeff(::Generic.AbsMSeries, ::Int)","category":"page"},{"location":"mseries/#AbstractAlgebra.coeff-Tuple{AbstractAlgebra.Generic.AbsMSeries, Int64}","page":"Multivariate series","title":"AbstractAlgebra.coeff","text":"coeff(a::AbsMSeries, n::Int)\n\nReturn the coefficient of the n-th nonzero term of the series (or zero if there are fewer than n nonzero terms). Terms are numbered from the least significant term, i.e. the first term displayed when the series is printed.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"characteristic(::Generic.AbsMSeries)","category":"page"},{"location":"mseries/#AbstractAlgebra.characteristic-Tuple{AbstractAlgebra.Generic.AbsMSeries}","page":"Multivariate series","title":"AbstractAlgebra.characteristic","text":"characteristic(R::FracField{T}) where T <: RingElem\n\nReturn the characteristic of the given field.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"gen(::Generic.AbsMSeriesRing, ::Int)","category":"page"},{"location":"mseries/#AbstractAlgebra.gen-Tuple{AbstractAlgebra.Generic.AbsMSeriesRing, Int64}","page":"Multivariate series","title":"AbstractAlgebra.gen","text":"gen(R::AbsMSeriesRing, i::Int)\n\nReturn the i-th generator (variable) of the series ring R. Numbering starts from 1 for the most significant variable.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"gens(::Generic.AbsMSeriesRing)","category":"page"},{"location":"mseries/#AbstractAlgebra.gens-Tuple{AbstractAlgebra.Generic.AbsMSeriesRing}","page":"Multivariate series","title":"AbstractAlgebra.gens","text":"gens(R::AbsMSeriesRing)\n\nReturn a vector of the generators (variables) of the series ring R, starting with the most significant.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"is_gen(::Generic.AbsMSeries)","category":"page"},{"location":"mseries/#AbstractAlgebra.is_gen-Tuple{AbstractAlgebra.Generic.AbsMSeries}","page":"Multivariate series","title":"AbstractAlgebra.is_gen","text":"is_gen(a::AbsMSeries)\n\nReturn true if the series a is a generator of its parent series ring.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"is_unit(::Generic.AbsMSeries)","category":"page"},{"location":"mseries/#AbstractAlgebra.is_unit-Tuple{AbstractAlgebra.Generic.AbsMSeries}","page":"Multivariate series","title":"AbstractAlgebra.is_unit","text":"is_unit(a::AbsMSeries)\n\nReturn true if the series is a unit in its series ring, i.e. if its constant term is a unit in the base ring.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"length(::Generic.AbsMSeries)","category":"page"},{"location":"mseries/#Base.length-Tuple{AbstractAlgebra.Generic.AbsMSeries}","page":"Multivariate series","title":"Base.length","text":"length(a::AbsMSeries)\n\nReturn the number of nonzero terms in the series a.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"The following are only available for unweighted series.","category":"page"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"max_precision(::Generic.AbsMSeriesRing)","category":"page"},{"location":"mseries/#AbstractAlgebra.max_precision-Tuple{AbstractAlgebra.Generic.AbsMSeriesRing}","page":"Multivariate series","title":"AbstractAlgebra.max_precision","text":"max_precision(R::AbsMSeriesRing)\n\nReturn a vector of precision caps, one for each variable in the ring. Arithmetic operations will be performed to precisions not exceeding these values.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"valuation(::Generic.AbsMSeries)","category":"page"},{"location":"mseries/#AbstractAlgebra.valuation-Tuple{AbstractAlgebra.Generic.AbsMSeries}","page":"Multivariate series","title":"AbstractAlgebra.valuation","text":"valuation(a::AbsMSeries)\n\nReturn the valuation of a as a vector of integers, one for each variable.\n\n\n\n\n\n","category":"method"},{"location":"mseries/#Iteration","page":"Multivariate series","title":"Iteration","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"coefficients(::Generic.AbsMSeries)","category":"page"},{"location":"mseries/#AbstractAlgebra.coefficients-Tuple{AbstractAlgebra.Generic.AbsMSeries}","page":"Multivariate series","title":"AbstractAlgebra.coefficients","text":"coefficients(a::AbsMSeries)\n\nReturn an array of the nonzero coefficients of the series, in the order they would be displayed, i.e. least significant term first.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"exponent_vectors(::Generic.AbsMSeries)","category":"page"},{"location":"mseries/#AbstractAlgebra.exponent_vectors-Tuple{AbstractAlgebra.Generic.AbsMSeries}","page":"Multivariate series","title":"AbstractAlgebra.exponent_vectors","text":"exponent_vectors(a::AbsMSeries)\n\nReturn an array of the exponent vectors of the nonzero terms of the series, in the order they would be displayed, i.e. least significant term first.\n\n\n\n\n\n","category":"method"},{"location":"mseries/#Truncation","page":"Multivariate series","title":"Truncation","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"truncate(::Generic.AbsMSeries, ::Vector{Int})\ntruncate(::Generic.AbsMSeries, ::Int)","category":"page"},{"location":"mseries/#Base.truncate-Tuple{AbstractAlgebra.Generic.AbsMSeries, Vector{Int64}}","page":"Multivariate series","title":"Base.truncate","text":"truncate(a::AbstractAlgebra.AbsMSeries, prec::Vector{Int})\n\nReturn a truncated to (absolute) precisions given by the vector prec.\n\n\n\n\n\n","category":"method"},{"location":"mseries/#Base.truncate-Tuple{AbstractAlgebra.Generic.AbsMSeries, Int64}","page":"Multivariate series","title":"Base.truncate","text":"truncate(a::AbstractAlgebra.AbsMSeries, prec::Int)\n\nReturn a truncated to precision prec. This either truncates by weight in the weighted cases or truncates each variable to precision prec in the unweighted case.\n\n\n\n\n\n","category":"method"},{"location":"mseries/#Exact-division","page":"Multivariate series","title":"Exact division","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"divexact(::Generic.AbsMSeries{T}, ::Generic.AbsMSeries{T}) where T <: RingElem","category":"page"},{"location":"mseries/#AbstractAlgebra.divexact-Union{Tuple{T}, Tuple{AbstractAlgebra.Generic.AbsMSeries{T, S} where S<:MPolyRingElem{T}, AbstractAlgebra.Generic.AbsMSeries{T, S} where S<:MPolyRingElem{T}}} where T<:RingElem","page":"Multivariate series","title":"AbstractAlgebra.divexact","text":"divexact(x::AbsMSeries{T}, y::AbsMSeries{T}; check::Bool=true) where T <: RingElement\n\nReturn the exact quotient of the series x by the series y. This function currently assumes y is an invertible series.\n\n\n\n\n\n","category":"method"},{"location":"mseries/#Evaluation","page":"Multivariate series","title":"Evaluation","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"evaluate(::U, ::Vector{Int}, ::Vector{U}) where {T <: RingElement, U <: Generic.AbsMSeries{T}}","category":"page"},{"location":"mseries/#AbstractAlgebra.evaluate-Union{Tuple{U}, Tuple{T}, Tuple{U, Vector{Int64}, Vector{U}}} where {T<:RingElement, U<:(AbstractAlgebra.Generic.AbsMSeries{T, S} where S<:MPolyRingElem{T})}","page":"Multivariate series","title":"AbstractAlgebra.evaluate","text":"evaluate(a::U, vars::Vector{Int}, vals::Vector{U}) where {T <: RingElement, U <: AbsMSeries{T}}\n\nEvaluate the series expression by substituting in the supplied values in the array vals for the corresponding variables with indices given by the array vars. The values must be in the same ring as a.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"evaluate(::U, ::Vector{U}, ::Vector{U}) where {T <: RingElement, U <: Generic.AbsMSeries{T}}","category":"page"},{"location":"mseries/#AbstractAlgebra.evaluate-Union{Tuple{U}, Tuple{T}, Tuple{U, Vector{U}, Vector{U}}} where {T<:RingElement, U<:(AbstractAlgebra.Generic.AbsMSeries{T, S} where S<:MPolyRingElem{T})}","page":"Multivariate series","title":"AbstractAlgebra.evaluate","text":"evaluate(a::U, vars::Vector{U}, vals::Vector{U}) where {T <: RingElement, U <: AbsMSeries{T}}\n\nEvaluate the series expression by substituting in the supplied values in the array vals for the corresponding variables given by the array vars. The values must be in the same ring as a.\n\n\n\n\n\n","category":"method"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"evaluate(::U, ::Vector{U}) where {T <: RingElement, U <: Generic.AbsMSeries{T}}","category":"page"},{"location":"mseries/#AbstractAlgebra.evaluate-Union{Tuple{U}, Tuple{T}, Tuple{U, Vector{U}}} where {T<:RingElement, U<:(AbstractAlgebra.Generic.AbsMSeries{T, S} where S<:MPolyRingElem{T})}","page":"Multivariate series","title":"AbstractAlgebra.evaluate","text":"evaluate(a::U, vals::Vector{U}) where {T <: RingElement, U <: AbsMSeries{T}}\n\nEvaluate the series expression by substituting in the supplied values in the array vals for the variables the series ring to which a belongs. The values must be in the same ring as a.\n\n\n\n\n\n","category":"method"},{"location":"mseries/#Random-generation","page":"Multivariate series","title":"Random generation","text":"","category":"section"},{"location":"mseries/","page":"Multivariate series","title":"Multivariate series","text":"rand(::MSeriesRing, term_range, v...)","category":"page"},{"location":"mseries/#Base.rand-Tuple{AbstractAlgebra.MSeriesRing, Any, Vararg{Any}}","page":"Multivariate series","title":"Base.rand","text":"rand(S::MSeriesRing, term_range, v...)\n\nReturn a random element of the series ring S with number of terms in the range given by term_range and where coefficients of the series are randomly generated in the base ring using the data given by v. The exponents of the variable in the terms will be less than the precision caps for the Ring S when it was created.\n\n\n\n\n\n","category":"method"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"laurent_polynomial/#Generic-Laurent-polynomials","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"","category":"section"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"Laurent polynomials are similar to polynomials but can have terms of negative degrees, and form a ring denoted by Rx x^-1 where R is the coefficient ring.","category":"page"},{"location":"laurent_polynomial/#Generic-Laurent-polynomial-types","page":"Generic Laurent polynomials","title":"Generic Laurent polynomial types","text":"","category":"section"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"AbstractAlgebra.jl provides a generic implementation of Laurent polynomials, built in terms of regular polynomials in the file src/generic/LaurentPoly.jl.","category":"page"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"The type LaurentPolyWrap{T, ...} <: LaurentPolyRingElem{T} implements generic Laurent polynomials by wrapping regular polynomials: a Laurent polynomial l wraps a polynomial p and an integer n such that l = x^-n * p.","category":"page"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"The corresponding parent type is LaurentPolyWrapRing{T, ...} <: LaurentPolyRing{T}.","category":"page"},{"location":"laurent_polynomial/#Abstract-types","page":"Generic Laurent polynomials","title":"Abstract types","text":"","category":"section"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"Two abstract types LaurentPolyRingElem{T} and LaurentPolyRing{T} are defined to represent Laurent polynomials and rings thereof, parameterized on a base ring T.","category":"page"},{"location":"laurent_polynomial/#Laurent-polynomials-ring-constructor","page":"Generic Laurent polynomials","title":"Laurent polynomials ring constructor","text":"","category":"section"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"In order to instantiate Laurent polynomials, one must first construct the parent ring:","category":"page"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"laurent_polynomial_ring","category":"page"},{"location":"laurent_polynomial/#AbstractAlgebra.laurent_polynomial_ring","page":"Generic Laurent polynomials","title":"AbstractAlgebra.laurent_polynomial_ring","text":"laurent_polynomial_ring(R::Ring, s::VarName)\n\nGiven a base ring R and string s specifying how the generator (variable) should be printed, return a tuple S, x representing the new Laurent polynomial ring S = Rx 1x and the generator x of the ring.\n\nExamples\n\njulia> R, x = laurent_polynomial_ring(ZZ, \"x\")\n(Univariate Laurent Polynomial Ring in x over Integers, x)\n\njulia> 2x^-3 + x^2\nx^2 + 2*x^-3\n\njulia> rand(R, -3:3, -9:9)\n-3*x^2 - 8*x + 4 + 3*x^-1 - 6*x^-2 + 9*x^-3\n\n\n\n\n\nlaurent_polynomial_ring(R::Ring, varnames...; cached::Bool = true)\n\nGiven a base ring R and variable names varnames..., say :x, :y, :z, return a tuple S, x, y, z representing the new ring S = Rx 1x y 1y z 1z and the generators x y z of the ring.\n\nBy default (cached=true), the output S will be cached, i.e. if laurent_polynomial_ring is invoked again with the same arguments, the same (identical) ring is returned. Setting cached to false ensures a distinct new ring is returned, and will also prevent it from being cached.\n\nFor information about the many ways to specify varnames... refer to polynomial_ring or the specification in AbstractAlgebra.@varnames_interface.\n\n\n\n\n\n","category":"function"},{"location":"laurent_polynomial/#Basic-functionality","page":"Generic Laurent polynomials","title":"Basic functionality","text":"","category":"section"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"Laurent polynomials implement the ring interface, and some methods from the polynomial interface, for example:","category":"page"},{"location":"laurent_polynomial/","page":"Generic Laurent polynomials","title":"Generic Laurent polynomials","text":"julia> R, x = laurent_polynomial_ring(ZZ, \"x\")\n(Univariate Laurent polynomial ring in x over integers, x)\n\njulia> var(R)\n:x\n\njulia> symbols(R)\n1-element Vector{Symbol}:\n :x\n\njulia> number_of_variables(R)\n1\n\njulia> f = x^-2 + 2x\n2*x + x^-2\n\njulia> coeff.(f, -2:2)\n5-element Vector{BigInt}:\n 1\n 0\n 0\n 2\n 0\n\njulia> set_coefficient!(f, 3, ZZ(5))\n5*x^3 + 2*x + x^-2\n\njulia> is_gen(f)\nfalse\n\njulia> shift_left(f,2)\n5*x^5 + 2*x^3 + 1\n\njulia> map_coefficients(x->2x, f)\n10*x^3 + 4*x + 2*x^-2\n\njulia> change_base_ring(RealField, f)\n5.0*x^3 + 2.0*x + x^-2\n\njulia> leading_coefficient(f), trailing_coefficient(f)\n(5, 1)","category":"page"},{"location":"ring_interface/#Ring-Interface","page":"Ring Interface","title":"Ring Interface","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"AbstractAlgebra.jl generic code makes use of a standardised set of functions which it expects to be implemented for all rings. Here we document this interface. All libraries which want to make use of the generic capabilities of AbstractAlgebra.jl must supply all of the required functionality for their rings.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"In addition to the required functions, there are also optional functions which can be provided for certain types of rings, e.g. GCD domains or fields, etc. If implemented, these allow the generic code to provide additional functionality for those rings, or in some cases, to select more efficient algorithms.","category":"page"},{"location":"ring_interface/#Types","page":"Ring Interface","title":"Types","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Most rings must supply two types:","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"a type for the parent object (representing the ring itself)\na type for elements of that ring","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For example, the generic univariate polynomial type in AbstractAlgebra.jl provides two types in generic/GenericTypes.jl:","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Generic.PolyRing{T} for the parent objects\nGeneric.Poly{T} for the actual polynomials","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"The parent type must belong to Ring and the element type must belong to RingElem. Of course, the types may belong to these abstract types transitively, e.g. Poly{T} actually belongs to PolyRingElem{T} which in turn belongs to RingElem.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For parameterised rings, we advise that the types of both the parent objects and element objects to be parameterised by the types of the elements of the base ring (see the function base_ring below for a definition).","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"There can be variations on this theme: e.g. in some areas of mathematics there is a notion of a coefficient domain, in which case it may make sense to parameterise all types by the type of elements of this coefficient domain. But note that this may have implications for the ad hoc operators one might like to explicitly implement.","category":"page"},{"location":"ring_interface/#RingElement-type-union","page":"Ring Interface","title":"RingElement type union","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Because of its lack of multiple inheritance, Julia does not allow Julia Base types to belong to RingElem. To allow us to work equally with AbstractAlgebra and Julia types that represent elements of rings we define a union type RingElement in src/julia/JuliaTypes.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"So far, in addition to RingElem the union type RingElement includes the Julia types Integer, Rational and AbstractFloat.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Most of the generic code in AbstractAlgebra makes use of the union type RingElement instead of RingElem so that the generic functions also accept the Julia Base ring types.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"note: Note\nOne must be careful when defining ad hoc binary operations for ring element types. It is often necessary to define separate versions of the functions for RingElem then for each of the Julia types separately in order to avoid ambiguity warnings.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Note that even though RingElement is a union type we still have the following inclusion","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"RingElement <: NCRingElement","category":"page"},{"location":"ring_interface/#Parent-object-caches","page":"Ring Interface","title":"Parent object caches","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"In many cases, it is desirable to have only one object in the system to represent each ring. This means that if the same ring is constructed twice, elements of the two rings will be compatible as far as arithmetic is concerned.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"In order to facilitate this, global caches of rings are stored in AbstractAlgebra.jl, usually implemented using dictionaries. For example, the Generic.PolyRing parent objects are looked up in a dictionary PolyID to see if they have been previously defined.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Whether these global caches are provided or not, depends on both mathematical and algorithmic considerations. E.g. in the case of number fields, it isn't desirable to identify all number fields with the same defining polynomial, as they may be considered with distinct embeddings into one another. In other cases, identifying whether two rings are the same may be prohibitively expensive. Generally, it may only make sense algorithmically to identify two rings if they were constructed from identical data.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"If a global cache is provided, it must be optionally possible to construct the parent objects without caching. This is done by passing a boolean value cached to the inner constructor of the parent object. See src/generic/GenericTypes.jl for examples of how to construct and handle such caches.","category":"page"},{"location":"ring_interface/#Required-functions-for-all-rings","page":"Ring Interface","title":"Required functions for all rings","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"In the following, we list all the functions that are required to be provided for rings in AbstractAlgebra.jl or by external libraries wanting to use AbstractAlgebra.jl.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"We give this interface for fictitious types MyParent for the type of the ring parent object R and MyElem for the type of the elements of the ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"note: Note\nGeneric functions in AbstractAlgebra.jl may not rely on the existence of functions that are not documented here. If they do, those functions will only be available for rings that implement that additional functionality, and should be documented as such.","category":"page"},{"location":"ring_interface/#Data-type-and-parent-object-methods","page":"Ring Interface","title":"Data type and parent object methods","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"parent_type(::Type{MyElem})","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return the type of the corresponding parent object for the given element type. For example, parent_type(Generic.Poly{T}) will return Generic.PolyRing{T}.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"elem_type(::Type{MyParent})","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return the type of the elements of the ring whose parent object has the given type. This is the inverse of the parent_type function, i.e. elem_type(Generic.PolyRing{T}) will return Generic.Poly{T}.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"base_ring(R::MyParent)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Given a parent object R, representing a ring, this function returns the parent object of any base ring that parameterises this ring. For example, the base ring of the ring of polynomials over the integers would be the integer ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"If the ring is not parameterised by another ring, this function must return Union{}.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"note: Note\nThere is a distinction between a base ring and other kinds of parameters. For example, in the ring mathbbZnmathbbZ, the modulus n is a parameter, but the only base ring is mathbbZ. We consider the ring mathbbZnmathbbZ to have been constructed from the base ring mathbbZ by taking its quotient by a (principal) ideal.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"parent(f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return the parent object of the given element, i.e. return the ring to which the given element belongs.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"This is usually stored in a field parent in each ring element. (If the parent objects have mutable struct types, the internal overhead here is just an additional machine pointer stored in each element of the ring.)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For some element types it isn't necessary to append the parent object as a field of every element. This is the case when the parent object can be reconstructed just given the type of the elements. For example, this is the case for the ring of integers and in fact for any ring element type that isn't parameterised or generic in any way.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"is_domain_type(::Type{MyElem})","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return true if every element of the given element type (which may be parameterised or an abstract type) necessarily has a parent that is an integral domain, otherwise if this cannot be guaranteed, the function returns false.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For example, if MyElem was the type of elements of generic residue rings of a polynomial ring, the answer to the question would depend on the modulus of the residue ring. Therefore is_domain_type would have to return false, since we cannot guarantee that we are dealing with elements of an integral domain in general. But if the given element type was for rational integers, the answer would be true, since every rational integer has as parent the ring of rational integers, which is an integral domain.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Note that this function depends only on the type of an element and cannot access information about the object itself, or its parent.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"is_exact_type(::Type{MyElem})","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return true if every element of the given type is represented exactly. For example, p-adic numbers, real and complex floating point numbers and power series are not exact, as we can only represent them in general with finite truncations. Similarly polynomials and matrices over inexact element types are themselves inexact.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Integers, rationals, finite fields and polynomials and matrices over them are always exact.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Note that MyElem may be parameterised or an abstract type, in which case every element of every type represented by MyElem must be exact, otherwise the function must return false.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Base.hash(f::MyElem, h::UInt)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return a hash for the object f of type UInt. This is used as a hopefully cheap way to distinguish objects that differ arithmetically.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"If the object has components, e.g. the coefficients of a polynomial or elements of a matrix, these should be hashed recursively, passing the same parameter h to all levels. Each component should then be xor'd with h before combining the individual component hashes to give the final hash.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"The hash functions in AbstractAlgebra.jl usually start from some fixed 64 bit hexadecimal value that has been picked at random by the library author for that type. That is then truncated to fit a UInt (in case the latter is not 64 bits). This ensures that objects that are the same arithmetically (or that have the same components), but have different types (or structures), are unlikely to hash to the same value.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"deepcopy_internal(f::MyElem, dict::IdDict)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return a copy of the given element, recursively copying all components of the object.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Obviously the parent, if it is stored in the element, should not be copied. The new element should have precisely the same parent as the old object.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For types that cannot self-reference themselves anywhere internally, the dict argument may be ignored.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"In the case that internal self-references are possible, please consult the Julia documentation on how to implement deepcopy_internal.","category":"page"},{"location":"ring_interface/#Constructors","page":"Ring Interface","title":"Constructors","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Outer constructors for most AbstractAlgebra types are provided by overloading the call syntax for parent objects.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"If R is a parent object for a given ring we require the following constructors.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"(R::MyParent)()","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return the zero object of the given ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"(R::MyParent)(a::Integer)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Coerce the given integer into the given ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"(R::MyParent)(a::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"If a belongs to the given ring, the function returns it (without making a copy). Otherwise an error is thrown.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For parameterised rings we also require a function to coerce from the base ring into the parent ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"(R::MyParent{T})(a::T) where T <: RingElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Coerce a into the ring R if a belongs to the base ring of R.","category":"page"},{"location":"ring_interface/#Basic-manipulation-of-rings-and-elements","page":"Ring Interface","title":"Basic manipulation of rings and elements","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"zero(R::MyParent)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return the zero element of the given ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"one(R::MyParent)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return the multiplicative identity of the given ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"iszero(f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return true if the given element is the zero element of the ring it belongs to.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"isone(f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return true if the given element is the multiplicative identity of the ring it belongs to.","category":"page"},{"location":"ring_interface/#Canonicalisation","page":"Ring Interface","title":"Canonicalisation","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"canonical_unit(f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"When fractions are created with two elements of the given type, it is nice to be able to represent them in some kind of canonical form. This is of course not always possible. But for example, fractions of integers can be canonicalised by first removing any common factors of the numerator and denominator, then making the denominator positive.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"In AbstractAlgebra.jl, the denominator would be made positive by dividing both the numerator and denominator by the canonical unit of the denominator. For a negative denominator, this would be -1.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For elements of a field, canonical_unit simply returns the element itself. In general, canonical_unit of an invertible element should be that element. Finally, if a = ub we should have the identity canonical_unit(a) = canonical_unit(u)*canonical_unit(b).","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For some rings, it is completely impractical to implement this function, in which case it may return 1 in the given ring. The function must however always exist, and always return an element of the ring.","category":"page"},{"location":"ring_interface/#String-I/O","page":"Ring Interface","title":"String I/O","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"show(io::IO, R::MyParent)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"This should print an English description of the parent ring (to the given IO object). If the ring is parameterised, it can call the corresponding show function for any rings it depends on.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"show(io::IO, f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"This should print a human readable, textual representation of the object (to the given IO object). It can recursively call the corresponding show functions for any of its components.","category":"page"},{"location":"ring_interface/#Expressions","page":"Ring Interface","title":"Expressions","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"To obtain best results when printing composed types derived from other types, e.g., polynomials, the following method should be implemented.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"expressify(f::MyElem; context = nothing)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"which must return either Expr, Symbol, Integer or String.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For a type which implements expressify, one can automatically derive show methods supporting output as plain text, LaTeX and html by using the following:","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"@enable_all_show_via_expressify MyElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"This defines the following show methods for the specified type MyElem:","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"function Base.show(io::IO, a::MyElem)\n show_via_expressify(io, a)\nend\n\nfunction Base.show(io::IO, mi::MIME\"text/plain\", a::MyElem)\n show_via_expressify(io, mi, a)\nend\n\nfunction Base.show(io::IO, mi::MIME\"text/latex\", a::MyElem)\n show_via_expressify(io, mi, a)\nend\n\nfunction Base.show(io::IO, mi::MIME\"text/html\", a::MyElem)\n show_via_expressify(io, mi, a)\nend","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"As an example, assume that an object f of type MyElem has two components f.a and f.b of integer type, which should be printed as a^b, this can be implemented as","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"expressify(f::MyElem; context = nothing) = Expr(:call, :^, f.a, f.b)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"If f.a and f.b themselves are objects that can be expressified, this can be implemented as","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"function expressify(f::MyElem; context = nothing)\n return Expr(:call, :^, expressify(f.a, context = context),\n expressify(f.b, context = context))\nend","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"As noted above, expressify should return an Expr, Symbol, Integer or String. The rendering of such expressions with a particular MIME type to an output context is controlled by the following rules which are subject to change slightly in future versions of AbstracAlgebra.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Integer: The printing of integers is straightforward and automatically includes transformations such as 1 + (-2)*x => 1 - 2*x as this is cumbersome to implement per-type.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Symbol: Since variable names are stored as mere symbols in AbstractAlgebra, some transformations related to subscripts are applied to symbols automatically in latex output. The \\operatorname{ in the following table is actually replaced with the more portable \\mathop{\\mathrm{.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"expressify latex output\nSymbol(\"a\") a\nSymbol(\"α\") {\\alpha}\nSymbol(\"x1\") \\operatorname{x1}\nSymbol(\"xy_1\") \\operatorname{xy}_{1}\nSymbol(\"sin\") \\operatorname{sin}\nSymbol(\"sin_cos\") \\operatorname{sin\\_cos}\nSymbol(\"sin_1\") \\operatorname{sin}_{1}\nSymbol(\"sin_cos_1\") \\operatorname{sin\\_cos}_{1}\nSymbol(\"αaβb_1_2\") \\operatorname{{\\alpha}a{\\beta}b}_{1,2}","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Expr: These are the most versatile as the Expr objects themselves contain a symbolic head and any number of arguments. What looks like f(a,b) in textual output is Expr(:call, :f, :a, :b) under the hood. AbstractAlgebra currently contains the following printing rules for such expressions.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"expressify output latex notes\nExpr(:call, :+, a, b) a + b \nExpr(:call, :*, a, b) a*b one space for implied multiplication\nExpr(:call, :cdot, a, b) a * b a real \\cdot is used\nExpr(:call, :^, a, b) a^b may include some courtesy parentheses\nExpr(:call, ://, a, b) a//b will create a fraction box\nExpr(:call, :/, a, b) a/b will not create a fraction box\nExpr(:call, a, b, c) a(b, c) \nExpr(:ref, a, b, c) a[b, c] \nExpr(:vcat, a, b) [a; b] actually vertical\nExpr(:vect, a, b) [a, b] \nExpr(:tuple, a, b) (a, b) \nExpr(:list, a, b) {a, b} \nExpr(:series, a, b) a, b \nExpr(:sequence, a, b) ab \nExpr(:row, a, b) a b combine with :vcat to make matrices\nExpr(:hcat, a, b) a b ","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"String: Strings are printed verbatim and should only be used as a last resort as they provide absolutely no precedence information on their contents.","category":"page"},{"location":"ring_interface/#Unary-operations","page":"Ring Interface","title":"Unary operations","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"-(f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return -f.","category":"page"},{"location":"ring_interface/#Binary-operations","page":"Ring Interface","title":"Binary operations","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"+(f::MyElem, g::MyElem)\n-(f::MyElem, g::MyElem)\n*(f::MyElem, g::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return f + g, f - g or fg, respectively.","category":"page"},{"location":"ring_interface/#Comparison","page":"Ring Interface","title":"Comparison","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"==(f::MyElem, g::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return true if f and g are arithmetically equal. In the case where the two elements are inexact, the function returns true if they agree to the minimum precision of the two.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"isequal(f::MyElem, g::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For exact rings, this should return the same thing as == above. For inexact rings, this returns true only if the two elements are arithmetically equal and have the same precision.","category":"page"},{"location":"ring_interface/#Powering","page":"Ring Interface","title":"Powering","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"^(f::MyElem, e::Int)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return f^e. The function should throw a DomainError() if negative exponents don't make sense but are passed to the function.","category":"page"},{"location":"ring_interface/#Exact-division","page":"Ring Interface","title":"Exact division","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"divexact(f::MyElem, g::MyElem; check::Bool=true)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return fg, though note that Julia uses / for floating point division. Here we mean exact division in the ring, i.e. return q such that f = gq. A DivideError() should be thrown if g is zero.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"If check=true the function should check that the division is exact and throw an exception if not.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"If check=false the check may be omitted for performance reasons. The behaviour is then undefined if a division is performed that is not exact. This may include throwing an exception, returning meaningless results, hanging or crashing. The function should only be called with check=false if it is already known that the division will be exact.","category":"page"},{"location":"ring_interface/#Inverse","page":"Ring Interface","title":"Inverse","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"inv(f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return the inverse of f, i.e. 1f, though note that Julia uses / for floating point division. Here we mean exact division in the ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"A fallback for this function is provided in terms of divexact so an implementation can be omitted if preferred.","category":"page"},{"location":"ring_interface/#Unsafe-operators","page":"Ring Interface","title":"Unsafe operators","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"To speed up polynomial and matrix arithmetic, it sometimes makes sense to mutate values in place rather than replace them with a newly created object every time they are modified.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For this purpose, certain mutating operators are required. In order to support immutable types (struct in Julia) and systems that don't have in-place operators, all unsafe operators must return the (ostensibly) mutated value. Only the returned value is used in computations, so this lifts the requirement that the unsafe operators actually mutate the value.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Note the exclamation point is a convention, which indicates that the object may be mutated in-place.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"To make use of these functions, one must be certain that no other references are held to the object being mutated, otherwise those values will also be changed!","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"The results of deepcopy and all arithmetic operations, including powering and division can be assumed to be new objects without other references being held, as can objects returned from constructors.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"note: Note\nIt is important to recognise that R(a) where R is the ring a belongs to, does not create a new value. For this case, use deepcopy(a).","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"zero!(f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Set the value f to zero in place. Return the mutated value.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"mul!(c::MyElem, a::MyElem, b::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Set c to the value ab in place. Return the mutated value. Aliasing is permitted.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"add!(c::MyElem, a::MyElem, b::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Set c to the value a + b in place. Return the mutated value. Aliasing is permitted.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"addeq!(a::MyElem, b::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Set a to a + b in place. Return the mutated value. Aliasing is permitted.","category":"page"},{"location":"ring_interface/#Random-generation","page":"Ring Interface","title":"Random generation","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"The random functions are only used for test code to generate test data. They therefore don't need to provide any guarantees on uniformity, and in fact, test values that are known to be a good source of corner cases can be supplied.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"rand(R::MyParent, v...)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return a random element in the given ring of the specified size.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"There can be as many arguments as is necessary to specify the size of the test example which is being produced.","category":"page"},{"location":"ring_interface/#Promotion-rules","page":"Ring Interface","title":"Promotion rules","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"AbstractAlgebra currently has a very simple coercion model. With few exceptions only simple coercions are supported. For example if x in mathbbZ and y in mathbbZx then x + y can be computed by coercing x into the same ring as y and then adding in that ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Complex coercions such as adding elements of mathbbQ and mathbbZx are not supported, as this would require finding and creating a common overring in which the elements could be added.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"AbstractAlgebra supports simple coercions by overloading parent object call syntax R(x) to coerce the object x into the ring R. However, to coerce elements up a tower of rings, one needs to also have a promotion system similar to Julia's type promotion system.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"As for Julia, AbstractAlgebra's promotion system only specifies what happens to types. It is the coercions themselves that must deal with the mathematical situation at the level of rings, including checking that the object can even be coerced into the given ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"We now describe the required AbstractAlgebra type promotion rules.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For every ring, one wants to be able to coerce integers into the ring. And for any ring constructed over a base ring, one would like to be able to coerce from the base ring into the ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"The required promotion rules to support this look a bit different depending on whether the element type is parameterised or not and whether it is built on a base ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For ring element types MyElem that are neither parameterised nor built over a base ring, the promotion rules can be defined as follows:","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"promote_rule(::Type{MyElem}, ::Type{T}) where {T <: Integer} = MyElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For ring element types MyElem that aren't parameterised, but which have a base ring with concrete element type T the promotion rules can be defined as follows:","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"promote_rule(::Type{MyElem}, ::Type{U}) where U <: Integer = MyElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"promote_rule(::Type{MyElem}, ::Type{T}) = MyElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For ring element types MyElem{T} that are parameterised by the type of elements of the base ring, the promotion rules can be defined as follows:","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"promote_rule(::Type{MyElem{T}}, ::Type{MyElem{T}}) where T <: RingElement = MyElem{T}","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"function promote_rule(::Type{MyElem{T}}, ::Type{U}) where {T <: RingElement, U <: RingElement}\n promote_rule(T, U) == T ? MyElem{T} : Union{}\nend","category":"page"},{"location":"ring_interface/#Required-functionality-for-inexact-rings","page":"Ring Interface","title":"Required functionality for inexact rings","text":"","category":"section"},{"location":"ring_interface/#Approximation-(floating-point-and-ball-arithmetic-only)","page":"Ring Interface","title":"Approximation (floating point and ball arithmetic only)","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"isapprox(f::MyElem, g::MyElem; atol::Real=sqrt(eps()))","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"This is used by test code that uses rings involving floating point or ball arithmetic. The function should return true if all components of f and g are equal to within the square root of the Julia epsilon, since numerical noise may make an exact comparison impossible.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For parameterised rings over an inexact ring, we also require the following ad hoc approximation functionality.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"isapprox(f::MyElem{T}, g::T; atol::Real=sqrt(eps())) where T <: RingElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"isapprox(f::T, g::MyElem{T}; atol::Real=sqrt(eps())) where T <: RingElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"These notionally coerce the element of the base ring into the parameterised ring and do a full comparison.","category":"page"},{"location":"ring_interface/#Optional-functionality","page":"Ring Interface","title":"Optional functionality","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Some functionality is difficult or impossible to implement for all rings in the system. If it is provided, additional functionality or performance may become available. Here is a list of all functions that are considered optional and can't be relied on by generic functions in the AbstractAlgebra Ring interface.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"It may be that no algorithm, or no efficient algorithm is known to implement these functions. As these functions are optional, they do not need to exist. Julia will already inform the user that the function has not been implemented if it is called but doesn't exist.","category":"page"},{"location":"ring_interface/#Optional-basic-manipulation-functionality","page":"Ring Interface","title":"Optional basic manipulation functionality","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"is_unit(f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return true if the given element is a unit in the ring it belongs to.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"is_zero_divisor(f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return true if the given element is a zero divisor in the ring it belongs to. When this function does not exist for a given ring then the total ring of fractions may not be usable over that ring. All fields in the system have a fallback defined for this function.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"characteristic(R::MyParent)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Return the characteristic of the ring. The function should not be defined if it is not possible to unconditionally give the characteristic. AbstractAlgebra will raise an exception is such cases.","category":"page"},{"location":"ring_interface/#Optional-binary-ad-hoc-operators","page":"Ring Interface","title":"Optional binary ad hoc operators","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"By default, ad hoc operations are handled by AbstractAlgebra.jl if they are not defined explicitly, by coercing both operands into the same ring and then performing the required operation.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"In some cases, e.g. for matrices, this leads to very inefficient behaviour. In such cases, it is advised to implement some of these operators explicitly.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"It can occasionally be worth adding a separate set of ad hoc binary operators for the type Int, if this can be done more efficiently than for arbitrary Julia Integer types.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"+(f::MyElem, c::Integer)\n-(f::MyElem, c::Integer)\n*(f::MyElem, c::Integer)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"+(c::Integer, f::MyElem)\n-(c::Integer, f::MyElem)\n*(c::Integer, f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"For parameterised types, it is also sometimes more performant to provide explicit ad hoc operators with elements of the base ring.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"+(f::MyElem{T}, c::T) where T <: RingElem\n-(f::MyElem{T}, c::T) where T <: RingElem\n*(f::MyElem{T}, c::T) where T <: RingElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"+(c::T, f::MyElem{T}) where T <: RingElem\n-(c::T, f::MyElem{T}) where T <: RingElem\n*(c::T, f::MyElem{T}) where T <: RingElem","category":"page"},{"location":"ring_interface/#Optional-ad-hoc-comparisons","page":"Ring Interface","title":"Optional ad hoc comparisons","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"==(f::MyElem, c::Integer)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"==(c::Integer, f::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"==(f::MyElem{T}, c:T) where T <: RingElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"==(c::T, f::MyElem{T}) where T <: RingElem","category":"page"},{"location":"ring_interface/#Optional-ad-hoc-exact-division-functions","page":"Ring Interface","title":"Optional ad hoc exact division functions","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"divexact(a::MyElem{T}, b::T) where T <: RingElem","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"divexact(a::MyElem, b::Integer)","category":"page"},{"location":"ring_interface/#Optional-powering-functions","page":"Ring Interface","title":"Optional powering functions","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"^(f::MyElem, e::BigInt)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"In case f cannot explode in size when powered by a very large integer, and it is practical to do so, one may provide this function to support powering with BigInt exponents (or for external modules, any other big integer type).","category":"page"},{"location":"ring_interface/#Optional-unsafe-operators","page":"Ring Interface","title":"Optional unsafe operators","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"addmul!(c::MyElem, a::MyElem, b::MyElem, t::MyElem)","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Set c = c + ab in-place. Return the mutated value. The value t should be a temporary of the same type as a, b and c, which can be used arbitrarily by the implementation to speed up the computation. Aliasing between a, b and c is permitted.","category":"page"},{"location":"ring_interface/#Minimal-example-of-ring-implementation","page":"Ring Interface","title":"Minimal example of ring implementation","text":"","category":"section"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"Here is a minimal example of implementing the Ring Interface for a constant polynomial type (i.e. polynomials of degree less than one).","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"# ConstPoly.jl : Implements constant polynomials\n\nusing AbstractAlgebra\n\nusing Random: Random, SamplerTrivial, GLOBAL_RNG\nusing RandomExtensions: RandomExtensions, Make2, AbstractRNG\n\nimport AbstractAlgebra: parent_type, elem_type, base_ring, parent, is_domain_type,\n is_exact_type, canonical_unit, isequal, divexact, zero!, mul!, add!, addeq!,\n get_cached!, is_unit, characteristic, Ring, RingElem, expressify\n\nimport Base: show, +, -, *, ^, ==, inv, isone, iszero, one, zero, rand,\n deepcopy_internal, hash\n\nmutable struct ConstPolyRing{T <: RingElement} <: Ring\n base_ring::Ring\n\n function ConstPolyRing{T}(R::Ring, cached::Bool) where T <: RingElement\n return get_cached!(ConstPolyID, R, cached) do\n new{T}(R)\n end::ConstPolyRing{T}\n end\nend\n\nconst ConstPolyID = AbstractAlgebra.CacheDictType{Ring, ConstPolyRing}()\n \nmutable struct ConstPoly{T <: RingElement} <: RingElem\n c::T\n parent::ConstPolyRing{T}\n\n function ConstPoly{T}(c::T) where T <: RingElement\n return new(c)\n end\nend\n\n# Data type and parent object methods\n\nparent_type(::Type{ConstPoly{T}}) where T <: RingElement = ConstPolyRing{T}\n\nelem_type(::Type{ConstPolyRing{T}}) where T <: RingElement = ConstPoly{T}\n\nbase_ring(R::ConstPolyRing) = R.base_ring\n\nparent(f::ConstPoly) = f.parent\n\nis_domain_type(::Type{ConstPoly{T}}) where T <: RingElement = is_domain_type(T)\n\nis_exact_type(::Type{ConstPoly{T}}) where T <: RingElement = is_exact_type(T)\n\nfunction hash(f::ConstPoly, h::UInt)\n r = 0x65125ab8e0cd44ca\n return xor(r, hash(f.c, h))\nend\n\nfunction deepcopy_internal(f::ConstPoly{T}, dict::IdDict) where T <: RingElement\n r = ConstPoly{T}(deepcopy_internal(f.c, dict))\n r.parent = f.parent # parent should not be deepcopied\n return r\nend\n\n# Basic manipulation\n\nzero(R::ConstPolyRing) = R()\n\none(R::ConstPolyRing) = R(1)\n\niszero(f::ConstPoly) = iszero(f.c)\n\nisone(f::ConstPoly) = isone(f.c)\n\nis_unit(f::ConstPoly) = is_unit(f.c)\n\ncharacteristic(R::ConstPolyRing) = characteristic(base_ring(R))\n\n# Canonical unit\n\ncanonical_unit(f::ConstPoly) = canonical_unit(f.c)\n\n# String I/O\n\nfunction show(io::IO, R::ConstPolyRing)\n print(io, \"Constant polynomials over \")\n show(io, base_ring(R))\nend\n\nfunction show(io::IO, f::ConstPoly)\n print(io, f.c)\nend\n\n# Expressification (optional)\n\nfunction expressify(R::ConstPolyRing; context = nothing)\n return Expr(:sequence, Expr(:text, \"Constant polynomials over \"),\n expressify(base_ring(R), context = context))\nend\n\nfunction expressify(f::ConstPoly; context = nothing)\n return expressify(f.c, context = context)\nend\n\n# Unary operations\n\nfunction -(f::ConstPoly)\n R = parent(f)\n return R(-f.c)\nend\n\n# Binary operations\n\nfunction +(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement\n parent(f) != parent(g) && error(\"Incompatible rings\")\n R = parent(f)\n return R(f.c + g.c)\nend\n\nfunction -(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement\n parent(f) != parent(g) && error(\"Incompatible rings\")\n R = parent(f)\n return R(f.c - g.c)\nend\n\nfunction *(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement\n parent(f) != parent(g) && error(\"Incompatible rings\")\n R = parent(f)\n return R(f.c*g.c)\nend\n\n# Comparison\n\nfunction ==(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement\n parent(f) != parent(g) && error(\"Incompatible rings\")\n return f.c == g.c\nend\n\nfunction isequal(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement\n parent(f) != parent(g) && error(\"Incompatible rings\")\n return isequal(f.c, g.c)\nend\n\n# Powering need not be implemented if * is\n\n# Exact division\n\nfunction divexact(f::ConstPoly{T}, g::ConstPoly{T}; check::Bool = true) where T <: RingElement\n parent(f) != parent(g) && error(\"Incompatible rings\")\n R = parent(f)\n return R(divexact(f.c, g.c, check = check))\nend\n\n# Inverse\n\nfunction inv(f::ConstPoly)\n R = parent(f)\n return R(AbstractAlgebra.inv(f.c))\nend\n\n# Unsafe operators\n\nfunction zero!(f::ConstPoly)\n f.c = zero(base_ring(parent(f)))\n return f\nend\n\nfunction mul!(f::ConstPoly{T}, g::ConstPoly{T}, h::ConstPoly{T}) where T <: RingElement\n f.c = g.c*h.c\n return f\nend\n\nfunction add!(f::ConstPoly{T}, g::ConstPoly{T}, h::ConstPoly{T}) where T <: RingElement\n f.c = g.c + h.c\n return f\nend\n\nfunction addeq!(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement\n f.c += g.c\n return f\nend\n\n# Random generation\n\nRandomExtensions.maketype(R::ConstPolyRing, _) = elem_type(R)\n\nrand(rng::AbstractRNG, sp::SamplerTrivial{<:Make2{ConstPoly,ConstPolyRing}}) =\n sp[][1](rand(rng, sp[][2]))\n\nrand(rng::AbstractRNG, R::ConstPolyRing, n::AbstractUnitRange{Int}) = R(rand(rng, n))\n\nrand(R::ConstPolyRing, n::AbstractUnitRange{Int}) = rand(Random.GLOBAL_RNG, R, n)\n\n# Promotion rules\n\npromote_rule(::Type{ConstPoly{T}}, ::Type{ConstPoly{T}}) where T <: RingElement = ConstPoly{T}\n\nfunction promote_rule(::Type{ConstPoly{T}}, ::Type{U}) where {T <: RingElement, U <: RingElement}\n promote_rule(T, U) == T ? ConstPoly{T} : Union{}\nend\n\n# Constructors\n\nfunction (R::ConstPolyRing{T})() where T <: RingElement\n r = ConstPoly{T}(base_ring(R)(0))\n r.parent = R\n return r\nend\n\nfunction (R::ConstPolyRing{T})(c::Integer) where T <: RingElement\n r = ConstPoly{T}(base_ring(R)(c))\n r.parent = R\n return r\nend\n\n# Needed to prevent ambiguity\nfunction (R::ConstPolyRing{T})(c::T) where T <: Integer\n r = ConstPoly{T}(base_ring(R)(c))\n r.parent = R\n return r\nend\n\nfunction (R::ConstPolyRing{T})(c::T) where T <: RingElement\n base_ring(R) != parent(c) && error(\"Unable to coerce element\")\n r = ConstPoly{T}(c)\n r.parent = R\n return r\nend\n\nfunction (R::ConstPolyRing{T})(f::ConstPoly{T}) where T <: RingElement\n R != parent(f) && error(\"Unable to coerce element\")\n return f\nend\n\n# Parent constructor\n\nfunction ConstantPolynomialRing(R::Ring, cached::Bool=true)\n T = elem_type(R)\n return ConstPolyRing{T}(R, cached)\nend","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"The above implementation of ConstantPolynomialRing may be tested as follows.","category":"page"},{"location":"ring_interface/","page":"Ring Interface","title":"Ring Interface","text":"using Test\ninclude(joinpath(pathof(AbstractAlgebra), \"..\", \"..\", \"test\", \"Rings-conformance-tests.jl\"))\n\nS, _ = polynomial_ring(QQ, \"x\")\n\nfunction test_elem(R::ConstPolyRing{elem_type(S)})\n return R(rand(base_ring(R), 1:6, -999:999))\nend\n\ntest_Ring_interface(ConstantPolynomialRing(S))","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"fraction_interface/#Fraction-Field-Interface","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"","category":"section"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Fraction fields are supported in AbstractAlgebra.jl, at least for gcd domains. In addition to the standard Ring interface, some additional functions are required to be present for fraction fields.","category":"page"},{"location":"fraction_interface/#Types-and-parents","page":"Fraction Field Interface","title":"Types and parents","text":"","category":"section"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"AbstractAlgebra provides two abstract types for fraction fields and their elements:","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"FracField{T} is the abstract type for fraction field parent types\nFracElem{T} is the abstract type for types of fractions","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"We have that FracField{T} <: Field and FracElem{T} <: FieldElem.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Note that both abstract types are parameterised. The type T should usually be the type of elements of the base ring of the fraction field.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Fraction fields should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Fraction fields should at least be distinguished based on their base ring.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).","category":"page"},{"location":"fraction_interface/#Required-functionality-for-fraction-fields","page":"Fraction Field Interface","title":"Required functionality for fraction fields","text":"","category":"section"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"In addition to the required functionality for the Field interface the Fraction Field interface has the following required functions.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"We suppose that R is a fictitious base ring, and that S is the fraction field with parent object S of type MyFracField{T}. We also assume the fractions in the field have type MyFrac{T}, where T is the type of elements of the base ring.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Note that the type T must (transitively) belong to the abstract type RingElem.","category":"page"},{"location":"fraction_interface/#Constructors","page":"Fraction Field Interface","title":"Constructors","text":"","category":"section"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"The following constructors create fractions. Note that these constructors don't require construction of the parent object first. This is easier to achieve if the fraction element type doesn't contain a reference to the parent object, but merely contains a reference to the base ring. The parent object can then be constructed on demand.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"//(x::T, y::T) where T <: RingElem","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Return the fraction xy.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"//(x::T, y::FracElem{T}) where T <: RingElem","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Return xy where x is in the base ring of y.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"//(x::FracElem{T}, y::T) where T <: RingElem","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Return xy where y is in the base ring of x.","category":"page"},{"location":"fraction_interface/#Basic-manipulation-of-fields-and-elements","page":"Fraction Field Interface","title":"Basic manipulation of fields and elements","text":"","category":"section"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"numerator(d::MyFrac{T}) where T <: RingElem","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Given a fraction d = ab return a, where ab is in lowest terms with respect to the canonical_unit and gcd functions on the base ring.","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"denominator(d::MyFrac{T}) where T <: RingElem","category":"page"},{"location":"fraction_interface/","page":"Fraction Field Interface","title":"Fraction Field Interface","text":"Given a fraction d = ab return b, where ab is in lowest terms with respect to the canonical_unit and gcd functions on the base ring.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"fraction/#Generic-fraction-fields","page":"Generic fraction fields","title":"Generic fraction fields","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"AbstractAlgebra.jl provides a module, implemented in src/Fraction.jl for fraction fields over any gcd domain belonging to the AbstractAlgebra.jl abstract type hierarchy.","category":"page"},{"location":"fraction/#Generic-fraction-types","page":"Generic fraction fields","title":"Generic fraction types","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"AbstractAlgebra.jl implements a generic fraction type Generic.FracFieldElem{T} where T is the type of elements of the base ring. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Parent objects of such fraction elements have type Generic.FracField{T}.","category":"page"},{"location":"fraction/#Factored-fraction-types","page":"Generic fraction fields","title":"Factored fraction types","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"AbstractAlgebra.jl also implements a fraction type Generic.FactoredFracFieldElem{T} with parent objects of such fractions having type Generic.FactoredFracField{T}. As opposed to the fractions of type Generic.FracFieldElem{T}, which are just a numerator and denominator, these fractions are maintained in factored form as much as possible.","category":"page"},{"location":"fraction/#Abstract-types","page":"Generic fraction fields","title":"Abstract types","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"All fraction element types belong to the abstract type FracElem{T} and the fraction field types belong to the abstract type FracField{T}. This enables one to write generic functions that can accept any AbstractAlgebra fraction type.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"note: Note\nBoth the generic fraction field type Generic.FracField{T} and the abstract type it belongs to, FracField{T} are both called FracField. The former is a (parameterised) concrete type for a fraction field over a given base ring whose elements have type T. The latter is an abstract type representing all fraction field types in AbstractAlgebra.jl, whether generic or very specialised (e.g. supplied by a C library).","category":"page"},{"location":"fraction/#Fraction-field-constructors","page":"Generic fraction fields","title":"Fraction field constructors","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"In order to construct fractions in AbstractAlgebra.jl, one can first construct the fraction field itself. This is accomplished with the following constructor.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"fraction_field(R::Ring; cached::Bool = true)","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Given a base ring R return the parent object of the fraction field of R. By default the parent object S will depend only on R and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Here are some examples of creating fraction fields and making use of the resulting parent objects to coerce various elements into the fraction field.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S = fraction_field(R)\nFraction field\n of univariate polynomial ring in x over integers\n\njulia> f = S()\n0\n\njulia> g = S(123)\n123\n\njulia> h = S(BigInt(1234))\n1234\n\njulia> k = S(x + 1)\nx + 1","category":"page"},{"location":"fraction/#Factored-Fraction-field-constructors","page":"Generic fraction fields","title":"Factored Fraction field constructors","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"The corresponding factored field uses the following constructor.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"FactoredFractionField(R::Ring; cached::Bool = true)","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> R, (x, y) = polynomial_ring(ZZ, [\"x\", \"y\"])\n(Multivariate polynomial ring in 2 variables over integers, AbstractAlgebra.Generic.MPoly{BigInt}[x, y])\n\njulia> S = FactoredFractionField(R)\nFactored fraction field of Multivariate polynomial ring in 2 variables over integers\n\njulia> (X, Y) = (S(x), S(y))\n(x, y)\n\njulia> f = X^6*(X+Y)^2*(X^2+Y)^3*(X+2*Y)^-3*(X+3*Y)^-4\nx^6*(x + y)^2*(x^2 + y)^3/((x + 2*y)^3*(x + 3*y)^4)\n\njulia> numerator(f)\nx^14 + 2*x^13*y + x^12*y^2 + 3*x^12*y + 6*x^11*y^2 + 3*x^10*y^3 + 3*x^10*y^2 + 6*x^9*y^3 + 3*x^8*y^4 + x^8*y^3 + 2*x^7*y^4 + x^6*y^5\n\njulia> denominator(f)\nx^7 + 18*x^6*y + 138*x^5*y^2 + 584*x^4*y^3 + 1473*x^3*y^4 + 2214*x^2*y^5 + 1836*x*y^6 + 648*y^7\n\njulia> derivative(f, x)\nx^5*(x + y)*(x^2 + y)^2*(7*x^5 + 58*x^4*y + 127*x^3*y^2 + x^3*y + 72*x^2*y^3 + 22*x^2*y^2 + 61*x*y^3 + 36*y^4)/((x + 2*y)^4*(x + 3*y)^5)","category":"page"},{"location":"fraction/#Fraction-constructors","page":"Generic fraction fields","title":"Fraction constructors","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"One can construct fractions using the fraction field parent object, as for any ring or field.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"(R::FracField)() # constructs zero\n(R::FracField)(c::Integer)\n(R::FracField)(c::elem_type(R))\n(R::FracField{T})(a::T) where T <: RingElement","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"One may also use the Julia double slash operator to construct elements of the fraction field without constructing the fraction field parent first.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"//(x::T, y::T) where T <: RingElement","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S = fraction_field(R)\nFraction field\n of univariate polynomial ring in x over rationals\n\njulia> f = S(x + 1)\nx + 1\n\njulia> g = (x^2 + x + 1)//(x^3 + 3x + 1)\n(x^2 + x + 1)//(x^3 + 3*x + 1)\n\njulia> x//f\nx//(x + 1)\n\njulia> f//x\n(x + 1)//x","category":"page"},{"location":"fraction/#Functions-for-types-and-parents-of-fraction-fields","page":"Generic fraction fields","title":"Functions for types and parents of fraction fields","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Fraction fields in AbstractAlgebra.jl implement the Ring interface.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"base_ring(R::FracField)\nbase_ring(a::FracElem)","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Return the base ring of which the fraction field was constructed.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"parent(a::FracElem)","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Return the fraction field of the given fraction.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"characteristic(R::FracField)","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Return the characteristic of the base ring of the fraction field. If the characteristic is not known an exception is raised.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S = fraction_field(R)\nFraction field\n of univariate polynomial ring in x over rationals\n\njulia> f = S(x + 1)\nx + 1\n\njulia> U = base_ring(S)\nUnivariate polynomial ring in x over rationals\n\njulia> V = base_ring(f)\nUnivariate polynomial ring in x over rationals\n\njulia> T = parent(f)\nFraction field\n of univariate polynomial ring in x over rationals\n\njulia> m = characteristic(S)\n0","category":"page"},{"location":"fraction/#Fraction-field-functions","page":"Generic fraction fields","title":"Fraction field functions","text":"","category":"section"},{"location":"fraction/#Basic-functions","page":"Generic fraction fields","title":"Basic functions","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Fraction fields implement the Ring interface.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"zero(R::FracField)\none(R::FracField)\niszero(a::FracElem)\nisone(a::FracElem)","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"inv(a::T) where T <: FracElem","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"They also implement the field interface.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"is_unit(f::FracElem)","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"And they implement the fraction field interface.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"numerator(a::FracElem)\ndenominator(a::FracElem)","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S = fraction_field(R)\nFraction field\n of univariate polynomial ring in x over rationals\n\njulia> f = S(x + 1)\nx + 1\n\njulia> g = (x^2 + x + 1)//(x^3 + 3x + 1)\n(x^2 + x + 1)//(x^3 + 3*x + 1)\n\njulia> h = zero(S)\n0\n\njulia> k = one(S)\n1\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> r = deepcopy(f)\nx + 1\n\njulia> n = numerator(g)\nx^2 + x + 1\n\njulia> d = denominator(g)\nx^3 + 3*x + 1","category":"page"},{"location":"fraction/#Greatest-common-divisor","page":"Generic fraction fields","title":"Greatest common divisor","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"gcd{T <: RingElem}(::FracElem{T}, ::FracElem{T})","category":"page"},{"location":"fraction/#Base.gcd-Union{Tuple{T}, Tuple{FracElem{T}, FracElem{T}}} where T<:RingElem","page":"Generic fraction fields","title":"Base.gcd","text":"gcd(a::FracElem{T}, b::FracElem{T}) where {T <: RingElem}\n\nReturn a greatest common divisor of a and b if one exists. N.B: we define the GCD of ab and cd to be gcd(ad bc)bd, reduced to lowest terms. This requires the existence of a greatest common divisor function for the base ring.\n\n\n\n\n\n","category":"method"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> f = (x + 1)//(x^3 + 3x + 1)\n(x + 1)//(x^3 + 3*x + 1)\n\njulia> g = (x^2 + 2x + 1)//(x^2 + x + 1)\n(x^2 + 2*x + 1)//(x^2 + x + 1)\n\njulia> h = gcd(f, g)\n(x + 1)//(x^5 + x^4 + 4*x^3 + 4*x^2 + 4*x + 1)\n","category":"page"},{"location":"fraction/#Square-root","page":"Generic fraction fields","title":"Square root","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"is_square{T <: RingElem}(::FracElem{T})","category":"page"},{"location":"fraction/#AbstractAlgebra.is_square-Union{Tuple{FracElem{T}}, Tuple{T}} where T<:RingElem","page":"Generic fraction fields","title":"AbstractAlgebra.is_square","text":"is_square(a::FracElem{T}) where T <: RingElem\n\nReturn true if a is a square.\n\n\n\n\n\n","category":"method"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Base.sqrt(::FracElem{T}) where {T <: RingElem}","category":"page"},{"location":"fraction/#Base.sqrt-Union{Tuple{FracElem{T}}, Tuple{T}} where T<:RingElem","page":"Generic fraction fields","title":"Base.sqrt","text":"Base.sqrt(a::FracElem{T}; check::Bool=true) where T <: RingElem\n\nReturn the square root of a. By default the function will throw an exception if the input is not square. If check=false this test is omitted.\n\n\n\n\n\n","category":"method"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S = fraction_field(R)\nFraction field\n of univariate polynomial ring in x over rationals\n\njulia> a = (21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)\n(21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)\n\njulia> sqrt(a^2)\n(21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)\n\njulia> is_square(a^2)\ntrue","category":"page"},{"location":"fraction/#Remove-and-valuation","page":"Generic fraction fields","title":"Remove and valuation","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"When working over a Euclidean domain, it is convenient to extend valuations to the fraction field. To facilitate this, we define the following functions.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"remove{T <: RingElem}(::FracElem{T}, ::T)","category":"page"},{"location":"fraction/#AbstractAlgebra.remove-Union{Tuple{T}, Tuple{FracElem{T}, T}} where T<:RingElem","page":"Generic fraction fields","title":"AbstractAlgebra.remove","text":"remove(z::FracElem{T}, p::T) where {T <: RingElem}\n\nReturn the tuple n x such that z = p^nx where x has valuation 0 at p.\n\n\n\n\n\n","category":"method"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"valuation{T <: RingElem}(::FracElem{T}, ::T)","category":"page"},{"location":"fraction/#AbstractAlgebra.valuation-Union{Tuple{T}, Tuple{FracElem{T}, T}} where T<:RingElem","page":"Generic fraction fields","title":"AbstractAlgebra.valuation","text":"valuation(z::FracElem{T}, p::T) where {T <: RingElem}\n\nReturn the valuation of z at p.\n\n\n\n\n\n","category":"method"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> f = (x + 1)//(x^3 + 3x + 1)\n(x + 1)//(x^3 + 3*x + 1)\n\njulia> g = (x^2 + 1)//(x^2 + x + 1)\n(x^2 + 1)//(x^2 + x + 1)\n\njulia> v, q = remove(f^3*g, x + 1)\n(3, (x^2 + 1)//(x^11 + x^10 + 10*x^9 + 12*x^8 + 39*x^7 + 48*x^6 + 75*x^5 + 75*x^4 + 66*x^3 + 37*x^2 + 10*x + 1))\n\njulia> v = valuation(f^3*g, x + 1)\n3\n","category":"page"},{"location":"fraction/#Random-generation","page":"Generic fraction fields","title":"Random generation","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Random fractions can be generated using rand. The parameters passed after the fraction field tell rand how to generate random elements of the base ring.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"rand(R::FracField, v...)","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> K = fraction_field(ZZ)\nRationals\n\njulia> f = rand(K, -10:10)\n-1//3\n\njulia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S = fraction_field(R)\nFraction field\n of univariate polynomial ring in x over integers\n\njulia> g = rand(S, -1:3, -10:10)\n(-4*x - 4)//(4*x^2 + x - 4)","category":"page"},{"location":"fraction/#Extra-functionality-for-factored-fractions","page":"Generic fraction fields","title":"Extra functionality for factored fractions","text":"","category":"section"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"The Generic.FactoredFracFieldElem{T} type implements an interface similar to that of the Fac{T} type for iterating over the terms in the factorisation. There is also the function push_term!(a, b, e) for efficiently performing a *= b^e, and the function normalise returns relatively prime terms.","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"Examples","category":"page"},{"location":"fraction/","page":"Generic fraction fields","title":"Generic fraction fields","text":"julia> F = FactoredFractionField(ZZ)\nFactored fraction field of Integers\n\njulia> f = F(-1)\n-1\n\njulia> push_term!(f, 10, 10)\n-10^10\n\njulia> push_term!(f, 42, -8)\n-10^10/42^8\n\njulia> normalise(f)\n-5^10*2^2/21^8\n\njulia> unit(f)\n-1\n\njulia> collect(f)\n2-element Vector{Tuple{BigInt, Int64}}:\n (10, 10)\n (42, -8)","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"function_field/#Rational-function-fields","page":"Rational function fields","title":"Rational function fields","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"AbstractAlgebra.jl provides a module, implemented in src/generic/RationalFunctionField.jl for rational function fields k(x) or k[x_1, x_2, \\ldots, x_n] over a field k.","category":"page"},{"location":"function_field/#Generic-rational-function-field-type","page":"Rational function fields","title":"Generic rational function field type","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Rational functions have type Generic.RationalFunctionFieldElem{T, U} where T is the type of elements of the coefficient field k and U is the type of polynomials (either univariate or multivariate) over that field. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Parent objects corresponding to the rational function field k have type Generic.RationalFunctionField{T, U}.","category":"page"},{"location":"function_field/#Abstract-types","page":"Rational function fields","title":"Abstract types","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"The rational function types belong to the abstract type Field and the rational function field types belong to the abstract type FieldElem.","category":"page"},{"location":"function_field/#Rational-function-field-constructors","page":"Rational function fields","title":"Rational function field constructors","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"In order to construct rational functions in AbstractAlgebra.jl, one can first construct the function field itself. This is accomplished with one of the following constructors.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"rational_function_field(k::Field, s::VarName; cached::Bool = true)\nrational_function_field(k::Field, s::Vector{<:VarName}; cached::Bool = true)","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Given a coefficient field k return a tuple (S, x) consisting of the parent object of the rational function field over k and the generator(s) x. By default the parent object S will depend only on R and s and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Here are some examples of creating rational function fields and making use of the resulting parent objects to coerce various elements into the function field.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Examples","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"julia> S, x = rational_function_field(QQ, \"x\")\n(Rational function field over rationals, x)\n\njulia> f = S()\n0\n\njulia> g = S(123)\n123\n\njulia> h = S(BigInt(1234))\n1234\n\njulia> k = S(x + 1)\nx + 1\n\njulia> m = S(numerator(x + 1, false), numerator(x + 2, false))\n(x + 1)//(x + 2)\n\njulia> R, (x, y) = rational_function_field(QQ, [\"x\", \"y\"])\n(Rational function field over rationals, AbstractAlgebra.Generic.RationalFunctionFieldElem{Rational{BigInt}, AbstractAlgebra.Generic.MPoly{Rational{BigInt}}}[x, y])\n\njulia> (x + y)//y^2\n(x + y)//y^2","category":"page"},{"location":"function_field/#Basic-rational-function-field-functionality","page":"Rational function fields","title":"Basic rational function field functionality","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Fraction fields in AbstractAlgebra.jl implement the full Field interface and the entire fraction field interface.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"We give some examples of such functionality.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Examples","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"julia> S, x = rational_function_field(QQ, \"x\")\n(Rational function field over rationals, x)\n\njulia> f = S(x + 1)\nx + 1\n\njulia> g = (x^2 + x + 1)//(x^3 + 3x + 1)\n(x^2 + x + 1)//(x^3 + 3*x + 1)\n\njulia> h = zero(S)\n0\n\njulia> k = one(S)\n1\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> m = characteristic(S)\n0\n\njulia> U = base_ring(S)\nRationals\n\njulia> V = base_ring(f)\nRationals\n\njulia> T = parent(f)\nRational function field\n over rationals\n\njulia> r = deepcopy(f)\nx + 1\n\njulia> n = numerator(g)\nx^2 + x + 1\n\njulia> d = denominator(g)\nx^3 + 3*x + 1\n","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Note that numerator and denominator are returned as elements of a polynomial ring whose variable is printed the same way as that of the generator of the rational function field.","category":"page"},{"location":"function_field/#Rational-function-field-functionality-provided-by-AbstractAlgebra.jl","page":"Rational function fields","title":"Rational function field functionality provided by AbstractAlgebra.jl","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"The following functionality is provided for rational function fields.","category":"page"},{"location":"function_field/#Greatest-common-divisor","page":"Rational function fields","title":"Greatest common divisor","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"gcd(::Generic.RationalFunctionFieldElem{T, U}, ::Generic.RationalFunctionFieldElem{T, U}) where {T <: FieldElement, U <: Union{PolyRingElem, MPolyRingElem}}","category":"page"},{"location":"function_field/#Base.gcd-Union{Tuple{U}, Tuple{T}, Tuple{AbstractAlgebra.Generic.RationalFunctionFieldElem{T, U}, AbstractAlgebra.Generic.RationalFunctionFieldElem{T, U}}} where {T<:FieldElement, U<:Union{MPolyRingElem, PolyRingElem}}","page":"Rational function fields","title":"Base.gcd","text":"gcd(a::RationalFunctionFieldElem{T, U}, b::RationalFunctionFieldElem{T, U}) where {T <: FieldElement, U <: Union{PolyRingElem, MPolyRingElem}}\n\nReturn a greatest common divisor of a and b if one exists. N.B: we define the GCD of ab and cd to be gcd(ad bc)bd, reduced to lowest terms.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Examples","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"julia> R, x = rational_function_field(QQ, \"x\")\n(Rational function field over rationals, x)\n\njulia> f = (x + 1)//(x^3 + 3x + 1)\n(x + 1)//(x^3 + 3*x + 1)\n\njulia> g = (x^2 + 2x + 1)//(x^2 + x + 1)\n(x^2 + 2*x + 1)//(x^2 + x + 1)\n\njulia> h = gcd(f, g)\n(x + 1)//(x^5 + x^4 + 4*x^3 + 4*x^2 + 4*x + 1)\n","category":"page"},{"location":"function_field/#Square-root","page":"Rational function fields","title":"Square root","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"is_square(::Generic.RationalFunctionFieldElem{T, U}) where {T <: FieldElem, U <: Union{PolyRingElem, MPolyRingElem}}","category":"page"},{"location":"function_field/#AbstractAlgebra.is_square-Union{Tuple{AbstractAlgebra.Generic.RationalFunctionFieldElem{T, U}}, Tuple{U}, Tuple{T}} where {T<:FieldElem, U<:Union{MPolyRingElem, PolyRingElem}}","page":"Rational function fields","title":"AbstractAlgebra.is_square","text":"is_square(f::PolyRingElem{T}) where T <: RingElement\n\nReturn true if f is a perfect square.\n\n\n\n\n\nis_square(a::FracElem{T}) where T <: RingElem\n\nReturn true if a is a square.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Base.sqrt(::Generic.RationalFunctionFieldElem{T, U}) where {T <: FieldElem, U <: Union{PolyRingElem, MPolyRingElem}}","category":"page"},{"location":"function_field/#Base.sqrt-Union{Tuple{AbstractAlgebra.Generic.RationalFunctionFieldElem{T, U}}, Tuple{U}, Tuple{T}} where {T<:FieldElem, U<:Union{MPolyRingElem, PolyRingElem}}","page":"Rational function fields","title":"Base.sqrt","text":"Base.sqrt(f::PolyRingElem{T}; check::Bool=true) where T <: RingElement\n\nReturn the square root of f. By default the function checks the input is square and raises an exception if not. If check=false this check is omitted.\n\n\n\n\n\nBase.sqrt(a::FracElem{T}; check::Bool=true) where T <: RingElem\n\nReturn the square root of a. By default the function will throw an exception if the input is not square. If check=false this test is omitted.\n\n\n\n\n\nsqrt(a::Generic.PuiseuxSeriesElem{T}; check::Bool=true) where T <: RingElement\n\nReturn the square root of the given Puiseux series a. By default the function will throw an exception if the input is not square. If check=false this test is omitted.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Examples","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"julia> R, x = rational_function_field(QQ, \"x\")\n(Rational function field over rationals, x)\n\njulia> a = (21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)\n(21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)\n\njulia> sqrt(a^2)\n(21//4*x^6 - 15*x^5 + 27//14*x^4 + 9//20*x^3 + 3//7*x + 9//10)//(x + 3)\n\njulia> is_square(a^2)\ntrue","category":"page"},{"location":"function_field/#Univariate-function-fields","page":"Rational function fields","title":"Univariate function fields","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Univariate function fields in AbstractAlgebra are algebraic extensions Kk(x) of a rational function field k(x) over a field k.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"These are implemented in a module implemented in src/generic/FunctionField.jl.","category":"page"},{"location":"function_field/#Generic-function-field-types","page":"Rational function fields","title":"Generic function field types","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Function field objects Kk(x) in AbstractAlgebra have type Generic.FunctionField{T} where T is the type of elements of the field k.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Corresponding function field elements have type Generic.FunctionFieldElement{T}. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"function_field/#Abstract-types-2","page":"Rational function fields","title":"Abstract types","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Function field types belong to the abstract type Field and their elements to the abstract type FieldElem.","category":"page"},{"location":"function_field/#Function-field-constructors","page":"Rational function fields","title":"Function field constructors","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"In order to construct function fields in AbstractAlgebra.jl, one first constructs the rational function field they are an extension of, then supplies a polynomial over this field to the following constructor:","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"function_field(p::Poly{RationalFunctionFieldElem{T, U}}, s::AbstractString; cached::Bool=true) where {T <: FieldElement, U <: PolyRingElem{T}}","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Given an irreducible polynomial p over a rational function field return a tuple (S, z) consisting of the parent object of the function field defined by that polynomial over k(x) and the generator z. By default the parent object S will depend only on p and s and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Here are some examples of creating function fields and making use of the resulting parent objects to coerce various elements into the function field.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Examples","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"julia> R1, x1 = rational_function_field(QQ, \"x1\") # characteristic 0\n(Rational function field over rationals, x1)\n\njulia> U1, z1 = R1[\"z1\"]\n(Univariate polynomial ring in z1 over rational function field, z1)\n\njulia> f = (x1^2 + 1)//(x1 + 1)*z1^3 + 4*z1 + 1//(x1 + 1)\n(x1^2 + 1)//(x1 + 1)*z1^3 + 4*z1 + 1//(x1 + 1)\n\njulia> S1, y1 = function_field(f, \"y1\")\n(Function Field over Rationals with defining polynomial (x1^2 + 1)*y1^3 + (4*x1 + 4)*y1 + 1, y1)\n\njulia> a = S1()\n0\n\njulia> b = S1((x1 + 1)//(x1 + 2))\n(x1 + 1)//(x1 + 2)\n\njulia> c = S1(1//3)\n1//3\n\njulia> R2, x2 = rational_function_field(GF(23), \"x1\") # characteristic p\n(Rational function field over finite field F_23, x1)\n\njulia> U2, z2 = R2[\"z2\"]\n(Univariate polynomial ring in z2 over rational function field, z2)\n\njulia> g = z2^2 + 3z2 + 1\nz2^2 + 3*z2 + 1\n\njulia> S2, y2 = function_field(g, \"y2\")\n(Function Field over Finite field F_23 with defining polynomial y2^2 + 3*y2 + 1, y2)\n\njulia> d = S2(R2(5))\n5\n\njulia> e = S2(y2)\ny2","category":"page"},{"location":"function_field/#Basic-function-field-functionality","page":"Rational function fields","title":"Basic function field functionality","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Function fields implement the full Ring and Field interfaces. We give some examples of such functionality.","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Examples","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"julia> R, x = rational_function_field(GF(23), \"x\") # characteristic p\n(Rational function field over finite field F_23, x)\n\njulia> U, z = R[\"z\"]\n(Univariate polynomial ring in z over rational function field, z)\n\njulia> g = z^2 + 3z + 1\nz^2 + 3*z + 1\n\njulia> S, y = function_field(g, \"y\")\n(Function Field over Finite field F_23 with defining polynomial y^2 + 3*y + 1, y)\n\njulia> f = (x + 1)*y + 1\n(x + 1)*y + 1\n\njulia> base_ring(f)\nRational function field\n over finite field F_23\n\njulia> f^2\n(20*x^2 + 19*x + 22)*y + 22*x^2 + 21*x\n\njulia> f*inv(f)\n1","category":"page"},{"location":"function_field/#Function-field-functionality-provided-by-AbstractAlgebra.jl","page":"Rational function fields","title":"Function field functionality provided by AbstractAlgebra.jl","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"The following functionality is provided for function fields.","category":"page"},{"location":"function_field/#Basic-manipulation","page":"Rational function fields","title":"Basic manipulation","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"base_field(::Generic.FunctionField)","category":"page"},{"location":"function_field/#AbstractAlgebra.Generic.base_field-Tuple{AbstractAlgebra.Generic.FunctionField}","page":"Rational function fields","title":"AbstractAlgebra.Generic.base_field","text":"base_field(R::FunctionField)\n\nReturn the rational function field that the field R is an extension of. Synonymous with base_ring.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"var(::Generic.FunctionField)","category":"page"},{"location":"function_field/#AbstractAlgebra.var-Tuple{AbstractAlgebra.Generic.FunctionField}","page":"Rational function fields","title":"AbstractAlgebra.var","text":"var(R::FunctionField)\n\nReturn the variable name of the generator of the function field R as a symbol.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"characteristic(S::Generic.FunctionField)","category":"page"},{"location":"function_field/#AbstractAlgebra.characteristic-Tuple{AbstractAlgebra.Generic.FunctionField}","page":"Rational function fields","title":"AbstractAlgebra.characteristic","text":"characteristic(R::FunctionField)\n\nReturn the characteristic of the underlying rational function field.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"defining_polynomial(R::Generic.FunctionField)","category":"page"},{"location":"function_field/#AbstractAlgebra.Generic.defining_polynomial-Tuple{AbstractAlgebra.Generic.FunctionField}","page":"Rational function fields","title":"AbstractAlgebra.Generic.defining_polynomial","text":"defining_polynomial(R::FunctionField)\nmodulus(R::FunctionField)\n\nReturn the original polynomial that was used to define the function field R.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Base.numerator(::Generic.FunctionField{T}, ::Bool=true) where T <: FieldElement","category":"page"},{"location":"function_field/#Base.numerator-Union{Tuple{AbstractAlgebra.Generic.FunctionField{T}}, Tuple{T}, Tuple{AbstractAlgebra.Generic.FunctionField{T}, Bool}} where T<:FieldElement","page":"Rational function fields","title":"Base.numerator","text":"Base.numerator(R::FunctionField{T}, canonicalise::Bool=true) where T <: FieldElement\nBase.denominator(R::FunctionField{T}, canonicalise::Bool=true) where T <: FieldElement\n\nThinking of elements of the rational function field as fractions, put the defining polynomial of the function field over a common denominator and return the numerator/denominator respectively. Note that the resulting polynomials belong to a different ring than the original defining polynomial. The canonicalise is ignored, but exists for compatibility with the Generic interface.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Base.numerator(::Generic.FunctionFieldElem{T}, ::Bool=true) where T <: FieldElement","category":"page"},{"location":"function_field/#Base.numerator-Union{Tuple{AbstractAlgebra.Generic.FunctionFieldElem{T}}, Tuple{T}, Tuple{AbstractAlgebra.Generic.FunctionFieldElem{T}, Bool}} where T<:FieldElement","page":"Rational function fields","title":"Base.numerator","text":"Base.numerator(a::FunctionFieldElem{T}, canonicalise::Bool=true) where T <: FieldElement\nBase.denominator(a::FunctionFieldElem{T}, canonicalise::Bool=true) where T <: FieldElement\n\nReturn the numerator and denominator of the function field element a. Note that elements are stored in fraction free form so that the denominator is a common denominator for the coefficients of the element a. If canonicalise is set to true the fraction is first canonicalised.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"degree(::Generic.FunctionField)","category":"page"},{"location":"function_field/#AbstractAlgebra.degree-Tuple{AbstractAlgebra.Generic.FunctionField}","page":"Rational function fields","title":"AbstractAlgebra.degree","text":"degree(S::FunctionField)\n\nReturn the degree of the defining polynomial of the function field, i.e. the degree of the extension that the function field makes of the underlying rational function field.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"gen(::Generic.FunctionField{T}) where T <: FieldElement","category":"page"},{"location":"function_field/#AbstractAlgebra.gen-Union{Tuple{AbstractAlgebra.Generic.FunctionField{T}}, Tuple{T}} where T<:FieldElement","page":"Rational function fields","title":"AbstractAlgebra.gen","text":"gen(S::FunctionField{T}) where T <: FieldElement\n\nReturn the generator of the function field returned by the function field constructor.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"is_gen(a::Generic.FunctionFieldElem)","category":"page"},{"location":"function_field/#AbstractAlgebra.is_gen-Tuple{AbstractAlgebra.Generic.FunctionFieldElem}","page":"Rational function fields","title":"AbstractAlgebra.is_gen","text":"is_gen(a::FunctionFieldElem)\n\nReturn true if a is the generator of the function field returned by the function field constructor.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"coeff(::Generic.FunctionFieldElem, ::Int)\nnum_coeff(::Generic.FunctionFieldElem, ::Int)","category":"page"},{"location":"function_field/#AbstractAlgebra.coeff-Tuple{AbstractAlgebra.Generic.FunctionFieldElem, Int64}","page":"Rational function fields","title":"AbstractAlgebra.coeff","text":"coeff(a::FunctionFieldElem, n::Int)\n\nReturn the degree n coefficient of the element a in its polynomial representation in terms of the generator of the function field. The coefficient is returned as an element of the underlying rational function field.\n\n\n\n\n\n","category":"method"},{"location":"function_field/#AbstractAlgebra.Generic.num_coeff-Tuple{AbstractAlgebra.Generic.FunctionFieldElem, Int64}","page":"Rational function fields","title":"AbstractAlgebra.Generic.num_coeff","text":"num_coeff(a::FunctionFieldElem, n::Int)\n\nReturn the degree n coefficient of the numerator of the element a (in its polynomial representation in terms of the generator of the function field, rationalised as per numerator/denominator described above). The coefficient will be an polynomial over the base_ring of the underlying rational function field.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"Examples","category":"page"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"julia> R, x = rational_function_field(QQ, \"x\")\n(Rational function field over rationals, x)\n\njulia> U, z = R[\"z\"]\n(Univariate polynomial ring in z over rational function field, z)\n\njulia> g = z^2 + 3*(x + 1)//(x + 2)*z + 1\nz^2 + (3*x + 3)//(x + 2)*z + 1\n\njulia> S, y = function_field(g, \"y\")\n(Function Field over Rationals with defining polynomial (x + 2)*y^2 + (3*x + 3)*y + x + 2, y)\n\njulia> base_field(S)\nRational function field\n over rationals\n\njulia> var(S)\n:y\n\njulia> characteristic(S)\n0\n\njulia> defining_polynomial(S)\nz^2 + (3*x + 3)//(x + 2)*z + 1\n\njulia> numerator(S)\n(x + 2)*y^2 + (3*x + 3)*y + x + 2\n\njulia> denominator(S)\nx + 2\n\njulia> a = (x + 1)//(x^2 + 1)*y + 3x + 2\n((x + 1)*y + 3*x^3 + 2*x^2 + 3*x + 2)//(x^2 + 1)\n\njulia> numerator(a, false)\n(x + 1)*y + 3*x^3 + 2*x^2 + 3*x + 2\n\njulia> denominator(a, false)\nx^2 + 1\n\njulia> degree(S)\n2\n\njulia> gen(S)\ny\n\njulia> is_gen(y)\ntrue\n\njulia> coeff(a, 1)\n(x + 1)//(x^2 + 1)\n\njulia> num_coeff(a, 1)\nx + 1","category":"page"},{"location":"function_field/#Trace-and-norm","page":"Rational function fields","title":"Trace and norm","text":"","category":"section"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"norm(::Generic.FunctionFieldElem)","category":"page"},{"location":"function_field/#LinearAlgebra.norm-Tuple{AbstractAlgebra.Generic.FunctionFieldElem}","page":"Rational function fields","title":"LinearAlgebra.norm","text":"norm(a::FunctionFieldElem)\n\nReturn the absolute norm of a as an element of the underlying rational function field.\n\n\n\n\n\n","category":"method"},{"location":"function_field/","page":"Rational function fields","title":"Rational function fields","text":"julia> R, x = rational_function_field(QQ, \"x\")\n(Rational function field over rationals, x)\n\njulia> U, z = R[\"z\"]\n(Univariate polynomial ring in z over rational function field, z)\n\njulia> g = z^2 + 3*(x + 1)//(x + 2)*z + 1\nz^2 + (3*x + 3)//(x + 2)*z + 1\n\njulia> S, y = function_field(g, \"y\")\n(Function Field over Rationals with defining polynomial (x + 2)*y^2 + (3*x + 3)*y + x + 2, y)\n\njulia> f = (-3*x - 5//3)//(x - 2)*y + (x^3 + 1//9*x^2 + 5)//(x - 2)\n((-3*x - 5//3)*y + x^3 + 1//9*x^2 + 5)//(x - 2)\n\njulia> norm(f)\n(x^7 + 20//9*x^6 + 766//81*x^5 + 2027//81*x^4 + 110//3*x^3 + 682//9*x^2 + 1060//9*x + 725//9)//(x^3 - 2*x^2 - 4*x + 8)\n\njulia> tr(f)\n(2*x^4 + 38//9*x^3 + 85//9*x^2 + 24*x + 25)//(x^2 - 4)","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"total_fraction/#Total-ring-of-fractions","page":"Total ring of fractions","title":"Total ring of fractions","text":"","category":"section"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"AbstractAlgebra.jl provides a module, implemented in src/generic/TotalFraction.jl, for the total ring of fractions of a ring.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"The total ring of fractions of a ring R is the localisation of R at the non-zero divisors of R, the latter being a multiplicative subset of R.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"There are no restrictions on the ring except the function is_zero_divisor must be defined and effective for R.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"In particular, we do not assume that all elements of R which are not zero divisors are units in R. This has the effect of making exact division impossible generically in the total ring of fractions of R.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"This in turn limits the usefulness of the total ring of fractions as a ring in AbstractAlgebra as a great deal of generic code relies on divexact. Should this be a limitation, the user can define their own divexact function for the total ring of fractions in question.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Note that in most cases a*inv(b) is not a sufficient definition of divexact(a, b) due to the possibility that b is not a unit in the total ring of fractions.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"It is also possible to construct a total ring of fractions of R without the is_zero_divisor function existing for R, but some functions such as is_unit, inv, rand and ad hoc arithmetic operations involving rational numbers are not available for the total ring of fractions. One must also construct fractions using the option check=false and it is one's own responsibility to check that the denominator is not a zero divisor.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Note that although the total ring of fractions of an integral domain R is mathematically the same thing as the fraction field of R, these will be different objects in AbstractAlgebra and have different types.","category":"page"},{"location":"total_fraction/#Generic-total-ring-of-fraction-types","page":"Total ring of fractions","title":"Generic total ring of fraction types","text":"","category":"section"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"AbstractAlgebra.jl implements a generic type for elements of a total ring of fractions, namelyGeneric.TotFrac{T} where T is the type of elements of the base ring. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Parent objects of such elements have type Generic.TotFracRing{T}.","category":"page"},{"location":"total_fraction/#Abstract-types","page":"Total ring of fractions","title":"Abstract types","text":"","category":"section"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"The types for elements of a total ring of fractions belong directly to the abstract type RingElem and the type for the total ring of fractions parent object belongs directly to the abstract type Ring.","category":"page"},{"location":"total_fraction/#Total-ring-of-fractions-constructors","page":"Total ring of fractions","title":"Total ring of fractions constructors","text":"","category":"section"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"In order to construct fractions in a total ring of fractions in AbstractAlgebra.jl, one must first construct the parent object for the total ring of fractions itself. This is accomplished with the following constructor.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"total_ring_of_fractions(R::Ring; cached::Bool = true)","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Given a base ring R return the parent object of the total ring of fractions of R. By default the parent object S will depend only on R and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Here are some examples of creating a total ring of fractions and making use of the resulting parent objects to coerce various elements into the ring.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Examples","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"julia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S = total_ring_of_fractions(R)\nTotal ring of fractions of Univariate polynomial ring in x over integers\n\njulia> f = S()\n0\n\njulia> g = S(123)\n123\n\njulia> h = S(BigInt(1234))\n1234\n\njulia> k = S(x + 1)\nx + 1","category":"page"},{"location":"total_fraction/#Fraction-constructors","page":"Total ring of fractions","title":"Fraction constructors","text":"","category":"section"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"One can construct fractions using the total ring of fractions parent object, as for any ring or field.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"(R::TotFracRing)() # constructs zero\n(R::TotFracRing)(c::Integer)\n(R::TotFracRing)(c::elem_type(R))\n(R::TotFracRing{T})(a::T) where T <: RingElement","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Although one cannot use the double slash operator // to construct elements of a total ring of fractions, as no parent has been specified, one can use the double slash operator to construct elements of a total ring of fractions so long as one of the arguments to the double slash operator is already in the total ring of fractions in question.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Examples","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S = total_ring_of_fractions(R)\nTotal ring of fractions of Univariate polynomial ring in x over rationals\n\njulia> f = S(x + 1)\nx + 1\n\njulia> f//3\n(x + 1)//3\n\njulia> 3//f\n3//(x + 1)\n\njulia> f//x\n(x + 1)//x","category":"page"},{"location":"total_fraction/#Functions-for-types-and-parents-of-total-rings-of-fractions","page":"Total ring of fractions","title":"Functions for types and parents of total rings of fractions","text":"","category":"section"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Total rings of fractions in AbstractAlgebra.jl implement the Ring interface except for the divexact function which is not generically possible to implement.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"base_ring(R::TotFracRing)\nbase_ring(a::TotFrac)","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Return the base ring of which the total ring of fractions was constructed.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"parent(a::TotFrac)","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Return the total ring of fractions that the given fraction belongs to.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"characteristic(R::TotFracRing)","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Return the characteristic of the base ring of the total ring of fractions. If the characteristic is not known an exception is raised.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Examples","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S = total_ring_of_fractions(R)\nTotal ring of fractions of Univariate polynomial ring in x over rationals\n\njulia> f = S(x + 1)\nx + 1\n\njulia> U = base_ring(S)\nUnivariate polynomial ring in x over rationals\n\njulia> V = base_ring(f)\nUnivariate polynomial ring in x over rationals\n\njulia> T = parent(f)\nTotal ring of fractions of Univariate polynomial ring in x over rationals\n\njulia> m = characteristic(S)\n0","category":"page"},{"location":"total_fraction/#Total-ring-of-fractions-functions","page":"Total ring of fractions","title":"Total ring of fractions functions","text":"","category":"section"},{"location":"total_fraction/#Basic-functions","page":"Total ring of fractions","title":"Basic functions","text":"","category":"section"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Total rings of fractions implement the Ring interface.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"zero(R::TotFracRing)\none(R::TotFracRing)\niszero(a::TotFrac)\nisone(a::TotFrac)","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"inv(a::T) where T <: TotFrac","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"They also implement some of the following functions which would usually be associated with the field and fraction field interfaces.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"is_unit(f::TotFrac)","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"numerator(a::TotFrac)\ndenominator(a::TotFrac)","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Examples","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S = total_ring_of_fractions(R)\nTotal ring of fractions of Univariate polynomial ring in x over rationals\n\njulia> f = S(x + 1)\nx + 1\n\njulia> g = f//(x^3 + 3x + 1)\n(x + 1)//(x^3 + 3*x + 1)\n\njulia> h = zero(S)\n0\n\njulia> k = one(S)\n1\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> r = deepcopy(f)\nx + 1\n\njulia> n = numerator(g)\nx + 1\n\njulia> d = denominator(g)\nx^3 + 3*x + 1","category":"page"},{"location":"total_fraction/#Random-generation","page":"Total ring of fractions","title":"Random generation","text":"","category":"section"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Random fractions can be generated using rand. The parameters passed after the total ring of fractions tell rand how to generate random elements of the base ring.","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"rand(R::TotFracRing, v...)","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"Examples","category":"page"},{"location":"total_fraction/","page":"Total ring of fractions","title":"Total ring of fractions","text":"julia> R, = residue_ring(ZZ, 12);\n\njulia> K = total_ring_of_fractions(R)\nTotal ring of fractions of Residue ring of integers modulo 12\n\njulia> f = rand(K, 0:11)\n7//5\n\njulia> R, x = polynomial_ring(ZZ, \"x\")\n(Univariate polynomial ring in x over integers, x)\n\njulia> S = total_ring_of_fractions(R)\nTotal ring of fractions of Univariate polynomial ring in x over integers\n\njulia> g = rand(S, -1:3, -10:10)\n(4*x + 4)//(-4*x^2 - x + 4)","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"rand/#Random-interface","page":"Random interface","title":"Random interface","text":"","category":"section"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"AbstractAlgebra makes use of the Julia Random interface for random generation.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"In addition we make use of an experimental package RandomExtensions.jl for extending the random interface in Julia.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"The latter is required because some of our types require more than one argument to specify how to randomise them.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"The usual way of generating random values that Julia and these extensions provide would look as follows:","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"julia> using AbstractAlgebra\n\njulia> using Random\n\njulia> using RandomExtensions\n\njulia> S, x = polynomial_ring(ZZ, \"x\")\n(Univariate Polynomial Ring in x over Integers, x)\n\njulia> rand(Random.GLOBAL_RNG, make(S, 1:3, -10:10))\n-5*x + 4","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"This example generates a polynomial over the integers with degree in the range 1 to 3 and with coefficients in the range -10 to 10.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"In addition we implement shortened versions for ease of use which don't require creating a make instance or passing in the standard RNG.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"julia> using AbstractAlgebra\n\njulia> S, x = polynomial_ring(ZZ, \"x\")\n(Univariate Polynomial Ring in x over Integers, x)\n\njulia> rand(S, 1:3, -10:10)\n-5*x + 4","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"Because rings can be constructed over other rings in a tower, all of this is supported by defining RandomExtensions.make instances that break the various levels of the ring down into separate make instances.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"For example, here is the implementation of make for polynomial rings such as the above:","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"function RandomExtensions.make(S::PolyRing, deg_range::AbstractUnitRange{Int}, vs...)\n R = base_ring(S)\n if length(vs) == 1 && elem_type(R) == Random.gentype(vs[1])\n Make(S, deg_range, vs[1]) # forward to default Make constructor\n else\n Make(S, deg_range, make(R, vs...))\n end\nend","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"As you can see, it has two cases. The first is where this invocation of make is already at the bottom of the tower of rings, in which case it just forwards to the default Make constructor.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"The second case expects that we are higher up in the tower of rings and that make needs to be broken up (recursively) into the part that deals with the ring level we are at and the level that deals with the base ring.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"To help make we tell it the type of object we are hoping to randomly generate.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"RandomExtensions.maketype(S::PolyRing, dr::AbstractUnitRange{Int}, _) = elem_type(S)","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"Finally we implement the actual random generation itself.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"# define rand for make(S, deg_range, v)\nfunction rand(rng::AbstractRNG, sp::SamplerTrivial{<:Make3{<:RingElement, <:PolyRing, <:AbstractUnitRange{Int}}})\n S, deg_range, v = sp[][1:end]\n R = base_ring(S)\n f = S()\n x = gen(S)\n # degree -1 is zero polynomial\n deg = rand(rng, deg_range)\n if deg == -1\n return f\n end\n for i = 0:deg - 1\n f += rand(rng, v)*x^i\n end\n # ensure leading coefficient is nonzero\n c = R()\n while iszero(c)\n c = rand(rng, v)\n end\n f += c*x^deg\n return f\nend","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"Note that when generating random elements of the base ring for example, one should use the random number generator rng that is passed in.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"As mentioned above, we define a simplified random generator that saves the user having to create make instances.","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"rand(rng::AbstractRNG, S::PolyRing, deg_range::AbstractUnitRange{Int}, v...) =\n rand(rng, make(S, deg_range, v...))\n\nrand(S::PolyRing, degs, v...) = rand(Random.GLOBAL_RNG, S, degs, v...)","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"To test whether a random generator is working properly, the test_rand function exists in the AbstractAlgebra test submodule in the file test/runtests.jl. For example, in AbstractAlgebra test code:","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"using Test\n\nR, x = polynomial_ring(ZZ, \"x\")\n\ntest_rand(R, -1:10, -10:10)","category":"page"},{"location":"rand/","page":"Random interface","title":"Random interface","text":"In general, we try to use UnitRange's to specify how 'big' we want the random instance to be, e.g. the range of degrees a polynomial could take, the range random integers could lie in, etc. The objective is to make it easy for the user to control the 'size' of random values in test code.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"map_interface/#Map-Interface","page":"Map Interface","title":"Map Interface","text":"","category":"section"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Maps in AbstractAlgebra can be constructed from Julia functions, or they can be represented by some other kind of data, e.g. a matrix, or built up from other maps.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"In the following, we will always use the word \"function\" to mean a Julia function, and reserve the word \"map\" for a map on sets, whether mathematically, or as an object in the system.","category":"page"},{"location":"map_interface/#Parent-objects","page":"Map Interface","title":"Parent objects","text":"","category":"section"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Maps in AbstractAlgebra currently don't have parents. This will change later when AbstractAlgebra has a category system, so that the parent of a map can be some sort of Hom set.","category":"page"},{"location":"map_interface/#Map-classes","page":"Map Interface","title":"Map classes","text":"","category":"section"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"All maps in AbstractAlgebra belong to a class of maps. The classes are modeled as abstract types that lie in a hierarchy, inheriting from SetMap at the top of the hierarchy. Other classes that inherit from SetMap are FunctionalMap for maps that are constructed from a Julia function (or closure), and IdentityMap for the class of the identity maps within the system.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"One might naturally assume that map types belong directly to these classes in the way that types of other objects in the system belong to abstract types in the AbstractAlgebra type hierarchy. However, in order to provide an extensible system, this is not the case.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Instead, a map type MyMap will belong to an abstract type of the form Map{D, C, T, MyMap}, where D is the type of the object representing the domain of the map type (this can also be an abstract type, such as Group), C is the type of the object representing the codomain of the map type and T is the map class that MyMap belongs to, e.g. SetMap or FunctionalMap.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Because a four parameter type system becomes quite cumbersome to use, we provide a number of functions for referring to collections of map types.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"If writing a function that accepts any map type, one makes the type of its argument belong to Map. For example f(M::Map) = 1.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"If writing a function that accepts any map from a domain of type D to a codomain of type C, one makes writes for example f(M::Map{D, C}) = 2. Note that D and C can be abstract types, such as Group, but otherwise must be the types of the parent objects representing the domain and codomain.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"A function that accepts any map belonging to a given map class might be written as f(M::Map(FunctionalMap)) = 3 or f(M::Map(FunctionalMap){D, C}) = 4 for example, where D and C are the types of the parent objects for the domain and codomain.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Finally, if a function should only work for a map of a given map type MyMap, say, one writes this f(M::Map(MyMap)) or f(M::Map(MyMap){D, C}, where as usual D and C are the types of the domain and codomain parent objects.","category":"page"},{"location":"map_interface/#Implementing-new-map-types","page":"Map Interface","title":"Implementing new map types","text":"","category":"section"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"There are two common kinds of map type that developers will need to write. The first has a fixed domain and codomain, and the second is a type parameterised by the types of the domain and codomain. We give two simple examples here of how this might look.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"In the case of fixed domain and codomain, e.g. Integers{BigInt}, we would write it as follows:","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"mutable struct MyMap <: Map{Integers{BigInt}, Integers{BigInt}, SetMap, MyMap}\n # some data fields\nend","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"In the case of parameterisation by the type of the domain and codomain:","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"mutable struct MyMap{D, C} <: Map{D, C, SetMap, MyMap}\n # some data fields\nend","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"As mentioned above, to write a function that only accepts maps of type MyMap, one writes the functions as follows:","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"function my_fun(M::Map(MyMap))","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"The Map function then computes the correct type to use, which is actually not MyMap if all features of the generic Map infrastructure are required. It is bad practice to write functions for MyMap directly instead of Map(MyMap), since other users will be unable to use generic constructions over the map type MyMap.","category":"page"},{"location":"map_interface/#Required-functionality-for-maps","page":"Map Interface","title":"Required functionality for maps","text":"","category":"section"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"All map types must implement a standard interface, which we specify here.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"We will define this interface for a custom map type MyMap belonging to Map(SetMap), SetMap being the map class that all maps types belong to.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Note that map types do not need to contain any specific fields, but must provide accessor functions (getters and setters) in the manner described above.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"The required accessors for map types of class SetMap are as follows.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"domain(M::Map(MyMap))\ncodomain(M::Map(MyMap))","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Return the domain and codomain parent objects respectively, for the map M. It is only necessary to define these functions if the map type MyMap does not contain fields domain and codomain containing these parent objects.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"It is also necessary to be able to apply a map. This amounts to overloading the call method for objects belonging to Map(MyMap).","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"(M::Map(MyMap)(a))","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Apply the map M to the element a of the domain of M. Note that it is usual to add a type assertion to the return value of this function, asserting that the return value has type elem_type(C) where C is the type of the codomain parent object.","category":"page"},{"location":"map_interface/#Optional-functionality-for-maps","page":"Map Interface","title":"Optional functionality for maps","text":"","category":"section"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"The Generic module in AbstractAlgebra automatically provides certain functionality for map types, assuming that they satisfy the full interface described above.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"However, certain map types or map classes might like to provide their own implementation of this functionality, overriding the generic functionality.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"We describe this optional functionality here.","category":"page"},{"location":"map_interface/#Show-method","page":"Map Interface","title":"Show method","text":"","category":"section"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Custom map types may like to provide a custom show method if the default of displaying the domain and codomain of the map is not sufficient.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"show(io::IO, M::Map(MyMap))","category":"page"},{"location":"map_interface/#Identity-maps","page":"Map Interface","title":"Identity maps","text":"","category":"section"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"There is a concrete map type Generic.IdentityMap{D} for the identity map on a given domain. Here D is the type of the object representing that domain.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Generic.IdentityMap belongs to the supertype Map{D, C, AbstractAlgebra.IdentityMap, IdentityMap}.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Note that the map class is also called IdentityMap. It is an abstract type, whereas Generic.IdentityMap is a concrete type in the Generic module.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"An identity map has the property that when composed with any map whose domain or codomain is compatible, that map will be returned as the composition. Identity maps can therefore serve as a starting point when building up a composition of maps, starting an identity map.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"We do not cached identity maps in the system, so that if more than one is created on the same domain, there will be more than one such map in the system. This underscores the fact that there is in general no way for the system to know if two maps compose to give an identity map, and therefore the only two maps that can be composed to give an identity map are identity maps on the same domain.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"To construct an identity map for a given domain, specified by a parent object R, say, we have the following function.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"identity_map(R::Set)","category":"page"},{"location":"map_interface/#AbstractAlgebra.identity_map-Tuple{AbstractAlgebra.Set}","page":"Map Interface","title":"AbstractAlgebra.identity_map","text":"identity_map(R::D) where D <: AbstractAlgebra.Set\n\nReturn an identity map on the domain R.\n\nExamples\n\njulia> R, t = ZZ[:t]\n(Univariate polynomial ring in t over integers, t)\n\njulia> f = identity_map(R)\nIdentity map\n of univariate polynomial ring in t over integers\n\njulia> f(t)\nt\n\n\n\n\n\n","category":"method"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Return an identity map on the domain R.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Of course there is nothing stopping a map type or class from implementing its own identity map type, and defining composition of maps of the same kind with such an identity map. In such a case, the class of such an identity map type must belong to IdentityMap so that composition with other map types still works.","category":"page"},{"location":"map_interface/#Composition-of-maps","page":"Map Interface","title":"Composition of maps","text":"","category":"section"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Any two compatible maps in AbstractAlgebra can be composed and any composition can be applied.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"In order to facilitate this, the Generic module provides a type Generic.CompositeMap{D, C}, which contains two maps map1 and map2, corresponding to the two maps to be applied in a composition, in the order they should be applied.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"To construct a composition map from two existing maps, we have the following function:","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"compose(f::Map, g::Map)","category":"page"},{"location":"map_interface/#AbstractAlgebra.compose-Tuple{Map, Map}","page":"Map Interface","title":"AbstractAlgebra.compose","text":"compose(f::Map, g::Map)\n\nCompose the two maps f and g, i.e. return the map h such that h(x) = g(f(x)).\n\nExamples\n\njulia> f = map_from_func(x -> x + 1, ZZ, ZZ);\n\njulia> g = map_from_func(x -> QQ(x), ZZ, QQ);\n\njulia> h = compose(f, g)\nFunctional composite map\n from integers\n to rationals\nwhich is the composite of\n Map: integers -> integers\n Map: integers -> rationals\n\n\n\n\n\n","category":"method"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"As a shortcut for this function we have the following operator:","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"*(f::Map{D, U}, g::Map{U, C}) where {D, U, C} = compose(f, g)","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Note the order of composition. If we have maps f X to Y, g Y to Z the correct order of the maps in this operator is f*g, so that (f*g)(x) = g(f(x)).","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"This is chosen so that for left R-module morphisms represented by a matrix, the order of matrix multiplication will match the order of composition of the corresponding morphisms.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Of course, a custom map type or class of maps can implement its own composition type and compose function.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"This is the case with the FunctionalMap class for example, which caches the Julia function/closure corresponding to the composition of two functional maps. As this cached function needs to be stored inside the composition, a special type is necessary for the composition of two functional maps.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"By default, compose will check that the two maps are composable, i.e. the codomain of the first map matches the domain of the second map. This is implemented by the following function:","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"check_composable(f::Map{D, U}, g::Map{U, C})","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Raise an exception if the codomain of f doesn't match the domain of g.","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Note that composite maps should keep track of the two maps they were constructed from. To access these maps, the following functions are provided:","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"map1(f::CompositeMap)\nmap2(f::CompositeMap)","category":"page"},{"location":"map_interface/","page":"Map Interface","title":"Map Interface","text":"Any custom composite map type must also provide these functions for that map type, even if there exist fields with those names. This is because there is no common map class for all composite map types. Therefore the Generic system cannot provide fallbacks for all such composite map types.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"real/#Real-field","page":"Real field","title":"Real field","text":"","category":"section"},{"location":"real/","page":"Real field","title":"Real field","text":"AbstractAlgebra.jl provides a module, implemented in src/julia/Float.jl for making Julia BigFloats conform to the AbstractAlgebra.jl Field interface.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"In addition to providing a parent object RealField for Julia BigFloats, we implement any additional functionality required by AbstractAlgebra.jl.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"Because BigFloat cannot be directly included in the AbstractAlgebra.jl abstract type hierarchy, we achieve integration of Julia BigFloats by introducing a type union, called FieldElement, which is a union of FieldElem and a number of Julia types, including BigFloat. Everywhere that FieldElem is notionally used in AbstractAlgebra.jl, we are in fact using FieldElement, with additional care being taken to avoid ambiguities.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"The details of how this is done are technical, and we refer the reader to the implementation for details. For most intents and purposes, one can think of the Julia BigFloat type as belonging to FieldElem.","category":"page"},{"location":"real/#Types-and-parent-objects","page":"Real field","title":"Types and parent objects","text":"","category":"section"},{"location":"real/","page":"Real field","title":"Real field","text":"Reals have type BigFloat, as in Julia itself. We simply supplement the functionality for this type as required for computer algebra.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"The parent objects of such integers has type Floats{BigFloat}.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"For convenience, we also make Float64 a part of the AbstractAlgebra.jl type hierarchy and its parent object (accessible as RDF) has type Floats{Float64}.","category":"page"},{"location":"real/#Rational-constructors","page":"Real field","title":"Rational constructors","text":"","category":"section"},{"location":"real/","page":"Real field","title":"Real field","text":"In order to construct reals in AbstractAlgebra.jl, one can first construct the real field itself. This is accomplished using the following constructor.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"Floats{BigFloat}()","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"This gives the unique object of type Floats{BigFloat} representing the field of reals in AbstractAlgebra.jl.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"In practice, one simply uses RealField which is assigned to be the return value of the above constructor. There is no need to call the constructor in practice.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"Here are some examples of creating the real field and making use of the resulting parent object to coerce various elements into the field.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"Examples","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"julia> RR = RealField\nFloats\n\njulia> f = RR()\n0.0\n\njulia> g = RR(123)\n123.0\n\njulia> h = RR(BigInt(1234))\n1234.0\n\njulia> k = RR(12//7)\n1.714285714285714285714285714285714285714285714285714285714285714285714285714291\n\njulia> m = RR(2.3)\n2.29999999999999982236431605997495353221893310546875\n","category":"page"},{"location":"real/#Basic-field-functionality","page":"Real field","title":"Basic field functionality","text":"","category":"section"},{"location":"real/","page":"Real field","title":"Real field","text":"The real field in AbstractAlgebra.jl implements the full Field interface.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"We give some examples of such functionality.","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"Examples","category":"page"},{"location":"real/","page":"Real field","title":"Real field","text":"julia> RR = RealField\nFloats\n\njulia> f = RR(12//7)\n1.714285714285714285714285714285714285714285714285714285714285714285714285714291\n\njulia> h = zero(RR)\n0.0\n\njulia> k = one(RR)\n1.0\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> U = base_ring(RR)\nUnion{}\n\njulia> T = parent(f)\nFloats\n\njulia> f == deepcopy(f)\ntrue\n\njulia> g = f + 12\n13.71428571428571428571428571428571428571428571428571428571428571428571428571433\n\njulia> m = inv(g)\n0.07291666666666666666666666666666666666666666666666666666666666666666666666666631\n","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"series_interface/#Series-Ring-Interface","page":"Series Ring Interface","title":"Series Ring Interface","text":"","category":"section"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Univariate power series rings are supported in AbstractAlgebra in a variety of different forms, including absolute and relative precision models and Laurent series.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"In addition to the standard Ring interface, numerous additional functions are required to be present for power series rings.","category":"page"},{"location":"series_interface/#Types-and-parents","page":"Series Ring Interface","title":"Types and parents","text":"","category":"section"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"AbstractAlgebra provides two abstract types for power series rings and their elements:","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"SeriesRing{T} is the abstract type for all power series ring parent types\nSeriesElem{T} is the abstract type for all power series types","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"We have that SeriesRing{T} <: Ring and SeriesElem{T} <: RingElem.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Note that both abstract types are parameterised. The type T should usually be the type of elements of the coefficient ring of the power series ring. For example, in the case of mathbbZx the type T would be the type of an integer, e.g. BigInt.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Within the SeriesElem{T} abstract type is the abstract type RelPowerSeriesRingElem{T} for relative power series, and AbsPowerSeriesRingElem{T} for absolute power series.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Relative series are typically stored with a valuation and a series that is either zero or that has nonzero constant term. Absolute series are stored starting from the constant term, even if it is zero.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"If the parent object for a relative series ring over the bignum integers has type MySeriesRing and series in that ring have type MySeries then one would have:","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"MySeriesRing <: SeriesRing{BigInt}\nMySeries <: RelPowerSeriesRingElem{BigInt}","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Series rings should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Series rings should at least be distinguished based on their base (coefficient) ring. But if they have the same base ring and symbol (for their variable/generator) and same default precision, they should certainly have the same parent object.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).","category":"page"},{"location":"series_interface/#Required-functionality-for-series","page":"Series Ring Interface","title":"Required functionality for series","text":"","category":"section"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"In addition to the required functionality for the Ring interface the Series Ring interface has the following required functions.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"We suppose that R is a fictitious base ring (coefficient ring) and that S is a series ring over R (e.g. S = Rx) with parent object S of type MySeriesRing{T}. We also assume the series in the ring have type MySeries{T}, where T is the type of elements of the base (coefficient) ring.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Note that the type T must (transitively) belong to the abstract type RingElem.","category":"page"},{"location":"series_interface/#Constructors","page":"Series Ring Interface","title":"Constructors","text":"","category":"section"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"In addition to the standard constructors, the following constructors, taking an array of coefficients, must be available.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"For relative power series and Laurent series we have:","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"(S::MySeriesRing{T})(A::Vector{T}, len::Int, prec::Int, val::Int) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Create the series in the given ring whose valuation is val, whose absolute precision is given by prec and the coefficients of which are given by A, starting from the first nonzero term. Only len terms of the array are used, the remaining terms being ignored. The value len cannot exceed the length of the supplied array.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"It is permitted to have trailing zeros in the array, but it is not needed, even if the precision minus the valuation is bigger than the length of the array.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"(S::MySeriesRing{T})(A::Vector{U}, len::Int, prec::Int, val::Int) where {T <: RingElem, U <: RingElem}","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"As above, but where the array is an array of coefficient that can be coerced into the base ring of the series ring.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"(S::MySeriesRing{T})(A::Vector{U}, len::Int, prec::Int, val::Int) where {T <: RingElem, U <: Integer}","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"As above, but where the array is an array of integers that can be coerced into the base ring of the series ring.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"It may be desirable to implement an addition version which accepts an array of Julia Int values if this can be done more efficiently.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"For absolute power series we have:","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"(S::MySeriesRing{T})(A::Vector{T}, len::Int, prec::Int) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Create the series in the given ring whose absolute precision is given by prec and the coefficients of which are given by A, starting from the constant term. Only len terms of the array are used, the remaining terms being ignored.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Note that len is usually maintained separately of any polynomial that is underlying the power series. This allows for easy trucation of a power series without actually modifying the polynomial underlying it.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"It is permitted to have trailing zeros in the array, but it is not needed, even if the precision is bigger than the length of the array.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"It is also possible to create series directly without having to create the corresponding series ring.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"abs_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T\nrel_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, val::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Create the power series over the given base ring R with coefficients specified by arr with the given absolute precision prec and in the case of relative series with the given valuation val.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Note that more coefficients may be specified than are actually used. Only the first len coefficients are made part of the series, the remainder being stored internally but ignored.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"In the case of absolute series one must have prec >= len and in the case of relative series one must have prec >= len + val.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"By default the series are created in a ring with variable x and max_precision equal to prec, however one may specify these directly to override the defaults. Note that series are only compatible if they have the same coefficient ring R, max_precision and variable name var.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Also by default any parent ring created is cached. If this behaviour is not desired, set cached=false. However, this means that subsequent series created in the same way will not be compatible. Instead, one should use the parent object of the first series to create subsequent series instead of calling this function repeatedly with cached=false.","category":"page"},{"location":"series_interface/#Data-type-and-parent-object-methods","page":"Series Ring Interface","title":"Data type and parent object methods","text":"","category":"section"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"var(S::MySeriesRing{T}) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Return a Symbol representing the variable (generator) of the series ring. Note that this is a Symbol not a String, though its string value will usually be used when printing series.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Custom series types over a given ring should define one of the following functions which return the type of an absolute or relative series object over that ring.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"abs_series_type(::Type{T}) where T <: RingElement\nrel_series_type(::Type{T}) where T <: RingElement","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Return the type of a series whose coefficients have the given type.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"This function is defined for generic series and only needs to be defined for custom series rings, e.g. ones defined by a C implementation.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"max_precision(S::MySeriesRing{T}) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Return the (default) maximum precision of the power series ring. This is the precision that the output of an operation will be if it cannot be represented to full precision (e.g. because it mathematically has infinite precision).","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"This value is usually supplied upon creation of the series ring and stored in the ring. It is independent of the precision which each series in the ring actually has. Those are stored on a per element basis in the actual series elements.","category":"page"},{"location":"series_interface/#Basic-manipulation-of-rings-and-elements","page":"Series Ring Interface","title":"Basic manipulation of rings and elements","text":"","category":"section"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"pol_length(f::MySeries{T}) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Return the length of the polynomial underlying the given power series. This is not generally useful to the user, but is used internally.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"set_length!(f::MySeries{T}, n::Int) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"This function sets the effective length of the polynomial underlying the given series. The function doesn't modify the actual polynomial, but simply changes the number of terms of the polynomial which are considered to belong to the power series. The remaining terms are ignored.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"This function cannot set the length to a value greater than the length of any underlying polynomial.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"The function mutates the series in-place but does not return the mutated series.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"precision(f::MySeries{T})","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Return the absolute precision of f.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"set_precision!(f::MySeries{T}, prec::Int)","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Set the absolute precision of the given series to the given value.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"This return the updated series.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"valuation(f::MySeries{T})","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Return the valuation of the given series.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"set_valuation!(f::MySeries{T}, val::Int)","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"For relative series and Laurent series only, this function alters the valuation of the given series to the given value.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"This function returns the updated series.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"polcoeff(f::MySeries{T}, n::Int)","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Return the coefficient of degree n of the polynomial underlying the series. If n is larger than the degree of this polynomial, zero is returned. This function is not generally of use to the user but is used internally.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"setcoeff!(f::MySeries{T}, n::Int, a::T) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Set the degree n coefficient of the polynomial underlying f to a. This mutates the polynomial in-place if possible and returns the mutated series (so that immutable types can also be supported). The function must not assume that the polynomial already has space for n + 1 coefficients. The polynomial must be resized if this is not the case.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"note: Note\nThis function is not required to normalise the polynomial and is not necessarily useful to the user, but is used extensively by the generic functionality in AbstractAlgebra.jl. It is for setting raw coefficients in the representation.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"normalise(f::MySeries{T}, n::Int)","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Given a series f represented by a polynomial of at least the given length, return the normalised length of the underlying polynomial assuming it has length at most n. This function does not actually normalise the polynomial and is not particularly useful to the user. It is used internally.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"renormalize!(f::MySeries{T}) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Given a relative series or Laurent series whose underlying polynomial has zero constant term, say as the result of some internal computation, renormalise the series so that the polynomial has nonzero constant term. The precision and valuation of the series are adjusted to compensate. This function is not intended to be useful to the user, but is used internally.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"fit!(f::MySeries{T}, n::Int) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Ensure that the polynomial underlying f internally has space for n coefficients. This function must mutate the series in-place if it is mutable. It does not return the mutated series. Immutable types can still be supported by defining this function to do nothing.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Some interfaces for C polynomial types automatically manage the internal allocation of polynomials in every function that can be called on them. Explicit adjustment by the generic code in AbstractAlgebra.jl is not required. In such cases, this function can also be defined to do nothing.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"gen(R::MySeriesRing{T}) where T <: RingElem","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Return the generator x of the series ring.","category":"page"},{"location":"series_interface/#Optional-functionality-for-series","page":"Series Ring Interface","title":"Optional functionality for series","text":"","category":"section"},{"location":"series_interface/#Similar-and-zero","page":"Series Ring Interface","title":"Similar and zero","text":"","category":"section"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"The following functions are available for all absolute and relative series types. The functions similar and zero do the same thing, but are provided for uniformity with other parts of the interface.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"similar(x::MySeries, R::Ring, max_prec::Int, var::VarName=var(parent(x)); cached::Bool=true)\nzero(a::MySeries, R::Ring, max_prec::Int, var::VarName=var(parent(a)); cached::Bool=true)","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Construct the zero series with the given variable (if specified), coefficients in the specified coefficient ring and with relative/absolute precision cap on its parent ring as given by max_prec.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"similar(x::MySeries, R::Ring, var::VarName=var(parent(x)); cached::Bool=true)\nsimilar(x::MySeries, max_prec::Int, var::VarName=var(parent(x)); cached::Bool=true)\nsimilar(x::MySeries, var::VarName=var(parent(x)); cached::Bool=true)\nsimilar(x::MySeries, R::Ring, max_prec::Int, var::VarName; cached::Bool=true)\nsimilar(x::MySeries, R::Ring, var::VarName; cached::Bool=true)\nsimilar(x::MySeries, max_prec::Int, var::VarName; cached::Bool=true)\nsimilar(x::MySeries, var::VarName; cached::Bool=true)\nzero(x::MySeries, R::Ring, var::VarName=var(parent(x)); cached::Bool=true)\nzero(x::MySeries, max_prec::Int, var::VarName=var(parent(x)); cached::Bool=true)\nzero(x::MySeries, var::VarName=var(parent(x)); cached::Bool=true)\nzero(x::MySeries, R::Ring, max_prec::Int, var::VarName; cached::Bool=true)\nzero(x::MySeries, R::Ring, var::VarName; cached::Bool=true)\nzero(x::MySeries, max_prec::Int, var::VarName; cached::Bool=true)\nzero(x::MySeries, var::VarName; cached::Bool=true)","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"As above, but use the precision cap of the parent ring of x and the base_ring of x if these are not specified.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"Custom series rings may choose which series type is best-suited to return for the given coefficient ring, precision cap and variable, however they should return a series with the same model as x, i.e. relative or series.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"If custom implementations don't specialise these function the default return type is a Generic.AbsSeries or Generic.RelSeries.","category":"page"},{"location":"series_interface/","page":"Series Ring Interface","title":"Series Ring Interface","text":"The default implementation of zero calls out to similar, so it's generally sufficient to specialise only similar. For both similar and zero only the most general method has to be implemented as all other methods call out to this more general method.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"residue/#Generic-residue-rings","page":"Generic residue rings","title":"Generic residue rings","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"AbstractAlgebra.jl provides modules, implemented in src/Residue.jl and src/residue_field for residue rings and fields, respectively, over any Euclidean domain (in practice most of the functionality is provided for GCD domains that provide a meaningful GCD function) belonging to the AbstractAlgebra.jl abstract type hierarchy.","category":"page"},{"location":"residue/#Generic-residue-types","page":"Generic residue rings","title":"Generic residue types","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"AbstractAlgebra.jl implements generic residue rings of Euclidean rings with type EuclideanRingResidueRingElem{T} or in the case of residue rings that are known to be fields, EuclideanRingResidueFieldElem{T}, where T is the type of elements of the base ring. See the file src/generic/GenericTypes.jl for details.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Parent objects of generic residue ring elements have type EuclideanRingResidueRing{T} and those of residue fields have type EuclideanRingResidueField{T}.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"The defining modulus of the residue ring is stored in the parent object.","category":"page"},{"location":"residue/#Abstract-types","page":"Generic residue rings","title":"Abstract types","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"All residue element types belong to the abstract type ResElem{T} or ResFieldElem{T} in the case of residue fields, and the residue ring types belong to the abstract type ResidueRing{T} or ResidueField{T} respectively. This enables one to write generic functions that can accept any AbstractAlgebra residue type.","category":"page"},{"location":"residue/#Residue-ring-constructors","page":"Generic residue rings","title":"Residue ring constructors","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"In order to construct residues in AbstractAlgebra.jl, one must first construct the residue ring itself. This is accomplished with one of the following constructors.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"residue_ring(R::Ring, m::RingElem; cached::Bool = true)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"residue_field(R::Ring, m::RingElem; cached::Bool = true)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Given a base ring R and residue m contained in this ring, return the parent object of the residue ring R(m) together with the canonical projection. By default the parent object S will depend only on R and m and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"The residue_field constructor does the same thing as the residue_ring constructor, but the resulting object has type belonging to Field rather than Ring, so it can be used anywhere a field is expected in AbstractAlgebra.jl. No check is made for maximality of the ideal generated by m.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"There are also the following for constructing residue rings and fields.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"quo(R::Ring, m::RingElem; cached::Bool = true)\nquo(::Type{Field}, R::Ring, m::RingElem; cached::Bool = true)","category":"page"},{"location":"residue/#AbstractAlgebra.quo-Tuple{Ring, RingElem}","page":"Generic residue rings","title":"AbstractAlgebra.quo","text":"quo(R::Ring, a::RingElement; cached::Bool = true)\n\nReturns S, f where S = residue_ring(R, a) and f is the projection map from R to S. This map is supplied as a map with section where the section is the lift of an element of the residue field back to the ring R.\n\n\n\n\n\n","category":"method"},{"location":"residue/#AbstractAlgebra.quo-Tuple{Type{Field}, Ring, RingElem}","page":"Generic residue rings","title":"AbstractAlgebra.quo","text":"quo(::Type{Field}, R::Ring, a::RingElement; cached::Bool = true)\n\nReturns S, f where S = residue_field(R, a) and f is the projection map from R to S. This map is supplied as a map with section where the section is the lift of an element of the residue field back to the ring R.\n\n\n\n\n\n","category":"method"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Here are some examples of creating residue rings and making use of the resulting parent objects to coerce various elements into the residue ring.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Examples","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S, = residue_ring(R, x^3 + 3x + 1);\n\njulia> f = S()\n0\n\njulia> g = S(123)\n123\n\njulia> h = S(BigInt(1234))\n1234\n\njulia> k = S(x + 1)\nx + 1\n\njulia> U, f = quo(R, x^3 + 3x + 1)\n(Residue ring of univariate polynomial ring modulo x^3 + 3*x + 1, Map: univariate polynomial ring -> residue ring)\n\njulia> U === S\ntrue","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"All of the examples here are generic residue rings, but specialised implementations of residue rings provided by external modules will also usually provide a residue_ring constructor to allow creation of their residue rings.","category":"page"},{"location":"residue/#Residue-constructors","page":"Generic residue rings","title":"Residue constructors","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"One can use the parent objects of a residue ring to construct residues, as per any ring.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"(R::ResidueRing)() # constructs zero\n(R::ResidueRing)(c::Integer)\n(R::ResidueRing)(c::elem_type(R))\n(R::ResidueRing{T})(a::T) where T <: RingElement","category":"page"},{"location":"residue/#Functions-for-types-and-parents-of-residue-rings","page":"Generic residue rings","title":"Functions for types and parents of residue rings","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"base_ring(R::ResidueRing)\nbase_ring(a::ResElem)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Return the base ring over which the ring was constructed.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"parent(a::ResElem)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Return the parent of the given residue.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"characteristic(R::ResidueRing)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Return the characteristic of the given residue ring. If the characteristic is not known, an exception is raised.","category":"page"},{"location":"residue/#Residue-ring-functions","page":"Generic residue rings","title":"Residue ring functions","text":"","category":"section"},{"location":"residue/#Basic-functionality","page":"Generic residue rings","title":"Basic functionality","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Residue rings implement the Ring interface.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"zero(R::NCRing)\none(R::NCRing)\niszero(a::NCRingElement)\nisone(a::NCRingElement)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"divexact(a::T, b::T) where T <: RingElement\ninv(a::T)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"The Residue Ring interface is also implemented.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"modulus(S::ResidueRing)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"data(f::ResElem)\nlift(f::ResElem)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Return a lift of the residue to the base ring.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"The following functions are also provided for residues.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"modulus(::ResElem)","category":"page"},{"location":"residue/#AbstractAlgebra.modulus-Tuple{ResElem}","page":"Generic residue rings","title":"AbstractAlgebra.modulus","text":"modulus(R::ResElem)\n\nReturn the modulus a of the residue ring S = R(a) that the supplied residue r belongs to.\n\n\n\n\n\n","category":"method"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Examples","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S, = residue_ring(R, x^3 + 3x + 1);\n\njulia> f = S(x + 1)\nx + 1\n\njulia> h = zero(S)\n0\n\njulia> k = one(S)\n1\n\njulia> isone(k)\ntrue\n\njulia> iszero(f)\nfalse\n\njulia> is_unit(f)\ntrue\n\njulia> m = modulus(S)\nx^3 + 3*x + 1\n\njulia> d = data(f)\nx + 1\n\njulia> U = base_ring(S)\nUnivariate polynomial ring in x over rationals\n\njulia> V = base_ring(f)\nUnivariate polynomial ring in x over rationals\n\njulia> T = parent(f)\nResidue ring of univariate polynomial ring modulo x^3 + 3*x + 1\n\njulia> f == deepcopy(f)\ntrue\n\njulia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)","category":"page"},{"location":"residue/#Inversion","page":"Generic residue rings","title":"Inversion","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Base.inv(::ResElem)","category":"page"},{"location":"residue/#Base.inv-Tuple{ResElem}","page":"Generic residue rings","title":"Base.inv","text":"Base.inv(a::ResElem)\n\nReturn the inverse of the element a in the residue ring. If an impossible inverse is encountered, an exception is raised.\n\n\n\n\n\n","category":"method"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Examples","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S, = residue_ring(R, x^3 + 3x + 1);\n\njulia> f = S(x + 1)\nx + 1\n\njulia> g = inv(f)\n1//3*x^2 - 1//3*x + 4//3\n","category":"page"},{"location":"residue/#Greatest-common-divisor","page":"Generic residue rings","title":"Greatest common divisor","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"gcd{T <: RingElem}(::ResElem{T}, ::ResElem{T})","category":"page"},{"location":"residue/#Base.gcd-Union{Tuple{T}, Tuple{ResElem{T}, ResElem{T}}} where T<:RingElem","page":"Generic residue rings","title":"Base.gcd","text":"gcd(a::ResElem{T}, b::ResElem{T}) where {T <: RingElement}\n\nReturn a greatest common divisor of a and b if one exists. This is done by taking the greatest common divisor of the data associated with the supplied residues and taking its greatest common divisor with the modulus.\n\n\n\n\n\n","category":"method"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Examples","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"julia> R, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> S, = residue_ring(R, x^3 + 3x + 1);\n\njulia> f = S(x + 1)\nx + 1\n\njulia> g = S(x^2 + 2x + 1)\nx^2 + 2*x + 1\n\njulia> h = gcd(f, g)\n1\n","category":"page"},{"location":"residue/#Square-Root","page":"Generic residue rings","title":"Square Root","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"is_square{T <: Integer}(::ResFieldElem{T})","category":"page"},{"location":"residue/#AbstractAlgebra.is_square-Union{Tuple{AbstractAlgebra.ResFieldElem{T}}, Tuple{T}} where T<:Integer","page":"Generic residue rings","title":"AbstractAlgebra.is_square","text":"is_square(a::ResFieldElem{T}) where T <: Integer\n\nReturn true if a is a square.\n\n\n\n\n\n","category":"method"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Base.sqrt{T <: Integer}(::ResFieldElem{T})","category":"page"},{"location":"residue/#Base.sqrt-Union{Tuple{AbstractAlgebra.ResFieldElem{T}}, Tuple{T}} where T<:Integer","page":"Generic residue rings","title":"Base.sqrt","text":"sqrt(a::ResFieldElem{T}; check::Bool=true) where T <: Integer\n\nReturn the square root of a. By default the function will throw an exception if the input is not square. If check=false this test is omitted.\n\n\n\n\n\n","category":"method"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Examples","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"julia> R = residue_field(ZZ, 733)\nResidue field of Integers modulo 733\n\njulia> a = R(86)\n86\n\njulia> is_square(a)\ntrue\n\njulia> sqrt(a)\n532","category":"page"},{"location":"residue/#Random-generation","page":"Generic residue rings","title":"Random generation","text":"","category":"section"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Random residues can be generated using rand. The parameters after the residue ring are used to generate elements of the base ring.","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"rand(R::ResidueRing, v...)","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"Examples","category":"page"},{"location":"residue/","page":"Generic residue rings","title":"Generic residue rings","text":"julia> R, = residue_ring(ZZ, 7);\n\njulia> f = rand(R, 0:6)\n4\n\njulia> S, x = polynomial_ring(QQ, \"x\")\n(Univariate polynomial ring in x over rationals, x)\n\njulia> g = rand(S, 2:2, -10:10)\n-1//4*x^2 - 2//7*x + 1","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"laurent_mpolynomial/#Sparse-distributed-multivariate-Laurent-polynomials","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"","category":"section"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"Every element of the multivariate Laurent polynomial ring Rx_1 x_1^-1 dots x_n x_n^-1 can be presented as a sum of products of powers of the x_i where the power can be any integer. Therefore, the interface for sparse multivarate polynomials carries over with the additional feature that exponents can be negative.","category":"page"},{"location":"laurent_mpolynomial/#Generic-multivariate-Laurent-polynomial-types","page":"Sparse distributed multivariate Laurent polynomials","title":"Generic multivariate Laurent polynomial types","text":"","category":"section"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"AbstractAlgebra.jl provides a generic implementation of multivariate Laurent polynomials, built in terms of regular multivariate polynomials, in the file src/generic/LaurentMPoly.jl.","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"The type LaurentMPolyWrap{T, ...} <: LaurentMPolyRingElem{T} implements generic multivariate Laurent polynomials by wrapping regular polynomials: a Laurent polynomial l wraps a polynomial p and a vector of integers n_i such that l = prod_i x_i^n_i * p. The representation is said to be normalized when each n_i is as large as possible (or zero when l is zero), but the representation of a given element is not required to be normalized internally.","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"The corresponding parent type is LaurentMPolyWrapRing{T, ...} <: LaurentMPolyRing{T}.","category":"page"},{"location":"laurent_mpolynomial/#Abstract-types","page":"Sparse distributed multivariate Laurent polynomials","title":"Abstract types","text":"","category":"section"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"Two abstract types LaurentMPolyRingElem{T} and LaurentMPolyRing{T} are defined to represent Laurent polynomials and rings thereof, parameterized on a base ring T.","category":"page"},{"location":"laurent_mpolynomial/#Multivate-Laurent-polynomial-operations","page":"Sparse distributed multivariate Laurent polynomials","title":"Multivate Laurent polynomial operations","text":"","category":"section"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"Since, from the point of view of the interface, Laurent polynomials are simply regular polynomials with possibly negative exponents, the following functions from the polynomial interface are completely analogous. As with regular polynomials, an implementation must provide access to the elements as a sum of individual terms in some order. This order currently cannot be specified in the constructor.","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"laurent_polynomial_ring(R::Ring, S::Vector{<:VarName}; cached::Bool = true)\nlaurent_polynomial_ring(R::Ring, n::Int, s::VarName; cached::Bool = false)","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"(S::LaurentMPolyRing{T})(A::Vector{T}, m::Vector{Vector{Int}})","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"MPolyBuildCtx(R::LaurentMPolyRing)\npush_term!(M::LaurentMPolyBuildCtx, c::RingElem, v::Vector{Int})\nfinish(M::LaurentMPolyBuildCtx)","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"symbols(S::LaurentMPolyRing)\nnumber_of_variables(f::LaurentMPolyRing)\ngens(S::LaurentMPolyRing)\ngen(S::LaurentMPolyRing, i::Int)\nis_gen(x::LaurentMPolyRingElem)\nvar_index(p::LaurentMPolyRingElem)\nlength(f::LaurentMPolyRingElem)","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"coefficients(p::LaurentMPolyRingElem)\nmonomials(p::LaurentMPolyRingElem)\nterms(p::LaurentMPolyRingElem)\nexponent_vectors(p::LaurentMPolyRingElem)\nleading_coefficient(p::LaurentMPolyRingElem)\nleading_monomial(p::LaurentMPolyRingElem)\nleading_term(p::LaurentMPolyRingElem)\nleading_exponent_vector(p::LaurentMPolyRingElem)","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"change_base_ring(::Ring, p::LaurentMPolyRingElem)\nchange_coefficient_ring(::Ring, p::LaurentMPolyRingElem)\nmap_coefficients(::Any, p::LaurentMPolyRingElem)","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"evaluate(p::LaurentMPolyRingElem, ::Vector)","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"derivative(p::LaurentMPolyRingElem, x::LaurentMPolyRingElem)\nderivative(p::LaurentMPolyRingElem, i::Int)","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"rand(R::LaurentMPolyRingElem, length_range::AbstractUnitRange{Int}, exp_range::AbstractUnitRange{Int}, v...)","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"The choice of canonical unit for Laurent polynomials includes the product prod_i x_i^n_i from the normalized representation. In particular, this means that the output of gcd will not have any negative exponents.","category":"page"},{"location":"laurent_mpolynomial/","page":"Sparse distributed multivariate Laurent polynomials","title":"Sparse distributed multivariate Laurent polynomials","text":"julia> R, (x, y) = laurent_polynomial_ring(ZZ, [\"x\", \"y\"]);\n\njulia> canonical_unit(2*x^-5 - 3*x + 4*y^-4 + 5*y^2)\n-x^-5*y^-4\n\njulia> gcd(x^-3 - y^3, x^-2 - y^2)\nx*y - 1","category":"page"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"module_homomorphism/#Module-Homomorphisms","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"","category":"section"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"Abstract Algebra provides homomorphisms of finitely presented modules.","category":"page"},{"location":"module_homomorphism/#Generic-module-homomorphism-types","page":"Module Homomorphisms","title":"Generic module homomorphism types","text":"","category":"section"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"AbstractAlgebra defines two module homomorphism types, namely Generic.ModuleHomomorphism and Generic.ModuleIsomorphism. Functionality for these is implemented in src/generic/ModuleHomomorphism.jl.","category":"page"},{"location":"module_homomorphism/#Abstract-types","page":"Module Homomorphisms","title":"Abstract types","text":"","category":"section"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"The Generic.ModuleHomomorphism and Generic.ModuleIsomorphism types inherit from Map(FPModuleHomomorphism).","category":"page"},{"location":"module_homomorphism/#Generic-functionality","page":"Module Homomorphisms","title":"Generic functionality","text":"","category":"section"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"The following generic functionality is provided for module homomorphisms.","category":"page"},{"location":"module_homomorphism/#Constructors","page":"Module Homomorphisms","title":"Constructors","text":"","category":"section"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"Homomorphisms of AbstractAlgebra modules, f R^s to R^t, can be represented by stimes t matrices over R.","category":"page"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"ModuleHomomorphism(M1::FPModule{T}, M2::FPModule{T}, m::MatElem{T}) where T <: RingElement","category":"page"},{"location":"module_homomorphism/#AbstractAlgebra.ModuleHomomorphism-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, AbstractAlgebra.FPModule{T}, MatElem{T}}} where T<:RingElement","page":"Module Homomorphisms","title":"AbstractAlgebra.ModuleHomomorphism","text":"ModuleHomomorphism(M1::FPModule{T},\n M2::FPModule{T}, m::MatElem{T}) where T <: RingElement\n\nCreate the homomorphism f M_1 to M_2 represented by the matrix m.\n\n\n\n\n\n","category":"method"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"ModuleIsomorphism(M1::FPModule{T}, M2::FPModule{T}, m::MatElem{T}) where T <: RingElement","category":"page"},{"location":"module_homomorphism/#AbstractAlgebra.ModuleIsomorphism-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, AbstractAlgebra.FPModule{T}, MatElem{T}}} where T<:RingElement","page":"Module Homomorphisms","title":"AbstractAlgebra.ModuleIsomorphism","text":"ModuleIsomorphism(M1::FPModule{T}, M2::FPModule{T}, M::MatElem{T},\n minv::MatElem{T}) where T <: RingElement\n\nCreate the isomorphism f M_1 to M_2 represented by the matrix M. The inverse morphism is automatically computed.\n\n\n\n\n\n","category":"method"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"Examples","category":"page"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"julia> M = FreeModule(ZZ, 2)\nFree module of rank 2 over integers\n\njulia> f = ModuleHomomorphism(M, M, matrix(ZZ, 2, 2, [1, 2, 3, 4]))\nModule homomorphism\n from free module of rank 2 over integers\n to free module of rank 2 over integers\n\njulia> m = M([ZZ(1), ZZ(2)])\n(1, 2)\n\njulia> f(m)\n(7, 10)\n","category":"page"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"They can also be created by giving images (in the codomain) of the generators of the domain:","category":"page"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"ModuleHomomorphism(M1::FPModule{T}, M2::FPModule{T}, v::Vector{<:FPModuleElem{T}}) where T <: RingElement","category":"page"},{"location":"module_homomorphism/#Kernels","page":"Module Homomorphisms","title":"Kernels","text":"","category":"section"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"kernel(f::Map(FPModuleHomomorphism))","category":"page"},{"location":"module_homomorphism/#AbstractAlgebra.kernel-Tuple{Map{D, C, <:AbstractAlgebra.FPModuleHomomorphism, T} where {D, C, T}}","page":"Module Homomorphisms","title":"AbstractAlgebra.kernel","text":"kernel(f::ModuleHomomorphism{T}) where T <: RingElement\n\nReturn a pair K, g consisting of the kernel object K of the given module homomorphism f (as a submodule of its domain) and the canonical injection from the kernel into the domain of f\n\n\n\n\n\n","category":"method"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"Examples","category":"page"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"julia> M = FreeModule(ZZ, 3)\nFree module of rank 3 over integers\n\njulia> m = M([ZZ(1), ZZ(2), ZZ(3)])\n(1, 2, 3)\n\njulia> S, f = sub(M, [m])\n(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 3 over integers)\n\njulia> Q, g = quo(M, S)\n(Quotient module over Integers with 2 generators and no relations, Hom: free module of rank 3 over integers -> quotient module over Integers with 2 generators and no relations)\n\njulia> kernel(g)\n(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 3 over integers)\n","category":"page"},{"location":"module_homomorphism/#Images","page":"Module Homomorphisms","title":"Images","text":"","category":"section"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"image(::Map(FPModuleHomomorphism))","category":"page"},{"location":"module_homomorphism/#AbstractAlgebra.image-Tuple{Map{D, C, <:AbstractAlgebra.FPModuleHomomorphism, T} where {D, C, T}}","page":"Module Homomorphisms","title":"AbstractAlgebra.image","text":"image(f::Map(FPModuleHomomorphism))\n\nReturn a pair I, g consisting of the image object I of the given module homomorphism f (as a submodule of its codomain) and the canonical injection from the image into the codomain of f\n\n\n\n\n\n","category":"method"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"M = FreeModule(ZZ, 3)\n\nm = M([ZZ(1), ZZ(2), ZZ(3)])\n\nS, f = sub(M, [m])\nQ, g = quo(M, S)\nK, k = kernel(g)\n\nimage(compose(k, g))","category":"page"},{"location":"module_homomorphism/#Preimages","page":"Module Homomorphisms","title":"Preimages","text":"","category":"section"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"preimage(::Map(FPModuleHomomorphism), ::FPModuleElem{T}) where T <: RingElement","category":"page"},{"location":"module_homomorphism/#AbstractAlgebra.preimage-Union{Tuple{T}, Tuple{Map{D, C, <:AbstractAlgebra.FPModuleHomomorphism, T} where {D, C, T}, AbstractAlgebra.FPModuleElem{T}}} where T<:RingElement","page":"Module Homomorphisms","title":"AbstractAlgebra.preimage","text":"preimage(f::Map(FPModuleHomomorphism),\n v::FPModuleElem{T}) where T <: RingElement\n\nReturn a preimage of v under the homomorphism f, i.e. an element of the domain of f that maps to v under f. Note that this has no special mathematical properties. It is an element of the set theoretical preimage of the map f as a map of sets, if one exists. The preimage is neither unique nor chosen in a canonical way in general. When no such element exists, an exception is raised.\n\n\n\n\n\n","category":"method"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"M = FreeModule(ZZ, 3)\n\nm = M([ZZ(1), ZZ(2), ZZ(3)])\n\nS, f = sub(M, [m])\nQ, g = quo(M, S)\n\nm = rand(M, -10:10)\nn = g(m)\n\np = preimage(g, n)","category":"page"},{"location":"module_homomorphism/#Inverses","page":"Module Homomorphisms","title":"Inverses","text":"","category":"section"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"Module isomorphisms can be cheaply inverted.","category":"page"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"Base.inv(::Map(Generic.ModuleIsomorphism))","category":"page"},{"location":"module_homomorphism/#Base.inv-Tuple{Map{AbstractAlgebra.FPModule{T}, AbstractAlgebra.FPModule{T}, AbstractAlgebra.FPModuleHomomorphism, AbstractAlgebra.Generic.ModuleIsomorphism} where T<:RingElement}","page":"Module Homomorphisms","title":"Base.inv","text":"Base.inv(f::Map(ModuleIsomorphism))\n\nReturn the inverse map of the given module isomorphism. This is computed cheaply.\n\n\n\n\n\n","category":"method"},{"location":"module_homomorphism/","page":"Module Homomorphisms","title":"Module Homomorphisms","text":"M = FreeModule(ZZ, 2)\nN = matrix(ZZ, 2, 2, BigInt[1, 0, 0, 1])\nf = ModuleIsomorphism(M, M, N)\n\ng = inv(f)","category":"page"},{"location":"ring_introduction/#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"ring_introduction/","page":"Introduction","title":"Introduction","text":"A rich ring hierarchy is provided, supporting both commutative and noncommutative rings.","category":"page"},{"location":"ring_introduction/","page":"Introduction","title":"Introduction","text":"A number of basic rings are provided, such as the integers, integers mod n and numerous fields.","category":"page"},{"location":"ring_introduction/","page":"Introduction","title":"Introduction","text":"A recursive rings implementation is then built on top of the basic rings via a number of generic ring constructions. These include univariate and multivariate polynomials and power series, univariate Laurent and Puiseux series, residue rings, matrix algebras, etc.","category":"page"},{"location":"ring_introduction/","page":"Introduction","title":"Introduction","text":"Where possible, these constructions can be built on top of one another in generic towers.","category":"page"},{"location":"ring_introduction/","page":"Introduction","title":"Introduction","text":"The ring hierarchy can be extended by implementing new rings to follow one or more ring interfaces. Generic functionality provided by the system is then automatically available for the new rings. These implementations can either be generic or can be specialised implementations provided by, for example, a C library.","category":"page"},{"location":"ring_introduction/","page":"Introduction","title":"Introduction","text":"In most cases, the interfaces consist of a set of constructors and functions that must be implemented to satisfy the interface. These are the functions that the generic code relies on being available.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"poly_interface/#Univariate-Polynomial-Ring-Interface","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"","category":"section"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Univariate polynomial rings are supported in AbstractAlgebra, and in addition to the standard Ring interface, numerous additional functions are required to be present for univariate polynomial rings.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Univariate polynomial rings can be built over both commutative and noncommutative rings.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Univariate polynomial rings over a field are also Euclidean and therefore such rings must implement the Euclidean interface.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Since a sparse distributed multivariate format can generally also handle sparse univariate polynomials, the univariate polynomial interface is designed around the assumption that they are dense. This is not a requirement, but it may be easier to use the multivariate interface for sparse univariate types.","category":"page"},{"location":"poly_interface/#Types-and-parents","page":"Univariate Polynomial Ring Interface","title":"Types and parents","text":"","category":"section"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"AbstractAlgebra provides two abstract types for polynomial rings and their elements over a commutative ring:","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"PolyRing{T} is the abstract type for univariate polynomial ring parent types\nPolyRingElem{T} is the abstract type for univariate polynomial types","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Similarly there are two abstract types for polynomial rings and their elements over a noncommutative ring:","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"NCPolyRing{T} is the abstract type for univariate polynomial ring parent types\nNCPolyRingElem{T} is the abstract type for univariate polynomial types","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"We have that PolyRing{T} <: Ring and PolyRingElem{T} <: RingElem. Similarly we have that NCPolyRing{T} <: NCRing and NCPolyRingElem{T} <: NCRingElem.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Note that the abstract types are parameterised. The type T should usually be the type of elements of the coefficient ring of the polynomial ring. For example, in the case of mathbbZx the type T would be the type of an integer, e.g. BigInt.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"If the parent object for such a ring has type MyZX and polynomials in that ring have type MyZXPoly then one would have:","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"MyZX <: PolyRing{BigInt}\nMyZXPoly <: PolyRingElem{BigInt}","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Polynomial rings should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Polynomial rings should at least be distinguished based on their base (coefficient) ring. But if they have the same base ring and symbol (for their variable/generator), they should certainly have the same parent object.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).","category":"page"},{"location":"poly_interface/#Required-functionality-for-univariate-polynomials","page":"Univariate Polynomial Ring Interface","title":"Required functionality for univariate polynomials","text":"","category":"section"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"In addition to the required functionality for the Ring/NCRing interface (and in the case of polynomials over a field, the Euclidean Ring interface), the Polynomial Ring interface has the following required functions.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"We suppose that R is a fictitious base ring (coefficient ring) and that S is a univariate polynomial ring over R (i.e. S = Rx) with parent object S of type MyPolyRing{T}. We also assume the polynomials in the ring have type MyPoly{T}, where T is the type of elements of the base (coefficient) ring.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Note that the type T must (transitively) belong to the abstract type RingElem or NCRingElem.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"We describe the functionality below for polynomials over commutative rings, i.e. with element type belonging to RingElem, however similar constructors should be available for element types belonging to NCRingElem instead, if the coefficient ring is noncommutative.","category":"page"},{"location":"poly_interface/#Constructors","page":"Univariate Polynomial Ring Interface","title":"Constructors","text":"","category":"section"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"In addition to the standard constructors, the following constructors, taking an array of coefficients, must be available.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"(S::MyPolyRing{T})(A::Vector{T}) where T <: RingElem\n(S::MyPolyRing{T})(A::Vector{U}) where T <: RingElem, U <: RingElem\n(S::MyPolyRing{T})(A::Vector{U}) where T <: RingElem, U <: Integer","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Create the polynomial in the given ring whose degree i coefficient is given by A[1 + i]. The elements of the array are assumed to be able to be coerced into the base ring R. If the argument is an empty vector, the zero polynomial shall be returned.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"It may be desirable to have a additional version of the function that accepts an array of Julia Int values if this can be done more efficiently.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"It is also possible to create polynomials directly without first creating the corresponding polynomial ring.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"polynomial(R::Ring, arr::Vector{T}, var::VarName=:x; cached::Bool=true)","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Given an array of coefficients construct the polynomial with those coefficients over the given ring and with the given variable.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"note: Note\nIf cached is set to false then the parent ring of the created polynomial is not cached. However, this means that subsequent polynomials created in the same way will not be compatible. Instead, one should use the parent object of the first polynomial to create subsequent polynomials instead of calling this function repeatedly with cached=false.","category":"page"},{"location":"poly_interface/#Data-type-and-parent-object-methods","page":"Univariate Polynomial Ring Interface","title":"Data type and parent object methods","text":"","category":"section"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"var(S::MyPolyRing{T}) where T <: RingElem","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Return a Symbol representing the variable (generator) of the polynomial ring. Note that this is a Symbol not a String, though its string value will usually be used when printing polynomials.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"symbols(S::MyPolyRing{T}) where T <: RingElem","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Return the array [s] where s is a Symbol representing the variable of the given polynomial ring. This is provided for uniformity with the multivariate interface, where there is more than one variable and hence an array of symbols.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"dense_poly_type(::Type{T}) where T <: RingElement","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Return the type of a polynomial whose coefficients have the given type. In our example MyPoly{T}.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"This function is defined for generic polynomials and only needs to be defined for custom polynomial rings, e.g. ones defined by a C implementation.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"polynomial_ring_only(R::Ring, s::Symbol; cached::Bool=true)","category":"page"},{"location":"poly_interface/#AbstractAlgebra.polynomial_ring_only-Tuple{Ring, Symbol}","page":"Univariate Polynomial Ring Interface","title":"AbstractAlgebra.polynomial_ring_only","text":"polynomial_ring_only(R::NCRing, s::Symbol; cached::Bool=true)\n\nLike polynomial_ring(R::NCRing, s::Symbol) but return only the polynomial ring.\n\n\n\n\n\n","category":"method"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"The default implementation figures out the appropriate polynomial ring type via dense_poly_type and calls its constructor with R, s, cached as arguments. In our example, this would be","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"MyPolyRing{T}(R, s, cached)","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Accordingly, polynomial_ring_only only needs to be defined, if such a constructor does not exist or other behaviour is wanted.","category":"page"},{"location":"poly_interface/#Basic-manipulation-of-rings-and-elements","page":"Univariate Polynomial Ring Interface","title":"Basic manipulation of rings and elements","text":"","category":"section"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"length(f::MyPoly{T}) where T <: RingElem","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Return the length of the given polynomial. The length of the zero polynomial is defined to be 0, otherwise the length is the degree plus 1. The return value should be of type Int.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"set_length!(f::MyPoly{T}, n::Int) where T <: RingElem","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"This function must zero any coefficients beyond the requested length n and then set the length of the polynomial to n. This function does not need to normalise the polynomial and is not useful to the user, but is used extensively by the AbstractAlgebra generic functionality.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"This function returns the resulting polynomial.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"coeff(f::MyPoly{T}, n::Int) where T <: RingElem","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Return the coefficient of the polynomial f of degree n. If n is larger than the degree of the polynomial, it should return zero in the coefficient ring. ","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"setcoeff!(f::MyPoly{T}, n::Int, a::T) where T <: RingElem","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Set the degree n coefficient of f to a. This mutates the polynomial in-place if possible and returns the mutated polynomial (so that immutable types can also be supported). The function must not assume that the polynomial already has space for n + 1 coefficients. The polynomial must be resized if this is not the case.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Note that this function is not required to normalise the polynomial and is not necessarily useful to the user, but is used extensively by the generic functionality in AbstractAlgebra.jl. It is for setting raw coefficients in the representation.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"normalise(f::MyPoly{T}, n::Int) where T <: RingElem","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Given a polynomial whose length is currently n, including any leading zero coefficients, return the length of the normalised polynomial (either zero or the length of the polynomial with nonzero leading coefficient). Note that the function does not actually perform the normalisation.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"fit!(f::MyPoly{T}, n::Int) where T <: RingElem","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Ensure that the polynomial f internally has space for n coefficients. This function must mutate the function in-place if it is mutable. It does not return the mutated polynomial. Immutable types can still be supported by defining this function to do nothing.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Some interfaces for C polynomial types automatically manage the internal allocation of polynomials in every function that can be called on them. Explicit adjustment by the generic code in AbstractAlgebra.jl is not required. In such cases, this function can also be defined to do nothing.","category":"page"},{"location":"poly_interface/#Optional-functionality-for-polynomial-rings","page":"Univariate Polynomial Ring Interface","title":"Optional functionality for polynomial rings","text":"","category":"section"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Sometimes parts of the Euclidean Ring interface can and should be implemented for polynomials over a ring that is not necessarily a field.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"When divisibility testing can be implemented for a polynomial ring over a field, it should be possible to implement the following functions from the Euclidean Ring interface:","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"divides\nremove\nvaluation","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"When the given polynomial ring is a GCD domain, with an effective GCD algorithm, it may be possible to implement the following functions:","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"gcd\nlcm","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Polynomial rings can optionally implement any part of the generic univariate polynomial functionality provided by AbstractAlgebra.jl, using the same interface. ","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Obviously additional functionality can also be added to that provided by AbstractAlgebra.jl on an ad hoc basis.","category":"page"},{"location":"poly_interface/#Similar","page":"Univariate Polynomial Ring Interface","title":"Similar","text":"","category":"section"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"The similar function is available for all univariate polynomial types, but new polynomial rings can define a specialised version of it if required.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"similar(x::MyPoly{T}, R::Ring=base_ring(x), var::VarName=var(parent(x))) where T <: RingElem","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Construct the zero polynomial with the given variable and coefficients in the given ring, if specified, and with the defaults shown if not.","category":"page"},{"location":"poly_interface/","page":"Univariate Polynomial Ring Interface","title":"Univariate Polynomial Ring Interface","text":"Custom polynomial rings may choose which polynomial type is best-suited to return for any given arguments. If they don't specialise the function the default polynomial type returned is a Generic.Poly.","category":"page"},{"location":"ring/#Ring-functionality","page":"Ring functionality","title":"Ring functionality","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"AbstractAlgebra has both commutative and noncommutative rings. Together we refer to them below as rings.","category":"page"},{"location":"ring/#Abstract-types-for-rings","page":"Ring functionality","title":"Abstract types for rings","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"All commutative ring types in AbstractAlgebra belong to the Ring abstract type and commutative ring elements belong to the RingElem abstract type.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Noncommutative ring types belong to the NCRing abstract type and their elements to NCRingElem.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"As Julia types cannot belong to our RingElem type hierarchy, we also provide the union type RingElement which includes RingElem in union with the Julia types Integer, Rational and AbstractFloat.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Similarly NCRingElement includes the Julia types just mentioned in union with NCRingElem.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Note that","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Ring <: NCRing\nRingElem <: NCRingElem\nRingElement <: NCRingElement","category":"page"},{"location":"ring/#Functions-for-types-and-parents-of-rings","page":"Ring functionality","title":"Functions for types and parents of rings","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"parent_type(::Type{T}) where T <: NCRingElement\nelem_type(::Type{T}) where T <: NCRing","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Return the type of the parent (resp. element) type corresponding to the given ring element (resp. parent) type.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"base_ring(R::NCRing)\nbase_ring(a::NCRingElement)","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"For generic ring constructions over a base ring (e.g. polynomials over a coefficient ring), return the parent object of that base ring.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"parent(a::NCRingElement)","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Return the parent of the given ring element.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"is_domain_type(::Type{T}) where T <: NCRingElement\nis_exact_type(::Type{T}) where T <: NCRingElement","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Return true if the given ring element type can only belong to elements of an integral domain or exact ring respectively. (An exact ring is one whose elements are represented exactly in the system without approximation.)","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"The following function is implemented where mathematically and algorithmically possible.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"characteristic(R::NCRing)","category":"page"},{"location":"ring/#Constructors","page":"Ring functionality","title":"Constructors","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"If R is a parent object of a ring in AbstractAlgebra, it can always be used to construct certain objects in that ring.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"(R::NCRing)() # constructs zero\n(R::NCRing)(c::Integer)\n(R::NCRing)(c::elem_type(R))\n(R::NCRing{T})(a::T) where T <: RingElement","category":"page"},{"location":"ring/#Basic-functions","page":"Ring functionality","title":"Basic functions","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"All rings in AbstractAlgebra are expected to implement basic ring operations, unary minus, binary addition, subtraction and multiplication, equality testing, powering.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"In addition, the following are implemented for parents/elements just as they would be in Julia for types/objects.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"zero(R::NCRing)\none(R::NCRing)\niszero(a::NCRingElement)\nisone(a::NCRingElement)","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"In addition, the following are implemented where it is mathematically/algorithmically viable to do so.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"is_unit(a::NCRingElement)\nis_zero_divisor(a::NCRingElement)\nis_zero_divisor_with_annihilator(a::NCRingElement)","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"The following standard Julia functions are also implemented for all ring elements.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"hash(f::RingElement, h::UInt)\ndeepcopy_internal(a::RingElement, dict::IdDict)\nshow(io::IO, R::NCRing)\nshow(io::IO, a::NCRingElement)","category":"page"},{"location":"ring/#Basic-functionality-for-inexact-rings-only","page":"Ring functionality","title":"Basic functionality for inexact rings only","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"By default, inexact ring elements in AbstractAlgebra compare equal if they are the same to the minimum precision of the two elements. However, we also provide the following more strict notion of equality, which also requires the precisions to be the same.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"isequal(a::T, b::T) where T <: NCRingElement","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"For floating point and ball arithmetic it is sometimes useful to be able to check if two elements are approximately equal, e.g. to suppress numerical noise in comparisons. For this, the following are provided.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"isapprox(a::T, b::T; atol::Real=sqrt(eps())) where T <: RingElement","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Similarly, for a parameterised ring with type MyElem{T} over such an inexact ring we have the following.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"isapprox(a::MyElem{T}, b::T; atol::Real=sqrt(eps())) where T <: RingElement\nisapprox(a::T, b::MyElem{T}; atol::Real=sqrt(eps())) where T <: RingElement","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"These notionally perform a coercion into the parameterised ring before doing the approximate equality test.","category":"page"},{"location":"ring/#Basic-functionality-for-commutative-rings-only","page":"Ring functionality","title":"Basic functionality for commutative rings only","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"divexact(a::T, b::T) where T <: RingElement\ninv(a::T)","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Return a/b or 1/a respectively, where the slash here refers to the mathematical notion of division in the ring, not Julia's floating point division operator.","category":"page"},{"location":"ring/#Basic-functionality-for-noncommutative-rings-only","page":"Ring functionality","title":"Basic functionality for noncommutative rings only","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"divexact_left(a::T, b::T) where T <: NCRingElement\ndivexact_right(a::T, b::T) where T <: NCRingElement","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"As per divexact above, except that division by b happens on the left or right, respectively, of a.","category":"page"},{"location":"ring/#Unsafe-ring-operators","page":"Ring functionality","title":"Unsafe ring operators","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"To speed up polynomial arithmetic, various unsafe operators are provided, which mutate the output rather than create a new object.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"zero!(a::NCRingElement)\nmul!(a::T, b::T, c::T) where T <: NCRingElement\nadd!(a::T, b::T, c::T) where T <: NCRingElement\naddeq!(a::T, b::T) where T <: NCRingElement\naddmul!(a::T, b::T, c::T, t::T) where T <: NCRingElement","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"In each case the mutated object is the leftmost parameter.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"The addeq!(a, b) operation does the same thing as add!(a, a, b). The optional addmul!(a, b, c, t) operation does the same thing as mul!(t, b, c); addeq!(a, t) where t is a temporary which can be mutated so that an addition allocation is not needed.","category":"page"},{"location":"ring/#Random-generation","page":"Ring functionality","title":"Random generation","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"The Julia random interface is implemented for all ring parents (instead of for types). The exact interface differs depending on the ring, but the parameters supplied are usually ranges, e.g. -1:10 for the range of allowed degrees for a univariate polynomial.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"rand(R::NCRing, v...)","category":"page"},{"location":"ring/#Factorization","page":"Ring functionality","title":"Factorization","text":"","category":"section"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"For commutative rings supporting factorization and irreducibility testing, the following optional functions may be implemented.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"is_irreducible(a::T) where T <: RingElement\nis_squarefree(a::T) where T <: RingElement","category":"page"},{"location":"ring/#AbstractAlgebra.is_irreducible-Tuple{T} where T<:RingElement","page":"Ring functionality","title":"AbstractAlgebra.is_irreducible","text":"is_irreducible(a::RingElement)\n\nReturn true if a is irreducible, else return false. Zero and units are by definition never irreducible.\n\n\n\n\n\n","category":"method"},{"location":"ring/#AbstractAlgebra.is_squarefree-Tuple{T} where T<:RingElement","page":"Ring functionality","title":"AbstractAlgebra.is_squarefree","text":"is_squarefree(a::RingElement)\n\nReturn true if a is squarefree, else return false. An element is squarefree if it it is not divisible by any squares except the squares of units.\n\n\n\n\n\n","category":"method"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"factor(a::T) where T <: RingElement\nfactor_squarefree(a::T) where T <: RingElement","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Return a factorization into irreducible or squarefree elements, respectively. The return is an object of type Fac{T}.","category":"page"},{"location":"ring/","page":"Ring functionality","title":"Ring functionality","text":"Fac\nunit(a::Fac)\nevaluate(a::Fac)\ngetindex(a::Fac, b)\nsetindex!(a::Fac{Int}, c::Int, b::Int)","category":"page"},{"location":"ring/#AbstractAlgebra.Fac","page":"Ring functionality","title":"AbstractAlgebra.Fac","text":"Fac{T <: RingElement}\n\nType for factored ring elements. The structure holds a unit of type T and is an iterable collection of T => Int pairs for the factors and exponents.\n\nSee unit(a::Fac), evaluate(a::Fac).\n\n\n\n\n\n","category":"type"},{"location":"ring/#AbstractAlgebra.Generic.unit-Tuple{Fac}","page":"Ring functionality","title":"AbstractAlgebra.Generic.unit","text":"unit(a::Fac{T}) -> T\n\nReturn the unit of the factorization.\n\n\n\n\n\n","category":"method"},{"location":"ring/#AbstractAlgebra.evaluate-Tuple{Fac}","page":"Ring functionality","title":"AbstractAlgebra.evaluate","text":"evaluate(a::Fac{T}) -> T\n\nMultiply out the factorization into a single element.\n\n\n\n\n\n","category":"method"},{"location":"ring/#Base.getindex-Tuple{Fac, Any}","page":"Ring functionality","title":"Base.getindex","text":"getindex(a::Fac, b) -> Int\n\nIf b is a factor of a, the corresponding exponent is returned. Otherwise an error is thrown.\n\n\n\n\n\n","category":"method"},{"location":"ring/#Base.setindex!-Tuple{Fac{Int64}, Int64, Int64}","page":"Ring functionality","title":"Base.setindex!","text":"setindex!(a::Fac{T}, c::Int, b::T)\n\nIf b is a factor of a, the corresponding entry is set to c.\n\n\n\n\n\n","category":"method"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"perm/#Permutations-and-Symmetric-groups","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"","category":"section"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"AbstractAlgebra.jl provides rudimentary native support for permutation groups (implemented in src/generic/PermGroups.jl). All functionality of permutations is accessible in the Generic submodule.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Permutations are represented internally via vector of integers, wrapped in type Perm{T}, where T<:Integer carries the information on the type of elements of a permutation. Symmetric groups are singleton parent objects of type SymmetricGroup{T} and are used mostly to store the length of a permutation, since it is not included in the permutation type.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Symmetric groups are created using the SymmetricGroup (inner) constructor.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Both SymmetricGroup and Perm and can be parametrized by any type T<:Integer . By default the parameter is the Int-type native to the systems architecture. However, if you are sure that your permutations are small enough to fit into smaller integer type (such as Int32, UInt16, or even Int8), you may choose to change the parametrizing type accordingly. In practice this may result in decreased memory footprint (when storing multiple permutations) and noticeable faster performance, if your workload is heavy in operations on permutations, which e.g. does not fit into cache of your cpu.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"All the permutation group types belong to the Group abstract type and the corresponding permutation element types belong to the GroupElem abstract type.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Generic.setpermstyle","category":"page"},{"location":"perm/#AbstractAlgebra.Generic.setpermstyle","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.setpermstyle","text":"setpermstyle(format::Symbol)\n\nSelect the style in which permutations are displayed (in the REPL or in general as strings). This can be either\n\n:array - as vector of integers whose n-th position represents the value at n), or\n:cycles - as, more familiar for mathematicians, decomposition into disjoint cycles, where the value at n is represented by the entry immediately following n in a cycle (the default).\n\nThe difference is purely esthetical.\n\nExamples\n\njulia> setpermstyle(:array)\n:array\n\njulia> Perm([2,3,1,5,4])\n[2, 3, 1, 5, 4]\n\njulia> setpermstyle(:cycles)\n:cycles\n\njulia> Perm([2,3,1,5,4])\n(1,2,3)(4,5)\n\n\n\n\n\n","category":"function"},{"location":"perm/#Permutations-constructors","page":"Permutations and Symmetric groups","title":"Permutations constructors","text":"","category":"section"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"There are several methods to construct permutations in AbstractAlgebra.jl.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"The easiest way is to directly call to the Perm (inner) constructor:","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Generic.Perm","category":"page"},{"location":"perm/#AbstractAlgebra.Perm","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Perm","text":"Perm{T<:Integer}\n\nThe type of permutations. Fieldnames:\n\nd::Vector{T} - vector representing the permutation\nmodified::Bool - bit to check the validity of cycle decomposition\ncycles::CycleDec{T} - (cached) cycle decomposition\n\nA permutation p consists of a vector (p.d) of n integers from 1 to n. If the i-th entry of the vector is j, this corresponds to p sending i to j. The cycle decomposition (p.cycles) is computed on demand and should never be accessed directly. Use cycles(p) instead.\n\nThere are two inner constructors of Perm:\n\nPerm(n::T) constructs the trivial Perm{T}-permutation of length n.\nPerm(v::AbstractVector{<:Integer} [,check=true]) constructs a permutation represented by v. By default Perm constructor checks if the vector constitutes a valid permutation. To skip the check call Perm(v, false).\n\nExamples\n\njulia> Perm([1,2,3])\n()\n \njulia> g = Perm(Int32[2,3,1])\n(1,2,3)\n\njulia> typeof(g)\nPerm{Int32}\n\n\n\n\n\n","category":"type"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Since the parent object can be reconstructed from the permutation itself, you can work with permutations without explicitly constructing the parent object.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"The other way is to first construct the permutation group they belong to. This is accomplished with the inner constructor SymmetricGroup(n::Integer) which constructs the permutation group on n symbols and returns the parent object representing the group.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Generic.SymmetricGroup","category":"page"},{"location":"perm/#AbstractAlgebra.Generic.SymmetricGroup","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.SymmetricGroup","text":"SymmetricGroup{T<:Integer}\n\nThe full symmetric group singleton type. SymmetricGroup(n) constructs the full symmetric group S_n on n-symbols. The type of elements of the group is inferred from the type of n.\n\nExamples\n\njulia> G = SymmetricGroup(5)\nFull symmetric group over 5 elements\n\njulia> elem_type(G)\nPerm{Int64}\n\njulia> H = SymmetricGroup(UInt16(5))\nFull symmetric group over 5 elements\n\njulia> elem_type(H)\nPerm{UInt16}\n\n\n\n\n\n","category":"type"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"A vector of integers can be then coerced to a permutation by calling a parent permutation group on it. The advantage is that the vector is automatically converted to the integer type fixed at the creation of the parent object.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Examples:","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"julia> G = SymmetricGroup(BigInt(5)); p = G([2,3,1,5,4])\n(1,2,3)(4,5)\n\njulia> typeof(p)\nPerm{BigInt}\n\njulia> H = SymmetricGroup(UInt16(5)); r = H([2,3,1,5,4])\n(1,2,3)(4,5)\n\njulia> typeof(r)\nPerm{UInt16}\n\njulia> one(H)\n()","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"By default the coercion checks for non-unique values in the vector, but this can be switched off with G([2,3,1,5,4], false).","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Finally there is a perm\"...\" string macro to construct a permutation from a string input.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"@perm_str","category":"page"},{"location":"perm/#AbstractAlgebra.Generic.@perm_str","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.@perm_str","text":"perm\"...\"\n\nString macro to parse disjoint cycles into Perm{Int}.\n\nStrings for the output of GAP could be copied directly into perm\"...\". Cycles of length 1 are not necessary, but can be included. A permutation of the minimal support is constructed, i.e. the maximal n in the decomposition determines the parent group S_n.\n\nExamples\n\njulia> p = perm\"(1,3)(2,4)\"\n(1,3)(2,4)\n\njulia> typeof(p)\nPerm{Int64}\n\njulia> parent(p) == SymmetricGroup(4)\ntrue\n\njulia> p = perm\"(1,3)(2,4)(10)\"\n(1,3)(2,4)\n\njulia> parent(p) == SymmetricGroup(10)\ntrue\n\n\n\n\n\n","category":"macro"},{"location":"perm/#Permutation-interface","page":"Permutations and Symmetric groups","title":"Permutation interface","text":"","category":"section"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"The following basic functionality is provided by the default permutation group implementation in AbstractAlgebra.jl, to support construction of other generic constructions over permutation groups. Any custom permutation group implementation in AbstractAlgebra.jl should provide the group element arithmetic and comparison.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"A custom implementation also needs to implement hash(::Perm, ::UInt) and (possibly) deepcopy_internal(::Perm, ::IdDict).","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"note: Note\nPermutation group elements are mutable and so returning shallow copies is not sufficient.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"getindex(a::Perm, n::Integer)","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Allow access to entry n of the given permutation via the syntax a[n]. Note that entries are 1-indexed.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"setindex!(a::Perm, d::Integer, n::Integer)","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Set the n-th entry of the given permutation to d. This allows Julia to provide the syntax a[n] = d for setting entries of a permutation. Entries are 1-indexed.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"note: Note\nUsing setindex! invalidates the cycle decomposition cached in a permutation, which will be computed the next time it is needed.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Given the parent object G for a permutation group, the following coercion functions are provided to coerce various arguments into the permutation group. Developers provide these by overloading the permutation group parent objects.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"one(G)","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Return the identity permutation.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"G(A::Vector{<:Integer})","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Return the permutation whose entries are given by the elements of the supplied vector.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"G(p::Perm)","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Take a permutation that is already in the permutation group and simply return it. A copy of the original is not made if not necessary.","category":"page"},{"location":"perm/#Basic-manipulation","page":"Permutations and Symmetric groups","title":"Basic manipulation","text":"","category":"section"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Numerous functions are provided to manipulate permutation group elements.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"cycles(::Perm)","category":"page"},{"location":"perm/#AbstractAlgebra.Generic.cycles-Tuple{Perm}","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.cycles","text":"cycles(g::Perm)\n\nDecompose permutation g into disjoint cycles.\n\nReturn a CycleDec object which iterates over disjoint cycles of g. The ordering of cycles is not guaranteed, and the order within each cycle is computed up to a cyclic permutation. The cycle decomposition is cached in g and used in future computation of permtype, parity, sign, order and ^ (powering).\n\nExamples\n\njulia> g = Perm([3,4,5,2,1,6])\n(1,3,5)(2,4)\n\njulia> collect(cycles(g))\n3-element Vector{Vector{Int64}}:\n [1, 3, 5]\n [2, 4]\n [6]\n\n\n\n\n\n","category":"method"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Cycle structure is cached in a permutation, since once available, it provides a convenient shortcut in many other algorithms.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"parity(::Perm)\nsign(::Perm)\npermtype(::Perm)","category":"page"},{"location":"perm/#AbstractAlgebra.Generic.parity-Tuple{Perm}","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.parity","text":"parity(g::Perm)\n\nReturn the parity of the given permutation, i.e. the parity of the number of transpositions in any decomposition of g into transpositions.\n\nparity returns 1 if the number is odd and 0 otherwise. parity uses cycle decomposition of g if already available, but will not compute it on demand. Since cycle structure is cached in g you may call cycles(g) before calling parity.\n\nExamples\n\njulia> g = Perm([3,4,1,2,5])\n(1,3)(2,4)\n\njulia> parity(g)\n0\n\njulia> g = Perm([3,4,5,2,1,6])\n(1,3,5)(2,4)\n\njulia> parity(g)\n1\n\n\n\n\n\n","category":"method"},{"location":"perm/#Base.sign-Tuple{Perm}","page":"Permutations and Symmetric groups","title":"Base.sign","text":"sign(g::Perm)\n\nReturn the sign of a permutation.\n\nsign returns 1 if g is even and -1 if g is odd. sign represents the homomorphism from the permutation group to the unit group of mathbbZ whose kernel is the alternating group.\n\nExamples\n\njulia> g = Perm([3,4,1,2,5])\n(1,3)(2,4)\n\njulia> sign(g)\n1\n\njulia> g = Perm([3,4,5,2,1,6])\n(1,3,5)(2,4)\n\njulia> sign(g)\n-1\n\n\n\n\n\n","category":"method"},{"location":"perm/#AbstractAlgebra.Generic.permtype-Tuple{Perm}","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.permtype","text":"permtype(g::Perm)\n\nReturn the type of permutation g, i.e. lengths of disjoint cycles in cycle decomposition of g.\n\nThe lengths are sorted in decreasing order by default. permtype(g) fully determines the conjugacy class of g.\n\nExamples\n\njulia> g = Perm([3,4,5,2,1,6])\n(1,3,5)(2,4)\n\njulia> permtype(g)\n3-element Vector{Int64}:\n 3\n 2\n 1\n\njulia> e = one(g)\n()\n\njulia> permtype(e)\n6-element Vector{Int64}:\n 1\n 1\n 1\n 1\n 1\n 1\n\n\n\n\n\n","category":"method"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Note that even an Int64 can be easily overflowed when computing with symmetric groups. Thus, by default, order returns (always correct) BigInts. If you are sure that the computation will not overflow, you may use order(::Type{T}, ...) to perform computations with machine integers. Julia's standard promotion rules apply for the returned value.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Since SymmetricGroup implements the iterator protocol, you may iterate over all permutations via a simple loop:","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"for p in SymmetricGroup(n)\n ...\nend","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Iteration over all permutations in reasonable time, (i.e. in terms of minutes) is possible when n 13.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"You may also use the non-allocating Generic.elements! function for n 14 (or even 15 if you are patient enough), which is an order of magnitude faster.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Generic.elements!(::Generic.SymmetricGroup)","category":"page"},{"location":"perm/#AbstractAlgebra.Generic.elements!-Tuple{AbstractAlgebra.Generic.SymmetricGroup}","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.elements!","text":"Generic.elements!(G::SymmetricGroup)\n\nReturn an unsafe iterator over all permutations in G. Only one permutation is allocated and then modified in-place using the non-recursive Heaps algorithm.\n\nNote: you need to explicitly copy permutations intended to be stored or modified.\n\nExamples\n\njulia> elts = Generic.elements!(SymmetricGroup(5));\n\n\njulia> length(elts)\n120\n\njulia> for p in Generic.elements!(SymmetricGroup(3))\n println(p)\n end\n()\n(1,2)\n(1,3,2)\n(2,3)\n(1,2,3)\n(1,3)\n\njulia> A = collect(Generic.elements!(SymmetricGroup(3))); A\n6-element Vector{Perm{Int64}}:\n (1,3)\n (1,3)\n (1,3)\n (1,3)\n (1,3)\n (1,3)\n\njulia> unique(A)\n1-element Vector{Perm{Int64}}:\n (1,3)\n\n\n\n\n\n","category":"method"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"However, since all permutations yielded by elements! are aliased (modified \"in-place\"), collect(Generic.elements!(SymmetricGroup(n))) returns a vector of identical permutations.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"note: Note\nIf you intend to use or store elements yielded by elements! you need to deepcopy them explicitly.","category":"page"},{"location":"perm/#Arithmetic-operators","page":"Permutations and Symmetric groups","title":"Arithmetic operators","text":"","category":"section"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"*(::Perm{T}, ::Perm{T}) where T\n^(::Perm, n::Integer)\nBase.inv(::Perm)","category":"page"},{"location":"perm/#Base.:*-Union{Tuple{T}, Tuple{Perm{T}, Perm{T}}} where T","page":"Permutations and Symmetric groups","title":"Base.:*","text":"*(g::Perm, h::Perm)\n\nReturn the composition h g of two permutations.\n\nThis corresponds to the action of permutation group on the set [1..n] on the right and follows the convention of GAP.\n\nIf g and h are parametrized by different types, the result is promoted accordingly.\n\nExamples\n\njulia> Perm([2,3,1,4])*Perm([1,3,4,2]) # (1,2,3)*(2,3,4)\n(1,3)(2,4)\n\n\n\n\n\n","category":"method"},{"location":"perm/#Base.:^-Tuple{Perm, Integer}","page":"Permutations and Symmetric groups","title":"Base.:^","text":"^(g::Perm, n::Integer)\n\nReturn the n-th power of a permutation g.\n\nBy default g^n is computed by cycle decomposition of g if n > 3. Generic.power_by_squaring provides a different method for powering which may or may not be faster, depending on the particular case. Due to caching of the cycle structure, repeated powering of g will be faster with the default method.\n\nExamples\n\njulia> g = Perm([2,3,4,5,1])\n(1,2,3,4,5)\n\njulia> g^3\n(1,4,2,5,3)\n\njulia> g^5\n()\n\n\n\n\n\n","category":"method"},{"location":"perm/#Base.inv-Tuple{Perm}","page":"Permutations and Symmetric groups","title":"Base.inv","text":"Base.inv(g::Perm)\n\nReturn the inverse of the given permutation, i.e. the permutation g^-1 such that g g^-1 = g^-1 g is the identity permutation.\n\n\n\n\n\n","category":"method"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Permutations parametrized by different types can be multiplied, and follow the standard julia integer promotion rules:","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"g = rand(SymmetricGroup(Int8(5)));\nh = rand(SymmetricGroup(UInt32(5)));\ntypeof(g*h)\n\n# output\nPerm{UInt32}","category":"page"},{"location":"perm/#Coercion","page":"Permutations and Symmetric groups","title":"Coercion","text":"","category":"section"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"The following coercions are available for G::SymmetricGroup parent objects. Each of the methods perform basic sanity checks on the input which can be switched off by the second argument.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Examples","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"(G::SymmetricGroup)(::AbstractVector{<:Integer}[, check=true])","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Turn a vector of integers into a permutation (performing conversion, if necessary).","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"(G::SymmetricGroup)(::Perm[, check=true])","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Coerce a permutation p into group G (performing the conversion, if necessary). If p is already an element of G no copy is performed.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"(G::SymmetricGroup)(::String[, check=true])","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Parse the string input e.g. copied from the output of GAP. The method uses the same logic as the perm\"...\" macro. The string is sanitized and checked for disjoint cycles. Both string(p::Perm) (if setpermstyle(:cycles)) and string(cycles(p::Perm)) are valid input for this method.","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"(G::SymmetricGroup{T})(::CycleDec{T}[, check=true]) where T","category":"page"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"Turn a cycle decomposition object into a permutation.","category":"page"},{"location":"perm/#Comparison","page":"Permutations and Symmetric groups","title":"Comparison","text":"","category":"section"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"==(::Perm, ::Perm)\n==(::Generic.SymmetricGroup, ::Generic.SymmetricGroup)","category":"page"},{"location":"perm/#Base.:==-Tuple{Perm, Perm}","page":"Permutations and Symmetric groups","title":"Base.:==","text":"==(g::Perm, h::Perm)\n\nReturn true if permutations are equal, otherwise return false.\n\nPermutations parametrized by different integer types are considered equal if they define the same permutation in the abstract permutation group.\n\nExamples\n\njulia> g = Perm(Int8[2,3,1])\n(1,2,3)\n\njulia> h = perm\"(3,1,2)\"\n(1,2,3)\n\njulia> g == h\ntrue\n\n\n\n\n\n","category":"method"},{"location":"perm/#Base.:==-Tuple{AbstractAlgebra.Generic.SymmetricGroup, AbstractAlgebra.Generic.SymmetricGroup}","page":"Permutations and Symmetric groups","title":"Base.:==","text":"==(G::SymmetricGroup, H::SymmetricGroup)\n\nReturn true if permutation groups are equal, otherwise return false.\n\nPermutation groups on the same number of letters, but parametrized by different integer types are considered different.\n\nExamples\n\njulia> G = SymmetricGroup(UInt(5))\nPermutation group over 5 elements\n\njulia> H = SymmetricGroup(5)\nPermutation group over 5 elements\n\njulia> G == H\nfalse\n\n\n\n\n\n","category":"method"},{"location":"perm/#Misc","page":"Permutations and Symmetric groups","title":"Misc","text":"","category":"section"},{"location":"perm/","page":"Permutations and Symmetric groups","title":"Permutations and Symmetric groups","text":"rand(::Generic.SymmetricGroup)\nGeneric.matrix_repr(::Perm)\nGeneric.emb(::Generic.SymmetricGroup, ::Vector{Int}, ::Bool)\nGeneric.emb!(::Perm, ::Perm, V)","category":"page"},{"location":"perm/#Base.rand-Tuple{AbstractAlgebra.Generic.SymmetricGroup}","page":"Permutations and Symmetric groups","title":"Base.rand","text":"rand([rng=GLOBAL_RNG,] G::SymmetricGroup)\n\nReturn a random permutation from G.\n\n\n\n\n\n","category":"method"},{"location":"perm/#AbstractAlgebra.Generic.matrix_repr-Tuple{Perm}","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.matrix_repr","text":"matrix_repr(a::Perm)\n\nReturn the permutation matrix as a sparse matrix representing a via natural embedding of the permutation group into the general linear group over mathbbZ.\n\nExamples\n\njulia> p = Perm([2,3,1])\n(1,2,3)\n\njulia> matrix_repr(p)\n3×3 SparseArrays.SparseMatrixCSC{Int64, Int64} with 3 stored entries:\n ⋅ 1 ⋅\n ⋅ ⋅ 1\n 1 ⋅ ⋅\n\njulia> Array(ans)\n3×3 Matrix{Int64}:\n 0 1 0\n 0 0 1\n 1 0 0\n\n\n\n\n\nmatrix_repr(Y::YoungTableau)\n\nConstruct sparse integer matrix representing the tableau.\n\nExamples\n\njulia> y = YoungTableau([4,3,1]);\n\n\njulia> matrix_repr(y)\n3×4 SparseArrays.SparseMatrixCSC{Int64, Int64} with 8 stored entries:\n 1 2 3 4\n 5 6 7 ⋅\n 8 ⋅ ⋅ ⋅\n\n\n\n\n\n","category":"method"},{"location":"perm/#AbstractAlgebra.Generic.emb-Tuple{AbstractAlgebra.Generic.SymmetricGroup, Vector{Int64}, Bool}","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.emb","text":"emb(G::SymmetricGroup, V::Vector{Int}, check::Bool=true)\n\nReturn the natural embedding of a permutation group into G as the subgroup permuting points indexed by V.\n\nExamples\n\njulia> p = Perm([2,3,1])\n(1,2,3)\n\njulia> f = Generic.emb(SymmetricGroup(5), [3,2,5]);\n\n\njulia> f(p)\n(2,5,3)\n\n\n\n\n\n","category":"method"},{"location":"perm/#AbstractAlgebra.Generic.emb!-Tuple{Perm, Perm, Any}","page":"Permutations and Symmetric groups","title":"AbstractAlgebra.Generic.emb!","text":"emb!(result::Perm, p::Perm, V)\n\nEmbed permutation p into permutation result on the indices given by V.\n\nThis corresponds to the natural embedding of S_k into S_n as the subgroup permuting points indexed by V.\n\nExamples\n\njulia> p = Perm([2,1,4,3])\n(1,2)(3,4)\n\njulia> Generic.emb!(Perm(collect(1:5)), p, [3,1,4,5])\n(1,3)(4,5)\n\n\n\n\n\n","category":"method"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"matrix_interface/#Matrix-Interface","page":"Matrix Interface","title":"Matrix Interface","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Generic matrices are supported in AbstractAlgebra.jl. Both the space of mtimes n matrices and the algebra (ring) of mtimes m matrices are supported.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"As the space of mtimes n matrices over a commutative ring is not itself a commutative ring, not all of the Ring interface needs to be implemented for such matrices in.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"In particular, the following functions do not need to be implemented: is_domain_type, and divexact. The canonical_unit function should be implemented, but simply needs to return the corresponding value for entry 1 1 (the function is never called on empty matrices).","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"For matrix algebras, all of the ring interface must be implemented.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"note: Note\nAbstractAlgebra.jl matrices are not the same as Julia matrices. We store a base ring in our matrix and matrices are row major instead of column major in order to support the numerous large C libraries that use this convention.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"All AbstractAlgebra.jl matrices are assumed to be mutable. This is usually critical to performance.","category":"page"},{"location":"matrix_interface/#Types-and-parents","page":"Matrix Interface","title":"Types and parents","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"AbstractAlgebra provides two abstract types for matrix spaces and their elements:","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"MatSpace{T} is the abstract type for matrix space parent types\nMatElem{T} is the abstract type for matrix types belonging to a matrix space","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"It also provides two abstract types for matrix algebras and their elements:","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"MatRing{T} is the abstract type for matrix algebra parent types\nMatRingElem{T} is the abstract type for matrix types belonging to a matrix algebra","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Note that these abstract types are parameterised. The type T should usually be the type of elements of the matrices.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Matrix spaces and matrix algebras should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Matrix spaces and algebras should at least be distinguished based on their base (coefficient) ring and the dimensions of the matrices in the space.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).","category":"page"},{"location":"matrix_interface/#Required-functionality-for-matrices","page":"Matrix Interface","title":"Required functionality for matrices","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"In addition to the required (relevant) functionality for the Ring interface (see above), the following functionality is required for the Matrix interface.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"We suppose that R is a fictitious base ring (coefficient ring) and that S is a space of mtimes n matrices over R, or algebra of mtimes m matrices with parent object S of type MyMatSpace{T} or MyMatAlgebra{T}, respectively. We also assume the matrices in the space have type MyMat{T}, where T is the type of elements of the base (element) ring.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Note that the type T must (transitively) belong to the abstract type RingElem.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Currently only matrices over commutative rings are supported.","category":"page"},{"location":"matrix_interface/#Constructors","page":"Matrix Interface","title":"Constructors","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"In addition to the standard constructors, the following constructors, taking an array of elements, must be available.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"(S::MyMatSpace{T})(A::Matrix{T}) where T <: RingElem\n(S::MyMatAlgebra{T})(A::Matrix{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Create the matrix in the given space/algebra whose (i j) entry is given by A[i, j].","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"(S::MyMatSpace{T})(A::Matrix{S}) where {S <: RingElem, T <: RingElem}\n(S::MyMatAlgebra{T})(A::Matrix{S}) where {S <: RingElem, T <: RingElem}","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Create the matrix in the given space/algebra whose (i j) entry is given by A[i, j], where S is the type of elements that can be coerced into the base ring of the matrix.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"(S::MyMatSpace{T})(A::Vector{S}) where {S <: RingElem, T <: RingElem}\n(S::MyMatAlgebra{T})(A::Vector{S}) where {S <: RingElem, T <: RingElem}","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Create the matrix in the given space/algebra of matrices (with dimensions mtimes n say), whose (i j) entry is given by A[i*(n - 1) + j] and where S is the type of elements that can be coerced into the base ring of the matrix.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"It is also possible to create matrices (in a matrix space only) directly, without first creating the corresponding matrix space (the inner constructor being called directly). Note that to support this, matrix space parent objects don't contain a reference to their parent. Instead, parents are constructed on-the-fly if requested. (The same strategy is used for matrix algebras.)","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"matrix(R::Ring, arr::Matrix{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Given an mtimes n Julia matrix of entries, construct the corresponding AbstractAlgebra.jl matrix over the given ring R, assuming all the entries can be coerced into R.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"matrix(R::Ring, r::Int, c::Int, A::Vector{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Construct the given rtimes c AbstractAlgebra.jl matrix over the ring R whose (i j) entry is given by A[c*(i - 1) + j], assuming that all the entries can be coerced into R.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"zero_matrix(R::Ring, r::Int, c::Int)","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Construct the rtimes c AbstractAlgebra.jl zero matrix over the ring R.","category":"page"},{"location":"matrix_interface/#Views","page":"Matrix Interface","title":"Views","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Just as Julia supports views of matrices, AbstractAlgebra requires all matrix types to support views. These allow one to work with a submatrix of a given matrix. Modifying the submatrix also modifies the original matrix.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Note that deepcopy of a view type must return the same type, but it should return a view into a deepcopy of the original matrix. Julia enforces this for consistency.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"To support views, generic matrices in AbstractAlgebra of type Generic.MatSpaceElem have an associated Generic.MatSpaceView type. Both belong to the Generic.Mat abstract type, so that one can work with that in functions that can accept both views and actual matrices.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"The syntax for views is as for Julia's own views.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Note that the parent_type function returns the same type for a view as for the original matrix type. This could potentially cause a problem if the elem_type function is applied to the return value of parent_type and then used in a type assertion. For this reason, there may be some limitations on the use of views.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"The similar function also returns a matrix of type MatSpaceElem when applied to a view, rather than another view.","category":"page"},{"location":"matrix_interface/#Basic-manipulation-of-matrices","page":"Matrix Interface","title":"Basic manipulation of matrices","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"dense_matrix_type(::Type{T}) where T<:NCRingElement\ndense_matrix_type(::T) where T<:NCRingElement\ndense_matrix_type(::Type{S}) where S<:NCRing\ndense_matrix_type(::S) where S<:NCRing","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return the type of dense matrices whose entries have type T respectively elem_type(S). It suffices to provide a method with the first signature. For the other three signatures, the default methods dispatch to the first. E.g. in Nemo, which depends on AbstractAlgebra, we define dense_matrix_type(::Type{ZZRingElem}) = ZZMatrix.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"number_of_rows(M::MyMatSpace{T}) where T <: RingElem\nnumber_of_rows(M::MyMatAlgebra{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return the number of rows of matrices in the matrix space.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"number_of_columns(M:MyMatSpace{T}) where T <: RingElem\nnumber_of_columns(M:MyMatAlgebra{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return the number of columns of matrices in the matrix space.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"number_of_rows(f::MyMat{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return the number of rows of the given matrix.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"number_of_columns(f::MyMat{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return the number of columns of the given matrix.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"getindex(M::MyMat{T}, r::Int, c::Int) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return the (i j)-th entry of the matrix M.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"setindex!(M::MyMat{T}, d::T, r::Int, c::Int) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Set the (i j)-th entry of the matrix M to d, which is assumed to be in the base ring of the matrix. The matrix must have such an entry and the matrix is mutated in place and not returned from the function.","category":"page"},{"location":"matrix_interface/#Transpose","page":"Matrix Interface","title":"Transpose","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"transpose(::MyMat{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return the transpose of the given matrix.","category":"page"},{"location":"matrix_interface/#Optional-functionality-for-matrices","page":"Matrix Interface","title":"Optional functionality for matrices","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Especially when wrapping C libraries, some functions are best implemented directly, rather than relying on the generic functionality. The following are all provided by the AbstractAlgebra.jl generic code, but can optionally be implemented directly for performance reasons.","category":"page"},{"location":"matrix_interface/#Optional-submatrices","page":"Matrix Interface","title":"Optional submatrices","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"The following are only available for matrix spaces, not for matrix algebras.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Base.getindex(M::MyMat, rows::AbstractVector{Int}, cols::AbstractVector{Int})","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return a new matrix with the same entries as the submatrix with the given range of rows and columns.","category":"page"},{"location":"matrix_interface/#Optional-row-swapping","page":"Matrix Interface","title":"Optional row swapping","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"swap_rows!(M::MyMat{T}, i::Int, j::Int) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Swap the rows of M in place. The function returns the mutated matrix (since matrices are assumed to be mutable in AbstractAlgebra.jl).","category":"page"},{"location":"matrix_interface/#Optional-concatenation","page":"Matrix Interface","title":"Optional concatenation","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"The following are only available for matrix spaces, not for matrix algebras.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"hcat(M::MyMat{T}, N::MyMat{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return the horizontal concatenation of M and N. It is assumed that the number of rows of M and N are the same.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"vcat(M::MyMat{T}, N::MyMat{T}) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return the vertical concatenation of M and N. It is assumed that the number of columns of M and N are the same.","category":"page"},{"location":"matrix_interface/#Optional-zero-tests","page":"Matrix Interface","title":"Optional zero tests","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"The following functions are available for matrices in both matrix algebras and matrix spaces.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"is_zero_entry(M::MatrixElem{T}, i::Int, j::Int) where T <: NCRingElement\nis_zero_row(M::MatrixElem{T}, i::Int) where T <: NCRingElement\nis_zero_column(M::MatrixElem{T}, j::Int) where T <: NCRingElement","category":"page"},{"location":"matrix_interface/#Optional-similar-and-zero","page":"Matrix Interface","title":"Optional similar and zero","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"The following functions are available for matrices in both matrix algebras and matrix spaces. Both similar and zero construct new matrices, with the same methods, but the entries are either undefined with similar or zero-initialized with zero.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"similar(x::MyMat{T}, R::Ring=base_ring(x)) where T <: RingElem\nzero(x::MyMat{T}, R::Ring=base_ring(x)) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Construct the matrix with the same dimensions as the given matrix, and the same base ring unless explicitly specified.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"similar(x::MyMat{T}, R::Ring, r::Int, c::Int) where T <: RingElem\nsimilar(x::MyMat{T}, r::Int, c::Int) where T <: RingElem\nzero(x::MyMat{T}, R::Ring, r::Int, c::Int) where T <: RingElem\nzero(x::MyMat{T}, r::Int, c::Int) where T <: RingElem","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Construct the rtimes c matrix with R as base ring (which defaults to the base ring of the the given matrix). If x belongs to a matrix algebra and r neq c, an exception is raised, and it's also possible to specify only one Int as the order (e.g. similar(x, n)).","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Custom matrices and rings may choose which specific matrix type is best-suited to return for the given ring and dimensionality. If they do not specialize these functions, the default is a Generic.MatSpaceElem matrix, or Generic.MatRingElem for matrix algebras. The default implementation of zero calls out to similar, so it's generally sufficient to specialize only similar. For both similar and zero, only the most general method has to be implemented (e.g. similar(x::MyMat, R::Ring, r::Int, c::Int), as all other methods (which have defaults) call out to this more general method.","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Base.isassigned(M::MyMat, i, j)","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Test whether the given matrix has a value associated with indices i and j. It is recommended to overload this method for custom matrices.","category":"page"},{"location":"matrix_interface/#Optional-symmetry-test","page":"Matrix Interface","title":"Optional symmetry test","text":"","category":"section"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"is_symmetric(a::MatrixElem)","category":"page"},{"location":"matrix_interface/","page":"Matrix Interface","title":"Matrix Interface","text":"Return true if the given matrix is symmetric with respect to its main diagonal, otherwise return false.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"univpolynomial/#Universal-polynomial","page":"Universal polynomial","title":"Universal polynomial","text":"","category":"section"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"AbstractAlgebra.jl provides a module, implemented in src/generic/UnivPoly.jl for a universal polynomial ring. This is very similar to the multivariate polynomial rings, except that variables can be added to the ring at any time.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"To compensate for the fact that the number of variables may change, many of the functions relax their restrictions on exponent vectors. For example, if one creates a polynomial when the ring only has two variables, each exponent vector would consist of two integers. Later, when the ring has more variable, these exponent vectors will still be accepted. The exponent vectors are simply padded out to the full number of variables behind the scenes.","category":"page"},{"location":"univpolynomial/#Generic-sparse-distributed-universal-multivariable-polynomial-types","page":"Universal polynomial","title":"Generic sparse distributed universal multivariable polynomial types","text":"","category":"section"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"AbstractAlgebra provides a generic universal polynomial type Generic.UnivPoly{T, U} where T is the type of elements of the coefficient ring and U is the type of the elements of the underlying multivariate polynomial ring. Essentially, U can be any type belonging to MPolyRingElem{T}.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"Parent objects of such polynomials have type Generic.UniversalPolyRing{T, U}.","category":"page"},{"location":"univpolynomial/#Abstract-types","page":"Universal polynomial","title":"Abstract types","text":"","category":"section"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"AbstractAlgebra also provides abstract types for universal polynomials and their rings. These are UniversalPolyRingElem{T, U} and UniversalPolyRing{T, U} respectively. These in turn belong to Ring.","category":"page"},{"location":"univpolynomial/#Polynomial-ring-constructors","page":"Universal polynomial","title":"Polynomial ring constructors","text":"","category":"section"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"In order to construct universal polynomials in AbstractAlgebra.jl, one must first construct the universal polynomial ring itself. This is unique given a base ring.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"The universal polynomial ring over a given base ring R is constructed with one of the following constructor functions.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"UniversalPolynomialRing(R::Ring; cached::Bool = true, ordering::Symbol=:lex)","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"Given a base ring R and an array S of strings, return an object representing the universal polynomial ring S = Rldots with no variables in it initially.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"Examples","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"julia> S = UniversalPolynomialRing(ZZ)\nUniversal Polynomial Ring over Integers","category":"page"},{"location":"univpolynomial/#Adding-variables","page":"Universal polynomial","title":"Adding variables","text":"","category":"section"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"There are two ways to add variables to a universal polynomial ring S.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"gen(S::UniversalPolyRing, var::VarName)\ngens(S::UniversalPolyRing, vars::Vector{VarName})","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"Examples","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"julia> S = UniversalPolynomialRing(ZZ)\nUniversal Polynomial Ring over Integers\n\njulia> x = gen(S, \"x\")\nx\n\njulia> y, z = gens(S, [\"y\", \"z\"])\n(y, z)","category":"page"},{"location":"univpolynomial/#Universal-polynomial-functionality","page":"Universal polynomial","title":"Universal polynomial functionality","text":"","category":"section"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"The universal polynomial ring behaves exactly like a multivariate polynomial ring with the few differences noted above.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"The only functionality not implemented is the ability to do divrem by an ideal of polynomials.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"The universal polynomial ring is very useful for doing symbolic manipulation. However, it is important to understand that AbstractAlgebra is not a symbolic system and the performance of the universal polynomial ring will closely match that of a multivariate polynomial ring with the same number of variables.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"The disadvantage of this approach to symbolic manipulation is that some manipulations that would be offered by a symbolic system are not available, as variables are not identified by their names alone in AbstractAlgebra, as would be the case symbolically, but by objects.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"The most powerful symbolic tools we offer are the generalised evaluation functions, the multivariate coefficient functionality, the ability to change coefficient ring and to map coefficients according to a supplied function and the ability to convert a multivariate which happens to have just one variable into a dense univariate polynomial.","category":"page"},{"location":"univpolynomial/","page":"Universal polynomial","title":"Universal polynomial","text":"Further facilities may be added in future to ease symbolic manipulations.","category":"page"},{"location":"field/#Field-functionality","page":"Field functionality","title":"Field functionality","text":"","category":"section"},{"location":"field/#Abstract-types-for-rings","page":"Field functionality","title":"Abstract types for rings","text":"","category":"section"},{"location":"field/","page":"Field functionality","title":"Field functionality","text":"All field types in AbstractAlgebra belong to the Field abstract type and field elements belong to the FieldElem abstract type.","category":"page"},{"location":"field/","page":"Field functionality","title":"Field functionality","text":"As Julia types cannot belong to our FieldElem type hierarchy, we also provide the union type FieldElement which includes FieldElem in union with the Julia types Rational and AbstractFloat.","category":"page"},{"location":"field/","page":"Field functionality","title":"Field functionality","text":"Note that","category":"page"},{"location":"field/","page":"Field functionality","title":"Field functionality","text":"Field <: Ring\nFieldElem <: RingElem\nFieldElement <: RingElement","category":"page"},{"location":"field/","page":"Field functionality","title":"Field functionality","text":"Of course all Ring functionality is available for AbstractAlgebra fields and their elements.","category":"page"},{"location":"field/#Functions-for-types-and-parents-of-fields","page":"Field functionality","title":"Functions for types and parents of fields","text":"","category":"section"},{"location":"field/","page":"Field functionality","title":"Field functionality","text":"characteristic(R::MyParent)","category":"page"},{"location":"field/","page":"Field functionality","title":"Field functionality","text":"Return the characteristic of the field. If the characteristic is not known, an exception is raised.","category":"page"},{"location":"field/#Basic-functions","page":"Field functionality","title":"Basic functions","text":"","category":"section"},{"location":"field/","page":"Field functionality","title":"Field functionality","text":"is_unit(f::MyElem)","category":"page"},{"location":"field/","page":"Field functionality","title":"Field functionality","text":"Return true if the given element is invertible, i.e. nonzero in the field.","category":"page"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"submodule/#Submodules","page":"Submodules","title":"Submodules","text":"","category":"section"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"AbstractAlgebra allows the construction of submodules/subvector spaces of AbstractAlgebra modules over euclidean domains. These are given as the submodule generated by a finite list of elements in the original module.","category":"page"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"We define two submodules to be equal if they are (transitively) submodules of the same module M and their generators generate the same set of elements.","category":"page"},{"location":"submodule/#Generic-submodule-type","page":"Submodules","title":"Generic submodule type","text":"","category":"section"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"AbstractAlgebra implements a generic submodule type Generic.Submodule{T} where T is the element type of the base ring in src/generic/Submodule.jl. See src/generic/GenericTypes.jl for more details of the type definition.","category":"page"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"Elements of a generic submodule have type Generic.SubmoduleElem{T}.","category":"page"},{"location":"submodule/#Abstract-types","page":"Submodules","title":"Abstract types","text":"","category":"section"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"Submodule types belong to the abstract type FPModule{T} and their elements to FPModuleElem{T}.","category":"page"},{"location":"submodule/#Constructors","page":"Submodules","title":"Constructors","text":"","category":"section"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"sub(::FPModule{T}, ::Vector{FPModuleElem{T}}) where T <: RingElement","category":"page"},{"location":"submodule/#AbstractAlgebra.sub-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, Array{AbstractAlgebra.FPModuleElem{T}, 1}}} where T<:RingElement","page":"Submodules","title":"AbstractAlgebra.sub","text":"sub(m::FPModule{T}, gens::Vector{<:FPModuleElem{T}}) where T <: RingElement\n\nReturn the submodule of the module m generated by the given generators, given as elements of m.\n\n\n\n\n\n","category":"method"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"sub(::FPModule{T}, ::Vector{Generic.Submodule{T}}) where T <: RingElement","category":"page"},{"location":"submodule/#AbstractAlgebra.sub-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, Array{AbstractAlgebra.Generic.Submodule{T}, 1}}} where T<:RingElement","page":"Submodules","title":"AbstractAlgebra.sub","text":"sub(m::Module{T}, subs::Vector{<:Generic.Submodule{T}}) where T <: RingElement\n\nReturn the submodule S of the module m generated by the union of the given submodules of m, and a map which is the canonical injection from S to m.\n\n\n\n\n\n","category":"method"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"Note that the preimage of the canonical injection can be obtained using the preimage function described in the section on module homomorphisms. As the canonical injection is injective, this is unique.","category":"page"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"Examples","category":"page"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"julia> M = FreeModule(ZZ, 2)\nFree module of rank 2 over integers\n\njulia> m = M([ZZ(1), ZZ(2)])\n(1, 2)\n\njulia> n = M([ZZ(2), ZZ(-1)])\n(2, -1)\n\njulia> N, f = sub(M, [m, n])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 2 over integers)\n\njulia> v = N([ZZ(3), ZZ(4)])\n(3, 4)\n\njulia> v2 = f(v)\n(3, 26)\n\njulia> V = VectorSpace(QQ, 2)\nVector space of dimension 2 over rationals\n\njulia> m = V([QQ(1), QQ(2)])\n(1//1, 2//1)\n\njulia> n = V([QQ(2), QQ(-1)])\n(2//1, -1//1)\n\njulia> N, f = sub(V, [m, n])\n(Subspace over Rationals with 2 generators and no relations, Hom: subspace over Rationals with 2 generators and no relations -> vector space of dimension 2 over rationals)\n","category":"page"},{"location":"submodule/#Functionality-for-submodules","page":"Submodules","title":"Functionality for submodules","text":"","category":"section"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"In addition to the Module interface, AbstractAlgebra submodules implement the following functionality.","category":"page"},{"location":"submodule/#Basic-manipulation","page":"Submodules","title":"Basic manipulation","text":"","category":"section"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"supermodule(::Generic.Submodule{T}) where T <: RingElement","category":"page"},{"location":"submodule/#AbstractAlgebra.Generic.supermodule-Union{Tuple{AbstractAlgebra.Generic.Submodule{T}}, Tuple{T}} where T<:RingElement","page":"Submodules","title":"AbstractAlgebra.Generic.supermodule","text":"supermodule(M::Submodule{T}) where T <: RingElement\n\nReturn the module that this module is a submodule of.\n\n\n\n\n\n","category":"method"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"is_submodule(::FPModule{T}, ::FPModule{T}) where T <: RingElement","category":"page"},{"location":"submodule/#AbstractAlgebra.Generic.is_submodule-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, AbstractAlgebra.FPModule{T}}} where T<:RingElement","page":"Submodules","title":"AbstractAlgebra.Generic.is_submodule","text":"is_submodule(M::AbstractAlgebra.FPModule{T}, N::AbstractAlgebra.FPModule{T}) where T <: RingElement\n\nReturn true if N was constructed as a submodule of M. The relation is taken transitively (i.e. subsubmodules are submodules for the purposes of this relation, etc). The module M is also considered a submodule of itself for this relation.\n\n\n\n\n\n","category":"method"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"is_compatible(::FPModule{T}, ::FPModule{T}) where T <: RingElement","category":"page"},{"location":"submodule/#AbstractAlgebra.Generic.is_compatible-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, AbstractAlgebra.FPModule{T}}} where T<:RingElement","page":"Submodules","title":"AbstractAlgebra.Generic.is_compatible","text":"is_compatible(M::AbstractAlgebra.FPModule{T}, N::AbstractAlgebra.FPModule{T}) where T <: RingElement\n\nReturn true, P if the given modules are compatible, i.e. that they are (transitively) submodules of the same module, P. Otherwise return false, M.\n\n\n\n\n\n","category":"method"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"dim(N::Generic.Submodule{T}) where T <: FieldElement","category":"page"},{"location":"submodule/#AbstractAlgebra.Generic.dim-Union{Tuple{AbstractAlgebra.Generic.Submodule{T}}, Tuple{T}} where T<:FieldElement","page":"Submodules","title":"AbstractAlgebra.Generic.dim","text":"dim(N::Submodule{T}) where T <: FieldElement\n\nReturn the dimension of the given vector subspace.\n\n\n\n\n\n","category":"method"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"Examples","category":"page"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"julia> M = FreeModule(ZZ, 2)\nFree module of rank 2 over integers\n\njulia> m = M([ZZ(2), ZZ(3)])\n(2, 3)\n\njulia> n = M([ZZ(1), ZZ(4)])\n(1, 4)\n\njulia> N1, = sub(M, [m, n])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 2 over integers)\n\njulia> N2, = sub(M, [m])\n(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 2 over integers)\n\njulia> supermodule(N1) == M\ntrue\n\njulia> is_compatible(N1, N2)\n(true, Free module of rank 2 over integers)\n\njulia> is_submodule(N1, M)\nfalse\n\n\njulia> V = VectorSpace(QQ, 2)\nVector space of dimension 2 over rationals\n\njulia> m = V([QQ(2), QQ(3)])\n(2//1, 3//1)\n\njulia> N, = sub(V, [m])\n(Subspace over Rationals with 1 generator and no relations, Hom: subspace over Rationals with 1 generator and no relations -> vector space of dimension 2 over rationals)\n\njulia> dim(V)\n2\n\njulia> dim(N)\n1\n","category":"page"},{"location":"submodule/#Intersection","page":"Submodules","title":"Intersection","text":"","category":"section"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"intersect(M::FPModule{T}, N::FPModule{T}) where\nT <: RingElement","category":"page"},{"location":"submodule/#Base.intersect-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, AbstractAlgebra.FPModule{T}}} where T<:RingElement","page":"Submodules","title":"Base.intersect","text":"intersect(M::FPModule{T}, N::FPModule{T}) where T <: RingElement\n\nReturn the intersection of the modules M as a submodule of M. Note that M and N must be (constructed as) submodules (transitively) of some common module P.\n\n\n\n\n\n","category":"method"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"Examples","category":"page"},{"location":"submodule/","page":"Submodules","title":"Submodules","text":"julia> M = FreeModule(ZZ, 2)\nFree module of rank 2 over integers\n\njulia> m = M([ZZ(2), ZZ(3)])\n(2, 3)\n\njulia> n = M([ZZ(1), ZZ(4)])\n(1, 4)\n\njulia> N1 = sub(M, [m, n])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 2 over integers)\n\njulia> N2 = sub(M, [m])\n(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 2 over integers)\n\njulia> I = intersect(N1, N2)\nAny[]","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"module/#Finitely-presented-modules","page":"Finitely presented modules","title":"Finitely presented modules","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"AbstractAlgebra allows the construction of finitely presented modules (i.e. with finitely many generators and relations), starting from free modules.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"The generic code provided by AbstractAlgebra will only work for modules over euclidean domains.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Free modules can be built over both commutative and noncommutative rings. Other types of module are restricted to fields and euclidean rings.","category":"page"},{"location":"module/#Abstract-types","page":"Finitely presented modules","title":"Abstract types","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"AbstractAlgebra provides two abstract types for finitely presented modules and their elements:","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"FPModule{T} is the abstract type for finitely presented module parent","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"types","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"FPModuleElem{T} is the abstract type for finitely presented module","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"element types","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Note that the abstract types are parameterised. The type T should usually be the type of elements of the ring the module is over.","category":"page"},{"location":"module/#Module-functions","page":"Finitely presented modules","title":"Module functions","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"All finitely presented modules over a Euclidean domain implement the following functions.","category":"page"},{"location":"module/#Basic-functions","page":"Finitely presented modules","title":"Basic functions","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"zero(M::FPModule)","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"iszero(m::FPModuleElem{T}) where T <: RingElement","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Return true if the given module element is zero.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"number_of_generators(M::FPModule{T}) where T <: RingElement","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Return the number of generators of the module M in its current representation.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"gen(M::FPModule{T}, i::Int) where T <: RingElement","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Return the i-th generator (indexed from 1) of the module M.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"gens(M::FPModule{T}) where T <: RingElement","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Return a Julia array of the generators of the module M.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"rels(M::FPModule{T}) where T <: RingElement","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Return a Julia vector of all the relations between the generators of M. Each relation is given as an AbstractAlgebra row matrix.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Examples","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"julia> M = FreeModule(QQ, 2)\nVector space of dimension 2 over rationals\n\njulia> n = number_of_generators(M)\n2\n\njulia> G = gens(M)\n2-element Vector{AbstractAlgebra.Generic.FreeModuleElem{Rational{BigInt}}}:\n (1//1, 0//1)\n (0//1, 1//1)\n\njulia> R = rels(M)\nAbstractAlgebra.Generic.MatSpaceElem{Rational{BigInt}}[]\n\njulia> g1 = gen(M, 1)\n(1//1, 0//1)\n\njulia> !iszero(g1)\ntrue\n\njulia> M = FreeModule(QQ, 2)\nVector space of dimension 2 over rationals\n\njulia> z = zero(M)\n(0//1, 0//1)\n\njulia> iszero(z)\ntrue","category":"page"},{"location":"module/#Element-constructors","page":"Finitely presented modules","title":"Element constructors","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"We can construct elements of a module M by specifying linear combinations of the generators of M. This is done by passing a vector of ring elements.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"(M::FPModule{T})(v::Vector{T}) where T <: RingElement","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Construct the element of the module M corresponding to sum_i givi where gi are the generators of the module M. The resulting element will lie in the module M.","category":"page"},{"location":"module/#Coercions","page":"Finitely presented modules","title":"Coercions","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Given a module M and an element n of a module N, it is possible to coerce n into M using the notation M(n) in certain circumstances.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"In particular the element n will be automatically coerced along any canonical injection of a submodule map and along any canonical projection of a quotient map. There must be a path from N to M along such maps.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Examples","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"F = FreeModule(ZZ, 3)\n\nS1, f = sub(F, [rand(F, -10:10)])\n\nS, g = sub(F, [rand(F, -10:10)])\nQ, h = quo(F, S)\n\nm = rand(S1, -10:10)\nn = Q(m)","category":"page"},{"location":"module/#Arithmetic-operators","page":"Finitely presented modules","title":"Arithmetic operators","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Elements of a module can be added, subtracted or multiplied by an element of the ring the module is defined over and compared for equality.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"In the case of a noncommutative ring, both left and right scalar multiplication are defined.","category":"page"},{"location":"module/#Basic-manipulation","page":"Finitely presented modules","title":"Basic manipulation","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"zero(M::FPModule)","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Examples","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"julia> M = FreeModule(QQ, 2)\nVector space of dimension 2 over rationals\n\njulia> z = zero(M)\n(0//1, 0//1)","category":"page"},{"location":"module/#Element-indexing","page":"Finitely presented modules","title":"Element indexing","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Base.getindex(m::FPModuleElem{T}) where T <: RingElement","category":"page"},{"location":"module/#Base.getindex-Union{Tuple{AbstractAlgebra.FPModuleElem{T}}, Tuple{T}} where T<:RingElement","page":"Finitely presented modules","title":"Base.getindex","text":"getindex(a::Fac, b) -> Int\n\nIf b is a factor of a, the corresponding exponent is returned. Otherwise an error is thrown.\n\n\n\n\n\n","category":"method"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Examples","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"julia> F = FreeModule(ZZ, 3)\nFree module of rank 3 over integers\n\njulia> m = F(BigInt[2, -5, 4])\n(2, -5, 4)\n\njulia> m[1]\n2","category":"page"},{"location":"module/#Module-comparison","page":"Finitely presented modules","title":"Module comparison","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"==(::FPModule{T}, ::FPModule{T}) where T <: RingElement","category":"page"},{"location":"module/#Base.:==-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, AbstractAlgebra.FPModule{T}}} where T<:RingElement","page":"Finitely presented modules","title":"Base.:==","text":"==(M::FPModule{T}, N::FPModule{T}) where T <: RingElement\n\nReturn true if the modules are (constructed to be) the same module elementwise. This is not object equality and it is not isomorphism. In fact, each method of constructing modules (submodules, quotient modules, products, etc.) must extend this notion of equality to the modules they create.\n\n\n\n\n\n","category":"method"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Examples","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"julia> M = FreeModule(QQ, 2)\nVector space of dimension 2 over rationals\n\njulia> M == M\ntrue\n","category":"page"},{"location":"module/#Isomorphism","page":"Finitely presented modules","title":"Isomorphism","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"is_isomorphic(::FPModule{T}, ::FPModule{T}) where T <: RingElement","category":"page"},{"location":"module/#AbstractAlgebra.is_isomorphic-Union{Tuple{T}, Tuple{AbstractAlgebra.FPModule{T}, AbstractAlgebra.FPModule{T}}} where T<:RingElement","page":"Finitely presented modules","title":"AbstractAlgebra.is_isomorphic","text":"is_isomorphic(M::FPModule{T}, N::FPModule{T}) where T <: RingElement\n\nReturn true if the modules M and N are isomorphic.\n\n\n\n\n\n","category":"method"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"note: Note\nNote that this function relies on the Smith normal form over the base ring of the modules being able to be made unique. This is true for Euclidean domains for which divrem has a fixed choice of quotient and remainder, but it will not in general be true for Euclidean rings that are not domains.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Examples","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"julia> M = FreeModule(ZZ, 3)\nFree module of rank 3 over integers\n\njulia> m1 = rand(M, -10:10)\n(3, -1, 0)\n\njulia> m2 = rand(M, -10:10)\n(4, 4, -7)\n\njulia> S, f = sub(M, [m1, m2])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 3 over integers)\n\njulia> I, g = image(f)\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 3 over integers)\n\njulia> is_isomorphic(S, I)\ntrue\n","category":"page"},{"location":"module/#Invariant-Factor-Decomposition","page":"Finitely presented modules","title":"Invariant Factor Decomposition","text":"","category":"section"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"For modules over a euclidean domain one can take the invariant factor decomposition to determine the structure of the module. The invariant factors are unique up to multiplication by a unit, and even unique if a canonical_unit is available for the ring that canonicalises elements.","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"snf(::FPModule{T}) where T <: RingElement\ninvariant_factors(::FPModule{T}) where T <: RingElement","category":"page"},{"location":"module/#AbstractAlgebra.snf-Union{Tuple{AbstractAlgebra.FPModule{T}}, Tuple{T}} where T<:RingElement","page":"Finitely presented modules","title":"AbstractAlgebra.snf","text":"snf(m::FPModule{T}) where T <: RingElement\n\nReturn a pair M, f consisting of the invariant factor decomposition M of the module m and a module homomorphism (isomorphisms) f M to m. The module M is itself a module which can be manipulated as any other module in the system.\n\n\n\n\n\n","category":"method"},{"location":"module/#AbstractAlgebra.invariant_factors-Union{Tuple{AbstractAlgebra.FPModule{T}}, Tuple{T}} where T<:RingElement","page":"Finitely presented modules","title":"AbstractAlgebra.invariant_factors","text":"invariant_factors(m::FPModule{T}) where T <: RingElement\n\nReturn a vector of the invariant factors of the module M.\n\n\n\n\n\n","category":"method"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"Examples","category":"page"},{"location":"module/","page":"Finitely presented modules","title":"Finitely presented modules","text":"julia> M = FreeModule(ZZ, 3)\nFree module of rank 3 over integers\n\njulia> m1 = rand(M, -10:10)\n(3, -1, 0)\n\njulia> m2 = rand(M, -10:10)\n(4, 4, -7)\n\njulia> S, f = sub(M, [m1, m2])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 3 over integers)\n\njulia> Q, g = quo(M, S)\n(Quotient module over Integers with 2 generators and relations:\n[16 -21], Hom: free module of rank 3 over integers -> quotient module over Integers with 2 generators and relations:\n[16 -21])\n\njulia> I, f = snf(Q)\n(Invariant factor decomposed module over Integers with invariant factors BigInt[0], Hom: invariant factor decomposed module over Integers with invariant factors BigInt[0] -> quotient module over Integers with 2 generators and relations:\n[16 -21])\n\njulia> invs = invariant_factors(Q)\n1-element Vector{BigInt}:\n 0\n","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"CurrentModule = AbstractAlgebra\nDocTestSetup = quote\n using AbstractAlgebra\nend","category":"page"},{"location":"direct_sum/#Direct-Sums","page":"Direct Sums","title":"Direct Sums","text":"","category":"section"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"AbstractAlgebra allows the construction of the external direct sum of any nonempty vector of finitely presented modules.","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Note that external direct sums are considered equal iff they are the same object.","category":"page"},{"location":"direct_sum/#Generic-direct-sum-type","page":"Direct Sums","title":"Generic direct sum type","text":"","category":"section"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"AbstractAlgebra provides a generic direct sum type Generic.DirectSumModule{T} where T is the element type of the base ring. The implementation is in src/generic/DirectSum.jl","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Elements of direct sum modules have type Generic.DirectSumModuleElem{T}.","category":"page"},{"location":"direct_sum/#Abstract-types","page":"Direct Sums","title":"Abstract types","text":"","category":"section"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Direct sum module types belong to the abstract type FPModule{T} and their elements to FPModuleElem{T}.","category":"page"},{"location":"direct_sum/#Constructors","page":"Direct Sums","title":"Constructors","text":"","category":"section"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"direct_sum","category":"page"},{"location":"direct_sum/#AbstractAlgebra.direct_sum","page":"Direct Sums","title":"AbstractAlgebra.direct_sum","text":"direct_sum(m::Vector{<:FPModule{T}}) where T <: RingElement\ndirect_sum(vals::FPModule{T}...) where T <: RingElement\n\nReturn a tuple M f g consisting of M the direct sum of the modules m (supplied as a vector of modules), a vector f of the injections of the mi into M and a vector g of the projections from M onto the mi.\n\n\n\n\n\n","category":"function"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Examples","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"julia> F = FreeModule(ZZ, 5)\nFree module of rank 5 over integers\n\njulia> m1 = F(BigInt[4, 7, 8, 2, 6])\n(4, 7, 8, 2, 6)\n\njulia> m2 = F(BigInt[9, 7, -2, 2, -4])\n(9, 7, -2, 2, -4)\n\njulia> S1, f1 = sub(F, [m1, m2])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)\n\njulia> m1 = F(BigInt[3, 1, 7, 7, -7])\n(3, 1, 7, 7, -7)\n\njulia> m2 = F(BigInt[-8, 6, 10, -1, 1])\n(-8, 6, 10, -1, 1)\n\njulia> S2, f2 = sub(F, [m1, m2])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)\n\njulia> m1 = F(BigInt[2, 4, 2, -3, -10])\n(2, 4, 2, -3, -10)\n\njulia> m2 = F(BigInt[5, 7, -6, 9, -5])\n(5, 7, -6, 9, -5)\n\njulia> S3, f3 = sub(F, [m1, m2])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)\n\njulia> D, f = direct_sum(S1, S2, S3)\n(DirectSumModule over integers, AbstractAlgebra.Generic.ModuleHomomorphism{BigInt}[Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers, Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers, Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers], AbstractAlgebra.Generic.ModuleHomomorphism{BigInt}[Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations, Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations, Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations])","category":"page"},{"location":"direct_sum/#Functionality-for-direct-sums","page":"Direct Sums","title":"Functionality for direct sums","text":"","category":"section"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"In addition to the Module interface, AbstractAlgebra direct sums implement the following functionality.","category":"page"},{"location":"direct_sum/#Basic-manipulation","page":"Direct Sums","title":"Basic manipulation","text":"","category":"section"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"summands(::Generic.DirectSumModule{T}) where T <: RingElement","category":"page"},{"location":"direct_sum/#AbstractAlgebra.Generic.summands-Union{Tuple{AbstractAlgebra.Generic.DirectSumModule{T}}, Tuple{T}} where T<:RingElement","page":"Direct Sums","title":"AbstractAlgebra.Generic.summands","text":"summands(M::DirectSumModule{T}) where T <: RingElement\n\nReturn the modules that this module is a direct sum of.\n\n\n\n\n\n","category":"method"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Examples","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"julia> F = FreeModule(ZZ, 5)\nFree module of rank 5 over integers\n\njulia> m1 = F(BigInt[4, 7, 8, 2, 6])\n(4, 7, 8, 2, 6)\n\njulia> m2 = F(BigInt[9, 7, -2, 2, -4])\n(9, 7, -2, 2, -4)\n\njulia> S1, f1 = sub(F, [m1, m2])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)\n\njulia> m1 = F(BigInt[3, 1, 7, 7, -7])\n(3, 1, 7, 7, -7)\n\njulia> m2 = F(BigInt[-8, 6, 10, -1, 1])\n(-8, 6, 10, -1, 1)\n\njulia> S2, f2 = sub(F, [m1, m2])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)\n\njulia> m1 = F(BigInt[2, 4, 2, -3, -10])\n(2, 4, 2, -3, -10)\n\njulia> m2 = F(BigInt[5, 7, -6, 9, -5])\n(5, 7, -6, 9, -5)\n\njulia> S3, f3 = sub(F, [m1, m2])\n(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 5 over integers)\n\njulia> D, f = direct_sum(S1, S2, S3)\n(DirectSumModule over integers, AbstractAlgebra.Generic.ModuleHomomorphism{BigInt}[Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers, Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers, Hom: submodule over Integers with 2 generators and no relations -> DirectSumModule over integers], AbstractAlgebra.Generic.ModuleHomomorphism{BigInt}[Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations, Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations, Hom: DirectSumModule over integers -> submodule over Integers with 2 generators and no relations])\n\njulia> summands(D)\n3-element Vector{AbstractAlgebra.Generic.Submodule{BigInt}}:\n Submodule over Integers with 2 generators and no relations\n Submodule over Integers with 2 generators and no relations\n Submodule over Integers with 2 generators and no relations","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":" (D::DirectSumModule{T}(::Vector{<:FPModuleElem{T}}) where T <: RingElement","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Given a vector (or 1-dim array) of module elements, where the i-th entry has to be an element of the i-summand of D, create the corresponding element in D.","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Examples","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"julia> N = FreeModule(QQ, 1);\n\njulia> M = FreeModule(QQ, 2);\n\njulia> D, _ = direct_sum(M, N, M);\n\njulia> D([gen(M, 1), gen(N, 1), gen(M, 2)])\n(1//1, 0//1, 1//1, 0//1, 1//1)","category":"page"},{"location":"direct_sum/#Special-Homomorphisms","page":"Direct Sums","title":"Special Homomorphisms","text":"","category":"section"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Due to the special structure as direct sums, homomorphisms can be created by specifying homomorphisms for all summands. In case of the codmain being a direct sum as well, any homomorphism may be thought of as a matrix containing maps from the i-th source summand to the j-th target module:","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"ModuleHomomorphism(D::DirectSumModule{T}, S::DirectSumModule{T}, m::Matrix{Any}) where T <: RingElement","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Given a matrix m such that the (ij)-th entry is either 0 (Int(0)) or a ModuleHomomorphism from the i-th summand of D to the j-th summand of S, construct the corresponding homomorphism.","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"ModuleHomomorphism(D::DirectSumModule{T}, S::FPModuleElem{T}, m::Vector{ModuleHomomorphism})","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Given an array a of ModuleHomomorphism such that a_i, the i-th entry of a is a ModuleHomomorphism from the i-th summand of D into S, construct the direct sum of the components.","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Given a matrix m such that the (ij)-th entry is either 0 (Int(0)) or a ModuleHomomorphism from the i-th summand of D to the j-th summand of S, construct the corresponding homomorphism.","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"Examples","category":"page"},{"location":"direct_sum/","page":"Direct Sums","title":"Direct Sums","text":"julia> N = FreeModule(QQ, 2);\n\njulia> D, _ = direct_sum(N, N);\n\njulia> p = ModuleHomomorphism(N, N, [3,4] .* basis(N));\n\njulia> q = ModuleHomomorphism(N, N, [5,7] .* basis(N));\n\njulia> phi = ModuleHomomorphism(D, D, [p 0; 0 q])\nModule homomorphism\n from DirectSumModule over rationals\n to DirectSumModule over rationals\n\njulia> r = ModuleHomomorphism(N, D, [2,3] .* gens(D)[1:2])\nModule homomorphism\n from vector space of dimension 2 over rationals\n to DirectSumModule over rationals\n\njulia> psi = ModuleHomomorphism(D, D, [r, r])\nModule homomorphism\n from DirectSumModule over rationals\n to DirectSumModule over rationals","category":"page"}] +} diff --git a/v0.37.6/series/index.html b/v0.37.6/series/index.html new file mode 100644 index 0000000000..2553570fa9 --- /dev/null +++ b/v0.37.6/series/index.html @@ -0,0 +1,302 @@ + +Power series · AbstractAlgebra.jl

Power series

AbstractAlgebra.jl allows the creation of capped relative and absolute power series over any computable commutative ring $R$.

Capped relative power series are power series of the form $a_jx^j + a_{j+1}x^{j+1} + \cdots + a_{k-1}x^{k-1} + O(x^k)$ where $a_j \in R$ and the relative precision $k - j$ is at most equal to some specified precision $n$.

Capped absolute power series are power series of the form $a_jx^j + a_{j+1}x^{j+1} + \cdots + a_{n-1}x^{n-1} + O(x^n)$ where $j \geq 0$, $a_j \in R$ and the precision $n$ is fixed.

There are two implementations of relative series: relative power series, implemented in src/RelSeries.jl for which $j > 0$ in the above description, and Laurent series where $j$ can be negative, implemented in src/Laurent.jl. Note that there are two implementations for Laurent series, one over rings and one over fields, though in practice most of the implementation uses the same code in both cases.

There is a single implementation of absolute series: absolute power series, implemented in src/AbsSeries.jl.

Generic power series types

AbstractAlgebra.jl provides generic series types implemented in src/generic/AbsSeries.jl, src/generic/RelSeries.jl and src/generic/LaurentSeries.jl which implement the Series interface.

These generic series have types Generic.RelSeries{T}, Generic.AbsSeries{T}, Generic.LaurentSeriesRingElem{T} and Generic.LaurentSeriesFieldElem{T}. See the file src/generic/GenericTypes.jl for details.

The parent objects have types Generic.AbsPowerSeriesRing{T} and Generic.RelPowerSeriesRing{T} and Generic.LaurentSeriesRing{T} respectively.

The default precision, string representation of the variable and base ring $R$ of a generic power series are stored in its parent object.

Abstract types

Relative power series elements belong to the abstract type RelPowerSeriesRingElem.

Laurent series elements belong directly to either RingElem or FieldElem since it is more useful to be able to distinguish whether they belong to a ring or field than it is to distinguish that they are relative series.

Absolute power series elements belong to AbsPowerSeriesRingElem.

The parent types for relative and absolute power series, Generic.RelPowerSeriesRing{T} and Generic.AbsPowerSeriesRing{T} respectively, belong to SeriesRing{T}.

The parent types of Laurent series belong directly to Ring and Field respectively.

Series ring constructors

In order to construct series in AbstractAlgebra.jl, one must first construct the ring itself. This is accomplished with any of the following constructors.

power_series_ring(R::Ring, prec_max::Int, s::VarName; cached::Bool = true, model=:capped_relative)
laurent_series_ring(R::Ring, prec_max::Int, s::VarName; cached::Bool = true)
laurent_series_ring(R::Field, prec_max::Int, s::VarName; cached::Bool = true)

Given a base ring R, a maximum precision (relative or absolute, depending on the model) and a string s specifying how the generator (variable) should be printed, return a tuple S, x representing the series ring and its generator.

By default, S will depend only on S, x and the maximum precision and will be cached. Setting the optional argument cached to false will prevent this.

In the case of power series, the optional argument model can be set to either :capped_absolute or capped_relative, depending on which power series model is required.

It is also possible to construct absolute and relative power series with a default variable. These are lightweight constructors and should be used in generic algorithms wherever possible when creating series rings where the symbol does not matter.

AbsPowerSeriesRing(R::Ring, prec::Int)
+RelPowerSeriesRing(R::Ring, prec::Int)

Return the absolute or relative power series ring over the given base ring $R$ and with precision cap given by prec. Note that a tuple is not returned, only the power series ring itself, not a generator.

Here are some examples of constructing various kinds of series rings and coercing various elements into those rings.

Examples

julia> R, x = power_series_ring(ZZ, 10, "x")
+(Univariate power series ring over integers, x + O(x^11))
+
+julia> S, y = power_series_ring(ZZ, 10, "y"; model=:capped_absolute)
+(Univariate power series ring over integers, y + O(y^10))
+
+julia> T, z = laurent_series_ring(ZZ, 10, "z")
+(Laurent series ring in z over integers, z + O(z^11))
+
+julia> U, w = laurent_series_field(QQ, 10, "w")
+(Laurent series field in w over rationals, w + O(w^11))
+
+julia> f = R()
+O(x^10)
+
+julia> g = S(123)
+123 + O(y^10)
+
+julia> h = U(BigInt(1234))
+1234 + O(w^10)
+
+julia> k = T(z + 1)
+1 + z + O(z^10)
+
+julia> V = AbsPowerSeriesRing(ZZ, 10)
+Univariate power series ring in x with precision 10
+  over integers

Power series constructors

Series can be constructed using arithmetic operators using the generator of the series. Also see the big-oh notation below for specifying the precision.

All of the standard ring constructors can also be used to construct power series.

(R::SeriesRing)() # constructs zero
+(R::SeriesRing)(c::Integer)
+(R::SeriesRing)(c::elem_type(R))
+(R::SeriesRing{T})(a::T) where T <: RingElement

In addition, the following constructors that are specific to power series are provided. They take an array of coefficients, a length, precision and valuation. Coefficients will be coerced into the coefficient ring if they are not already in that ring.

For relative series we have:

(S::SeriesRing{T})(A::Vector{T}, len::Int, prec::Int, val::Int) where T <: RingElem
+(S::SeriesRing{T})(A::Vector{U}, len::Int, prec::Int, val::Int) where {T <: RingElem, U <: RingElem}
+(S::SeriesRing{T})(A::Vector{U}, len::Int, prec::Int, val::Int) where {T <: RingElem, U <: Integer}

And for absolute series:

(S::SeriesRing{T})(A::Vector{T}, len::Int, prec::Int) where T <: RingElem

It is also possible to create series directly without having to create the corresponding series ring.

abs_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T
+rel_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, val::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T
+laurent_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, val::Int, scale::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T

Examples

julia> S, x = power_series_ring(QQ, 10, "x"; model=:capped_absolute)
+(Univariate power series ring over rationals, x + O(x^10))
+
+julia> f = S(Rational{BigInt}[0, 2, 3, 1], 4, 6)
+2*x + 3*x^2 + x^3 + O(x^6)
+
+julia> f = abs_series(ZZ, [1, 2, 3], 3, 5, "y")
+1 + 2*y + 3*y^2 + O(y^5)
+
+julia> g = rel_series(ZZ, [1, 2, 3], 3, 7, 4)
+x^4 + 2*x^5 + 3*x^6 + O(x^7)
+
+julia> k = abs_series(ZZ, [1, 2, 3], 1, 6, cached=false)
+1 + O(x^6)
+
+julia> p = rel_series(ZZ, BigInt[], 0, 3, 1)
+O(x^3)
+
+julia> q = abs_series(ZZ, [], 0, 6)
+O(x^6)
+
+julia> s = abs_series(ZZ, [1, 2, 3], 3, 5; max_precision=10)
+1 + 2*x + 3*x^2 + O(x^5)
+
+julia> s = laurent_series(ZZ, [1, 2, 3], 3, 5, 0, 2; max_precision=10)
+1 + 2*x^2 + 3*x^4 + O(x^5)

Big-oh notation

Series elements can be given a precision using the big-oh notation. This is provided by a function of the following form, (or something equivalent for Laurent series):

O(x::SeriesElem)

Examples

julia> R, x = power_series_ring(ZZ, 10, "x")
+(Univariate power series ring over integers, x + O(x^11))
+
+julia> S, y = laurent_series_ring(ZZ, 10, "y")
+(Laurent series ring in y over integers, y + O(y^11))
+
+julia> f = 1 + 2x + O(x^5)
+1 + 2*x + O(x^5)
+
+julia> g = 2y + 7y^2 + O(y^7)
+2*y + 7*y^2 + O(y^7)

What is happening here in practice is that O(x^n) is creating the series 0 + O(x^n) and the rules for addition of series dictate that if this is added to a series of greater precision, then the lower of the two precisions must be used.

Of course it may be that the precision of the series that O(x^n) is added to is already lower than n, in which case adding O(x^n) has no effect. This is the case if the default precision is too low, since x on its own has the default precision.

Power series models

Capped relative power series have their maximum relative precision capped at some value prec_max. This means that if the leading term of a nonzero power series element is $c_ax^a$ and the precision is $b$ then the power series is of the form $c_ax^a + c_{a+1}x^{a+1} + \ldots + O(x^{a + b})$.

The zero power series is simply taken to be $0 + O(x^b)$.

The capped relative model has the advantage that power series are stable multiplicatively. In other words, for nonzero power series $f$ and $g$ we have that divexact(f*g), g) == f.

However, capped relative power series are not additively stable, i.e. we do not always have $(f + g) - g = f$.

Similar comments apply to Laurent series.

On the other hand, capped absolute power series have their absolute precision capped. This means that if the leading term of a nonzero power series element is $c_ax^a$ and the precision is $b$ then the power series is of the form $c_ax^a + c_{a+1}x^{a+1} + \ldots + O(x^b)$.

Capped absolute series are additively stable, but not necessarily multiplicatively stable.

For all models, the maximum precision is also used as a default precision in the case of coercing coefficients into the ring and for any computation where the result could mathematically be given to infinite precision.

In all models we say that two power series are equal if they agree up to the minimum absolute precision of the two power series.

Thus, for example, $x^5 + O(x^{10}) == 0 + O(x^5)$, since the minimum absolute precision is $5$.

During computations, it is possible for power series to lose relative precision due to cancellation. For example if $f = x^3 + x^5 + O(x^8)$ and $g = x^3 + x^6 + O(x^8)$ then $f - g = x^5 - x^6 + O(x^8)$ which now has relative precision $3$ instead of relative precision $5$.

Amongst other things, this means that equality is not transitive. For example $x^6 + O(x^{11}) == 0 + O(x^5)$ and $x^7 + O(x^{12}) == 0 + O(x^5)$ but $x^6 + O(x^{11}) \neq x^7 + O(x^{12})$.

Sometimes it is necessary to compare power series not just for arithmetic equality, as above, but to see if they have precisely the same precision and terms. For this purpose we introduce the isequal function.

For example, if $f = x^2 + O(x^7)$ and $g = x^2 + O(x^8)$ and $h = 0 + O(x^2)$ then $f == g$, $f == h$ and $g == h$, but isequal(f, g), isequal(f, h) and isequal(g, h) would all return false. However, if $k = x^2 + O(x^7)$ then isequal(f, k) would return true.

There are further difficulties if we construct polynomial over power series. For example, consider the polynomial in $y$ over the power series ring in $x$ over the rationals. Normalisation of such polynomials is problematic. For instance, what is the leading coefficient of $(0 + O(x^{10}))y + (1 + O(x^{10}))$?

If one takes it to be $(0 + O(x^{10}))$ then some functions may not terminate due to the fact that algorithms may require the degree of polynomials to decrease with each iteration. Instead, the degree may remain constant and simply accumulate leading terms which are arithmetically zero but not identically zero.

On the other hand, when constructing power series over other power series, if we simply throw away terms which are arithmetically equal to zero, our computations may have different output depending on the order in which the power series are added!

One should be aware of these difficulties when working with power series. Power series, as represented on a computer, simply don't satisfy the axioms of a ring. They must be used with care in order to approximate operations in a mathematical power series ring.

Simply increasing the precision will not necessarily give a "more correct" answer and some computations may not even terminate due to the presence of arithmetic zeroes!

An absolute power series ring over a ring $R$ with precision $p$ behaves very much like the quotient $R[x]/(x^p)$ of the polynomial ring over $R$. Therefore one can often treat absolute power series rings as though they were rings. However, this depends on all series being given a precision equal to the specified maximum precision and not a lower precision.

Functions for types and parents of series rings

base_ring(R::SeriesRing)
+base_ring(a::SeriesElem)

Return the coefficient ring of the given series ring or series.

parent(a::SeriesElem)

Return the parent of the given series.

characteristic(R::SeriesRing)

Return the characteristic of the given series ring. If the characteristic is not known, an exception is raised.

Series functions

Unless otherwise noted, the functions below are available for all series models, including Laurent series. We denote this by using the abstract type RelPowerSeriesRingElem, even though absolute series and Laurent series types do not belong to this abstract type.

Basic functionality

Series implement the Ring Interface

zero(R::SeriesRing)
+one(R::SeriesRing)
+iszero(a::SeriesElem)
+isone(a::SeriesElem)
divexact(a::T, b::T) where T <: SeriesElem
+inv(a::SeriesElem) 

Series also implement the Series Interface, the most important basic functions being the following.

var(S::SeriesRing)

Return a symbol for the variable of the given series ring.

max_precision(S::SeriesRing)

Return the precision cap of the given series ring.

precision(f::SeriesElem)
+valuation(f::SeriesElem)
gen(R::SeriesRing)

The following functions are also provided for all series.

coeff(a::SeriesElem, n::Int)

Return the degree $n$ coefficient of the given power series. Note coefficients are numbered from $n = 0$ for the constant coefficient. If $n$ exceeds the current precision of the power series, the function returns a zero coefficient.

For power series types, $n$ must be non-negative. Laurent series do not have this restriction.

AbstractAlgebra.modulusMethod
modulus(a::SeriesElem{T}) where {T <: ResElem}

Return the modulus of the coefficients of the given power series.

source
AbstractAlgebra.is_genMethod
is_gen(a::RelPowerSeriesRingElem)

Return true if the given power series is arithmetically equal to the generator of its power series ring to its current precision, otherwise return false.

source

Examples

julia> S, x = power_series_ring(ZZ, 10, "x")
+(Univariate power series ring over integers, x + O(x^11))
+
+julia> f = 1 + 3x + x^3 + O(x^10)
+1 + 3*x + x^3 + O(x^10)
+
+julia> g = 1 + 2x + x^2 + O(x^10)
+1 + 2*x + x^2 + O(x^10)
+
+julia> h = zero(S)
+O(x^10)
+
+julia> k = one(S)
+1 + O(x^10)
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> n = pol_length(f)
+4
+
+julia> c = polcoeff(f, 3)
+1
+
+julia> U = base_ring(S)
+Integers
+
+julia> v = var(S)
+:x
+
+julia> max_precision(S) == 10
+true
+
+julia> T = parent(x + 1)
+Univariate power series ring in x with precision 10
+  over integers
+
+julia> g == deepcopy(g)
+true
+
+julia> t = divexact(2g, 2)
+1 + 2*x + x^2 + O(x^10)
+
+julia> p = precision(f)
+10
+
+julia> R, t = power_series_ring(QQ, 10, "t")
+(Univariate power series ring over rationals, t + O(t^11))
+
+julia> S, x = power_series_ring(R, 30, "x")
+(Univariate power series ring over univariate power series ring, x + O(x^31))
+
+julia> a = O(x^4)
+O(x^4)
+
+julia> b = (t + 3)*x + (t^2 + 1)*x^2 + O(x^4)
+(3 + t + O(t^10))*x + (1 + t^2 + O(t^10))*x^2 + O(x^4)
+
+julia> k = is_gen(gen(R))
+true
+
+julia> m = is_unit(-1 + x + 2x^2)
+true
+
+julia> n = valuation(a)
+4
+
+julia> p = valuation(b)
+1
+
+julia> c = coeff(b, 2)
+1 + t^2 + O(t^10)
+
+julia> S, x = power_series_ring(ZZ, 10, "x")
+(Univariate power series ring over integers, x + O(x^11))
+
+julia> f = 1 + 3x + x^3 + O(x^5)
+1 + 3*x + x^3 + O(x^5)
+
+julia> g = S(BigInt[1, 2, 0, 1, 0, 0, 0], 4, 10, 3);
+
+julia> set_length!(g, 3)
+x^3 + 2*x^4 + O(x^10)
+
+julia> g = setcoeff!(g, 2, BigInt(11))
+x^3 + 2*x^4 + 11*x^5 + O(x^10)
+
+julia> fit!(g, 8)
+
+julia> g = setcoeff!(g, 7, BigInt(4))
+x^3 + 2*x^4 + 11*x^5 + O(x^10)

Change base ring

AbstractAlgebra.map_coefficientsMethod
map_coefficients(f, p::SeriesElem{<: RingElement}; cached::Bool=true, parent::PolyRing)

Transform the series p by applying f on each non-zero coefficient.

If the optional parent keyword is provided, the polynomial will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.

source
AbstractAlgebra.change_base_ringMethod
change_base_ring(R::Ring, p::SeriesElem{<: RingElement}; parent::PolyRing)

Return the series obtained by coercing the non-zero coefficients of p into R.

If the optional parent keyword is provided, the series will be an element of parent. The caching of the parent object can be controlled via the cached keyword argument.

source

Examples

julia> R, x = power_series_ring(ZZ, 10, "x")
+(Univariate power series ring over integers, x + O(x^11))
+
+julia> f = 4*x^6 + x^7 + 9*x^8 + 16*x^9 + 25*x^10 + O(x^11)
+4*x^6 + x^7 + 9*x^8 + 16*x^9 + 25*x^10 + O(x^11)
+
+julia> map_coefficients(AbstractAlgebra.sqrt, f)
+2*x^6 + x^7 + 3*x^8 + 4*x^9 + 5*x^10 + O(x^11)
+
+julia> change_base_ring(QQ, f)
+4*x^6 + x^7 + 9*x^8 + 16*x^9 + 25*x^10 + O(x^11)

Shifting

AbstractAlgebra.shift_leftMethod
shift_left(x::RelPowerSeriesRingElem{T}, n::Int) where T <: RingElement

Return the power series $x$ shifted left by $n$ terms, i.e. multiplied by $x^n$.

source
AbstractAlgebra.shift_rightMethod
shift_right(x::RelPowerSeriesRingElem{T}, n::Int) where T <: RingElement

Return the power series $x$ shifted right by $n$ terms, i.e. divided by $x^n$.

source

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S, x = power_series_ring(R, 30, "x")
+(Univariate power series ring over univariate polynomial ring, x + O(x^31))
+
+julia> a = 2x + x^3
+2*x + x^3 + O(x^31)
+
+julia> b = O(x^4)
+O(x^4)
+
+julia> c = 1 + x + 2x^2 + O(x^5)
+1 + x + 2*x^2 + O(x^5)
+
+julia> d = 2x + x^3 + O(x^4)
+2*x + x^3 + O(x^4)
+
+julia> f = shift_left(a, 2)
+2*x^3 + x^5 + O(x^33)
+
+julia> g = shift_left(b, 2)
+O(x^6)
+
+julia> h = shift_right(c, 1)
+1 + 2*x + O(x^4)
+
+julia> k = shift_right(d, 3)
+1 + O(x^1)
+

Truncation

Base.truncateMethod
truncate(a::RelPowerSeriesRingElem{T}, n::Int) where T <: RingElement

Return $a$ truncated to (absolute) precision $n$.

source

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S, x = power_series_ring(R, 30, "x")
+(Univariate power series ring over univariate polynomial ring, x + O(x^31))
+
+julia> a = 2x + x^3
+2*x + x^3 + O(x^31)
+
+julia> b = O(x^4)
+O(x^4)
+
+julia> c = 1 + x + 2x^2 + O(x^5)
+1 + x + 2*x^2 + O(x^5)
+
+julia> d = 2x + x^3 + O(x^4)
+2*x + x^3 + O(x^4)
+
+julia> f = truncate(a, 3)
+2*x + O(x^3)
+
+julia> g = truncate(b, 2)
+O(x^2)
+
+julia> h = truncate(c, 7)
+1 + x + 2*x^2 + O(x^5)
+
+julia> k = truncate(d, 5)
+2*x + x^3 + O(x^4)
+

Division

Base.invMethod
Base.inv(a::RelPowerSeriesRingElem)

Return the inverse of the power series $a$, i.e. $1/a$.

source

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S, x = power_series_ring(R, 30, "x")
+(Univariate power series ring over univariate polynomial ring, x + O(x^31))
+
+julia> a = 1 + x + 2x^2 + O(x^5)
+1 + x + 2*x^2 + O(x^5)
+
+julia> b = S(-1)
+-1 + O(x^30)
+
+julia> c = inv(a)
+1 - x - x^2 + 3*x^3 - x^4 + O(x^5)
+
+julia> d = inv(b)
+-1 + O(x^30)
+

Composition

AbstractAlgebra.composeMethod
compose(a::RelPowerSeriesRingElem, b::RelPowerSeriesRingElem)

Compose the series $a$ with the series $b$ and return the result, i.e. return $a\circ b$. The two series do not need to be in the same ring, however the series $b$ must have positive valuation or an exception is raised.

source

Note that subst can be used instead of compose, however the provided functionality is the same. General series substitution is not well-defined.

Derivative and integral

AbstractAlgebra.derivativeMethod
derivative(f::AbsPowerSeriesRingElem{T})

Return the derivative of the power series $f$.

source
derivative(f::RelPowerSeriesRingElem{T})

Return the derivative of the power series $f$.

julia> R, x = power_series_ring(QQ, 10, "x")
+(Univariate power series ring in x over Rationals, x + O(x^11))
+
+julia> f = 2 + x + 3x^3
+2 + x + 3*x^3 + O(x^10)
+
+julia> derivative(f)
+1 + 9*x^2 + O(x^9)
source
derivative(f::MPolyRingElem{T}, j::Int) where {T <: RingElement}

Return the partial derivative of f with respect to $j$-th variable of the polynomial ring.

source
derivative(f::MPolyRingElem{T}, x::MPolyRingElem{T}) where T <: RingElement

Return the partial derivative of f with respect to x. The value x must be a generator of the polynomial ring of f.

source
derivative(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the derivative of the given Puiseux series $a$.

source
AbstractAlgebra.integralMethod
integral(f::AbsPowerSeriesRingElem{T})

Return the integral of the power series $f$.

source
integral(f::RelPowerSeriesRingElem{T})

Return the integral of the power series $f$.

julia> R, x = power_series_ring(QQ, 10, "x")
+(Univariate power series ring in x over Rationals, x + O(x^11))
+
+julia> f = 2 + x + 3x^3
+2 + x + 3*x^3 + O(x^10)
+
+julia> integral(f)
+2*x + 1//2*x^2 + 3//4*x^4 + O(x^11)
source
integral(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the integral of the given Puiseux series $a$.

source

Special functions

Base.logMethod
log(a::SeriesElem{T}) where T <: FieldElement

Return the logarithm of the power series $a$.

source
log(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the logarithm of the given Puiseux series $a$.

source
Base.expMethod
exp(a::AbsPowerSeriesRingElem)

Return the exponential of the power series $a$.

source
exp(a::RelPowerSeriesRingElem)

Return the exponential of the power series $a$.

source
exp(a::Generic.LaurentSeriesElem)

Return the exponential of the power series $a$.

source
exp(a::Generic.PuiseuxSeriesElem{T}) where T <: RingElement

Return the exponential of the given Puiseux series $a$.

source
Base.sqrtMethod
sqrt(a::RelPowerSeriesRingElem)

Return the square root of the power series $a$. By default the function raises an exception if the input is not a square. If check=false this check is omitted.

source

Examples

julia> R, t = polynomial_ring(QQ, "t")
+(Univariate polynomial ring in t over rationals, t)
+
+julia> S, x = power_series_ring(R, 30, "x")
+(Univariate power series ring over univariate polynomial ring, x + O(x^31))
+
+julia> T, z = power_series_ring(QQ, 30, "z")
+(Univariate power series ring over rationals, z + O(z^31))
+
+julia> a = 1 + z + 3z^2 + O(z^5)
+1 + z + 3*z^2 + O(z^5)
+
+julia> b = z + 2z^2 + 5z^3 + O(z^5)
+z + 2*z^2 + 5*z^3 + O(z^5)
+
+julia> c = exp(x + O(x^40))
+1 + x + 1//2*x^2 + 1//6*x^3 + 1//24*x^4 + 1//120*x^5 + 1//720*x^6 + 1//5040*x^7 + 1//40320*x^8 + 1//362880*x^9 + 1//3628800*x^10 + 1//39916800*x^11 + 1//479001600*x^12 + 1//6227020800*x^13 + 1//87178291200*x^14 + 1//1307674368000*x^15 + 1//20922789888000*x^16 + 1//355687428096000*x^17 + 1//6402373705728000*x^18 + 1//121645100408832000*x^19 + 1//2432902008176640000*x^20 + 1//51090942171709440000*x^21 + 1//1124000727777607680000*x^22 + 1//25852016738884976640000*x^23 + 1//620448401733239439360000*x^24 + 1//15511210043330985984000000*x^25 + 1//403291461126605635584000000*x^26 + 1//10888869450418352160768000000*x^27 + 1//304888344611713860501504000000*x^28 + 1//8841761993739701954543616000000*x^29 + 1//265252859812191058636308480000000*x^30 + O(x^31)
+
+julia> d = divexact(x, exp(x + O(x^40)) - 1)
+1 - 1//2*x + 1//12*x^2 - 1//720*x^4 + 1//30240*x^6 - 1//1209600*x^8 + 1//47900160*x^10 - 691//1307674368000*x^12 + 1//74724249600*x^14 - 3617//10670622842880000*x^16 + 43867//5109094217170944000*x^18 - 174611//802857662698291200000*x^20 + 77683//14101100039391805440000*x^22 - 236364091//1693824136731743669452800000*x^24 + 657931//186134520519971831808000000*x^26 - 3392780147//37893265687455865519472640000000*x^28 + O(x^29)
+
+julia> f = exp(b)
+1 + z + 5//2*z^2 + 43//6*z^3 + 193//24*z^4 + O(z^5)
+
+julia> log(exp(b)) == b
+true
+
+julia> h = sqrt(a)
+1 + 1//2*z + 11//8*z^2 - 11//16*z^3 - 77//128*z^4 + O(z^5)
+

Random generation

Random series can be constructed using the rand function. A range of possible valuations is provided. The maximum precision of the ring is used as a bound on the precision. Other parameters are used to construct random coefficients.

rand(R::SeriesRing, val_range::AbstractUnitRange{Int}, v...)

Examples

julia> R, x = power_series_ring(ZZ, 10, "x")
+(Univariate power series ring over integers, x + O(x^11))
+
+julia> f = rand(R, 3:5, -10:10)
+3*x^4 - x^5 + 4*x^7 + 4*x^8 - 7*x^9 + 2*x^10 + 4*x^11 - x^12 - 4*x^13 + O(x^14)
diff --git a/v0.37.6/series_interface/index.html b/v0.37.6/series_interface/index.html new file mode 100644 index 0000000000..ad930c2f5c --- /dev/null +++ b/v0.37.6/series_interface/index.html @@ -0,0 +1,18 @@ + +Series Ring Interface · AbstractAlgebra.jl

Series Ring Interface

Univariate power series rings are supported in AbstractAlgebra in a variety of different forms, including absolute and relative precision models and Laurent series.

In addition to the standard Ring interface, numerous additional functions are required to be present for power series rings.

Types and parents

AbstractAlgebra provides two abstract types for power series rings and their elements:

  • SeriesRing{T} is the abstract type for all power series ring parent types
  • SeriesElem{T} is the abstract type for all power series types

We have that SeriesRing{T} <: Ring and SeriesElem{T} <: RingElem.

Note that both abstract types are parameterised. The type T should usually be the type of elements of the coefficient ring of the power series ring. For example, in the case of $\mathbb{Z}[[x]]$ the type T would be the type of an integer, e.g. BigInt.

Within the SeriesElem{T} abstract type is the abstract type RelPowerSeriesRingElem{T} for relative power series, and AbsPowerSeriesRingElem{T} for absolute power series.

Relative series are typically stored with a valuation and a series that is either zero or that has nonzero constant term. Absolute series are stored starting from the constant term, even if it is zero.

If the parent object for a relative series ring over the bignum integers has type MySeriesRing and series in that ring have type MySeries then one would have:

  • MySeriesRing <: SeriesRing{BigInt}
  • MySeries <: RelPowerSeriesRingElem{BigInt}

Series rings should be made unique on the system by caching parent objects (unless an optional cache parameter is set to false). Series rings should at least be distinguished based on their base (coefficient) ring. But if they have the same base ring and symbol (for their variable/generator) and same default precision, they should certainly have the same parent object.

See src/generic/GenericTypes.jl for an example of how to implement such a cache (which usually makes use of a dictionary).

Required functionality for series

In addition to the required functionality for the Ring interface the Series Ring interface has the following required functions.

We suppose that R is a fictitious base ring (coefficient ring) and that S is a series ring over R (e.g. $S = R[[x]]$) with parent object S of type MySeriesRing{T}. We also assume the series in the ring have type MySeries{T}, where T is the type of elements of the base (coefficient) ring.

Of course, in practice these types may not be parameterised, but we use parameterised types here to make the interface clearer.

Note that the type T must (transitively) belong to the abstract type RingElem.

Constructors

In addition to the standard constructors, the following constructors, taking an array of coefficients, must be available.

For relative power series and Laurent series we have:

(S::MySeriesRing{T})(A::Vector{T}, len::Int, prec::Int, val::Int) where T <: RingElem

Create the series in the given ring whose valuation is val, whose absolute precision is given by prec and the coefficients of which are given by A, starting from the first nonzero term. Only len terms of the array are used, the remaining terms being ignored. The value len cannot exceed the length of the supplied array.

It is permitted to have trailing zeros in the array, but it is not needed, even if the precision minus the valuation is bigger than the length of the array.

(S::MySeriesRing{T})(A::Vector{U}, len::Int, prec::Int, val::Int) where {T <: RingElem, U <: RingElem}

As above, but where the array is an array of coefficient that can be coerced into the base ring of the series ring.

(S::MySeriesRing{T})(A::Vector{U}, len::Int, prec::Int, val::Int) where {T <: RingElem, U <: Integer}

As above, but where the array is an array of integers that can be coerced into the base ring of the series ring.

It may be desirable to implement an addition version which accepts an array of Julia Int values if this can be done more efficiently.

For absolute power series we have:

(S::MySeriesRing{T})(A::Vector{T}, len::Int, prec::Int) where T <: RingElem

Create the series in the given ring whose absolute precision is given by prec and the coefficients of which are given by A, starting from the constant term. Only len terms of the array are used, the remaining terms being ignored.

Note that len is usually maintained separately of any polynomial that is underlying the power series. This allows for easy trucation of a power series without actually modifying the polynomial underlying it.

It is permitted to have trailing zeros in the array, but it is not needed, even if the precision is bigger than the length of the array.

It is also possible to create series directly without having to create the corresponding series ring.

abs_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T
+rel_series(R::Ring, arr::Vector{T}, len::Int, prec::Int, val::Int, var::VarName=:x; max_precision::Int=prec, cached::Bool=true) where T

Create the power series over the given base ring R with coefficients specified by arr with the given absolute precision prec and in the case of relative series with the given valuation val.

Note that more coefficients may be specified than are actually used. Only the first len coefficients are made part of the series, the remainder being stored internally but ignored.

In the case of absolute series one must have prec >= len and in the case of relative series one must have prec >= len + val.

By default the series are created in a ring with variable x and max_precision equal to prec, however one may specify these directly to override the defaults. Note that series are only compatible if they have the same coefficient ring R, max_precision and variable name var.

Also by default any parent ring created is cached. If this behaviour is not desired, set cached=false. However, this means that subsequent series created in the same way will not be compatible. Instead, one should use the parent object of the first series to create subsequent series instead of calling this function repeatedly with cached=false.

Data type and parent object methods

var(S::MySeriesRing{T}) where T <: RingElem

Return a Symbol representing the variable (generator) of the series ring. Note that this is a Symbol not a String, though its string value will usually be used when printing series.

Custom series types over a given ring should define one of the following functions which return the type of an absolute or relative series object over that ring.

abs_series_type(::Type{T}) where T <: RingElement
+rel_series_type(::Type{T}) where T <: RingElement

Return the type of a series whose coefficients have the given type.

This function is defined for generic series and only needs to be defined for custom series rings, e.g. ones defined by a C implementation.

max_precision(S::MySeriesRing{T}) where T <: RingElem

Return the (default) maximum precision of the power series ring. This is the precision that the output of an operation will be if it cannot be represented to full precision (e.g. because it mathematically has infinite precision).

This value is usually supplied upon creation of the series ring and stored in the ring. It is independent of the precision which each series in the ring actually has. Those are stored on a per element basis in the actual series elements.

Basic manipulation of rings and elements

pol_length(f::MySeries{T}) where T <: RingElem

Return the length of the polynomial underlying the given power series. This is not generally useful to the user, but is used internally.

set_length!(f::MySeries{T}, n::Int) where T <: RingElem

This function sets the effective length of the polynomial underlying the given series. The function doesn't modify the actual polynomial, but simply changes the number of terms of the polynomial which are considered to belong to the power series. The remaining terms are ignored.

This function cannot set the length to a value greater than the length of any underlying polynomial.

The function mutates the series in-place but does not return the mutated series.

precision(f::MySeries{T})

Return the absolute precision of $f$.

set_precision!(f::MySeries{T}, prec::Int)

Set the absolute precision of the given series to the given value.

This return the updated series.

valuation(f::MySeries{T})

Return the valuation of the given series.

set_valuation!(f::MySeries{T}, val::Int)

For relative series and Laurent series only, this function alters the valuation of the given series to the given value.

This function returns the updated series.

polcoeff(f::MySeries{T}, n::Int)

Return the coefficient of degree n of the polynomial underlying the series. If n is larger than the degree of this polynomial, zero is returned. This function is not generally of use to the user but is used internally.

setcoeff!(f::MySeries{T}, n::Int, a::T) where T <: RingElem

Set the degree $n$ coefficient of the polynomial underlying $f$ to $a$. This mutates the polynomial in-place if possible and returns the mutated series (so that immutable types can also be supported). The function must not assume that the polynomial already has space for $n + 1$ coefficients. The polynomial must be resized if this is not the case.

Note

This function is not required to normalise the polynomial and is not necessarily useful to the user, but is used extensively by the generic functionality in AbstractAlgebra.jl. It is for setting raw coefficients in the representation.

normalise(f::MySeries{T}, n::Int)

Given a series $f$ represented by a polynomial of at least the given length, return the normalised length of the underlying polynomial assuming it has length at most $n$. This function does not actually normalise the polynomial and is not particularly useful to the user. It is used internally.

renormalize!(f::MySeries{T}) where T <: RingElem

Given a relative series or Laurent series whose underlying polynomial has zero constant term, say as the result of some internal computation, renormalise the series so that the polynomial has nonzero constant term. The precision and valuation of the series are adjusted to compensate. This function is not intended to be useful to the user, but is used internally.

fit!(f::MySeries{T}, n::Int) where T <: RingElem

Ensure that the polynomial underlying $f$ internally has space for $n$ coefficients. This function must mutate the series in-place if it is mutable. It does not return the mutated series. Immutable types can still be supported by defining this function to do nothing.

Some interfaces for C polynomial types automatically manage the internal allocation of polynomials in every function that can be called on them. Explicit adjustment by the generic code in AbstractAlgebra.jl is not required. In such cases, this function can also be defined to do nothing.

gen(R::MySeriesRing{T}) where T <: RingElem

Return the generator x of the series ring.

Optional functionality for series

Similar and zero

The following functions are available for all absolute and relative series types. The functions similar and zero do the same thing, but are provided for uniformity with other parts of the interface.

similar(x::MySeries, R::Ring, max_prec::Int, var::VarName=var(parent(x)); cached::Bool=true)
+zero(a::MySeries, R::Ring, max_prec::Int, var::VarName=var(parent(a)); cached::Bool=true)

Construct the zero series with the given variable (if specified), coefficients in the specified coefficient ring and with relative/absolute precision cap on its parent ring as given by max_prec.

similar(x::MySeries, R::Ring, var::VarName=var(parent(x)); cached::Bool=true)
+similar(x::MySeries, max_prec::Int, var::VarName=var(parent(x)); cached::Bool=true)
+similar(x::MySeries, var::VarName=var(parent(x)); cached::Bool=true)
+similar(x::MySeries, R::Ring, max_prec::Int, var::VarName; cached::Bool=true)
+similar(x::MySeries, R::Ring, var::VarName; cached::Bool=true)
+similar(x::MySeries, max_prec::Int, var::VarName; cached::Bool=true)
+similar(x::MySeries, var::VarName; cached::Bool=true)
+zero(x::MySeries, R::Ring, var::VarName=var(parent(x)); cached::Bool=true)
+zero(x::MySeries, max_prec::Int, var::VarName=var(parent(x)); cached::Bool=true)
+zero(x::MySeries, var::VarName=var(parent(x)); cached::Bool=true)
+zero(x::MySeries, R::Ring, max_prec::Int, var::VarName; cached::Bool=true)
+zero(x::MySeries, R::Ring, var::VarName; cached::Bool=true)
+zero(x::MySeries, max_prec::Int, var::VarName; cached::Bool=true)
+zero(x::MySeries, var::VarName; cached::Bool=true)

As above, but use the precision cap of the parent ring of x and the base_ring of x if these are not specified.

Custom series rings may choose which series type is best-suited to return for the given coefficient ring, precision cap and variable, however they should return a series with the same model as x, i.e. relative or series.

If custom implementations don't specialise these function the default return type is a Generic.AbsSeries or Generic.RelSeries.

The default implementation of zero calls out to similar, so it's generally sufficient to specialise only similar. For both similar and zero only the most general method has to be implemented as all other methods call out to this more general method.

diff --git a/v0.37.6/siteinfo.js b/v0.37.6/siteinfo.js new file mode 100644 index 0000000000..50921b5d9d --- /dev/null +++ b/v0.37.6/siteinfo.js @@ -0,0 +1 @@ +var DOCUMENTER_CURRENT_VERSION = "v0.37.6"; diff --git a/v0.37.6/submodule/index.html b/v0.37.6/submodule/index.html new file mode 100644 index 0000000000..caf1634eb1 --- /dev/null +++ b/v0.37.6/submodule/index.html @@ -0,0 +1,86 @@ + +Submodules · AbstractAlgebra.jl

Submodules

AbstractAlgebra allows the construction of submodules/subvector spaces of AbstractAlgebra modules over euclidean domains. These are given as the submodule generated by a finite list of elements in the original module.

We define two submodules to be equal if they are (transitively) submodules of the same module $M$ and their generators generate the same set of elements.

Generic submodule type

AbstractAlgebra implements a generic submodule type Generic.Submodule{T} where T is the element type of the base ring in src/generic/Submodule.jl. See src/generic/GenericTypes.jl for more details of the type definition.

Elements of a generic submodule have type Generic.SubmoduleElem{T}.

Abstract types

Submodule types belong to the abstract type FPModule{T} and their elements to FPModuleElem{T}.

Constructors

AbstractAlgebra.subMethod
sub(m::FPModule{T}, gens::Vector{<:FPModuleElem{T}}) where T <: RingElement

Return the submodule of the module m generated by the given generators, given as elements of m.

source
AbstractAlgebra.subMethod
sub(m::Module{T}, subs::Vector{<:Generic.Submodule{T}}) where T <: RingElement

Return the submodule S of the module m generated by the union of the given submodules of $m$, and a map which is the canonical injection from S to m.

source

Note that the preimage of the canonical injection can be obtained using the preimage function described in the section on module homomorphisms. As the canonical injection is injective, this is unique.

Examples

julia> M = FreeModule(ZZ, 2)
+Free module of rank 2 over integers
+
+julia> m = M([ZZ(1), ZZ(2)])
+(1, 2)
+
+julia> n = M([ZZ(2), ZZ(-1)])
+(2, -1)
+
+julia> N, f = sub(M, [m, n])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 2 over integers)
+
+julia> v = N([ZZ(3), ZZ(4)])
+(3, 4)
+
+julia> v2 = f(v)
+(3, 26)
+
+julia> V = VectorSpace(QQ, 2)
+Vector space of dimension 2 over rationals
+
+julia> m = V([QQ(1), QQ(2)])
+(1//1, 2//1)
+
+julia> n = V([QQ(2), QQ(-1)])
+(2//1, -1//1)
+
+julia> N, f = sub(V, [m, n])
+(Subspace over Rationals with 2 generators and no relations, Hom: subspace over Rationals with 2 generators and no relations -> vector space of dimension 2 over rationals)
+

Functionality for submodules

In addition to the Module interface, AbstractAlgebra submodules implement the following functionality.

Basic manipulation

AbstractAlgebra.Generic.is_submoduleMethod
is_submodule(M::AbstractAlgebra.FPModule{T}, N::AbstractAlgebra.FPModule{T}) where T <: RingElement

Return true if $N$ was constructed as a submodule of $M$. The relation is taken transitively (i.e. subsubmodules are submodules for the purposes of this relation, etc). The module $M$ is also considered a submodule of itself for this relation.

source
AbstractAlgebra.Generic.is_compatibleMethod
is_compatible(M::AbstractAlgebra.FPModule{T}, N::AbstractAlgebra.FPModule{T}) where T <: RingElement

Return true, P if the given modules are compatible, i.e. that they are (transitively) submodules of the same module, P. Otherwise return false, M.

source

Examples

julia> M = FreeModule(ZZ, 2)
+Free module of rank 2 over integers
+
+julia> m = M([ZZ(2), ZZ(3)])
+(2, 3)
+
+julia> n = M([ZZ(1), ZZ(4)])
+(1, 4)
+
+julia> N1, = sub(M, [m, n])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 2 over integers)
+
+julia> N2, = sub(M, [m])
+(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 2 over integers)
+
+julia> supermodule(N1) == M
+true
+
+julia> is_compatible(N1, N2)
+(true, Free module of rank 2 over integers)
+
+julia> is_submodule(N1, M)
+false
+
+
+julia> V = VectorSpace(QQ, 2)
+Vector space of dimension 2 over rationals
+
+julia> m = V([QQ(2), QQ(3)])
+(2//1, 3//1)
+
+julia> N, = sub(V, [m])
+(Subspace over Rationals with 1 generator and no relations, Hom: subspace over Rationals with 1 generator and no relations -> vector space of dimension 2 over rationals)
+
+julia> dim(V)
+2
+
+julia> dim(N)
+1
+

Intersection

Base.intersectMethod
intersect(M::FPModule{T}, N::FPModule{T}) where T <: RingElement

Return the intersection of the modules $M$ as a submodule of $M$. Note that $M$ and $N$ must be (constructed as) submodules (transitively) of some common module $P$.

source

Examples

julia> M = FreeModule(ZZ, 2)
+Free module of rank 2 over integers
+
+julia> m = M([ZZ(2), ZZ(3)])
+(2, 3)
+
+julia> n = M([ZZ(1), ZZ(4)])
+(1, 4)
+
+julia> N1 = sub(M, [m, n])
+(Submodule over Integers with 2 generators and no relations, Hom: submodule over Integers with 2 generators and no relations -> free module of rank 2 over integers)
+
+julia> N2 = sub(M, [m])
+(Submodule over Integers with 1 generator and no relations, Hom: submodule over Integers with 1 generator and no relations -> free module of rank 2 over integers)
+
+julia> I = intersect(N1, N2)
+Any[]
diff --git a/v0.37.6/total_fraction/index.html b/v0.37.6/total_fraction/index.html new file mode 100644 index 0000000000..8daa5123ff --- /dev/null +++ b/v0.37.6/total_fraction/index.html @@ -0,0 +1,107 @@ + +Total ring of fractions · AbstractAlgebra.jl

Total ring of fractions

AbstractAlgebra.jl provides a module, implemented in src/generic/TotalFraction.jl, for the total ring of fractions of a ring.

The total ring of fractions of a ring R is the localisation of R at the non-zero divisors of R, the latter being a multiplicative subset of R.

There are no restrictions on the ring except the function is_zero_divisor must be defined and effective for R.

In particular, we do not assume that all elements of R which are not zero divisors are units in R. This has the effect of making exact division impossible generically in the total ring of fractions of R.

This in turn limits the usefulness of the total ring of fractions as a ring in AbstractAlgebra as a great deal of generic code relies on divexact. Should this be a limitation, the user can define their own divexact function for the total ring of fractions in question.

Note that in most cases a*inv(b) is not a sufficient definition of divexact(a, b) due to the possibility that b is not a unit in the total ring of fractions.

It is also possible to construct a total ring of fractions of R without the is_zero_divisor function existing for R, but some functions such as is_unit, inv, rand and ad hoc arithmetic operations involving rational numbers are not available for the total ring of fractions. One must also construct fractions using the option check=false and it is one's own responsibility to check that the denominator is not a zero divisor.

Note that although the total ring of fractions of an integral domain R is mathematically the same thing as the fraction field of R, these will be different objects in AbstractAlgebra and have different types.

Generic total ring of fraction types

AbstractAlgebra.jl implements a generic type for elements of a total ring of fractions, namelyGeneric.TotFrac{T} where T is the type of elements of the base ring. See the file src/generic/GenericTypes.jl for details.

Parent objects of such elements have type Generic.TotFracRing{T}.

Abstract types

The types for elements of a total ring of fractions belong directly to the abstract type RingElem and the type for the total ring of fractions parent object belongs directly to the abstract type Ring.

Total ring of fractions constructors

In order to construct fractions in a total ring of fractions in AbstractAlgebra.jl, one must first construct the parent object for the total ring of fractions itself. This is accomplished with the following constructor.

total_ring_of_fractions(R::Ring; cached::Bool = true)

Given a base ring R return the parent object of the total ring of fractions of $R$. By default the parent object S will depend only on R and will be cached. Setting the optional argument cached to false will prevent the parent object S from being cached.

Here are some examples of creating a total ring of fractions and making use of the resulting parent objects to coerce various elements into the ring.

Examples

julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S = total_ring_of_fractions(R)
+Total ring of fractions of Univariate polynomial ring in x over integers
+
+julia> f = S()
+0
+
+julia> g = S(123)
+123
+
+julia> h = S(BigInt(1234))
+1234
+
+julia> k = S(x + 1)
+x + 1

Fraction constructors

One can construct fractions using the total ring of fractions parent object, as for any ring or field.

(R::TotFracRing)() # constructs zero
+(R::TotFracRing)(c::Integer)
+(R::TotFracRing)(c::elem_type(R))
+(R::TotFracRing{T})(a::T) where T <: RingElement

Although one cannot use the double slash operator // to construct elements of a total ring of fractions, as no parent has been specified, one can use the double slash operator to construct elements of a total ring of fractions so long as one of the arguments to the double slash operator is already in the total ring of fractions in question.

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S = total_ring_of_fractions(R)
+Total ring of fractions of Univariate polynomial ring in x over rationals
+
+julia> f = S(x + 1)
+x + 1
+
+julia> f//3
+(x + 1)//3
+
+julia> 3//f
+3//(x + 1)
+
+julia> f//x
+(x + 1)//x

Functions for types and parents of total rings of fractions

Total rings of fractions in AbstractAlgebra.jl implement the Ring interface except for the divexact function which is not generically possible to implement.

base_ring(R::TotFracRing)
+base_ring(a::TotFrac)

Return the base ring of which the total ring of fractions was constructed.

parent(a::TotFrac)

Return the total ring of fractions that the given fraction belongs to.

characteristic(R::TotFracRing)

Return the characteristic of the base ring of the total ring of fractions. If the characteristic is not known an exception is raised.

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S = total_ring_of_fractions(R)
+Total ring of fractions of Univariate polynomial ring in x over rationals
+
+julia> f = S(x + 1)
+x + 1
+
+julia> U = base_ring(S)
+Univariate polynomial ring in x over rationals
+
+julia> V = base_ring(f)
+Univariate polynomial ring in x over rationals
+
+julia> T = parent(f)
+Total ring of fractions of Univariate polynomial ring in x over rationals
+
+julia> m = characteristic(S)
+0

Total ring of fractions functions

Basic functions

Total rings of fractions implement the Ring interface.

zero(R::TotFracRing)
+one(R::TotFracRing)
+iszero(a::TotFrac)
+isone(a::TotFrac)
inv(a::T) where T <: TotFrac

They also implement some of the following functions which would usually be associated with the field and fraction field interfaces.

is_unit(f::TotFrac)
numerator(a::TotFrac)
+denominator(a::TotFrac)

Examples

julia> R, x = polynomial_ring(QQ, "x")
+(Univariate polynomial ring in x over rationals, x)
+
+julia> S = total_ring_of_fractions(R)
+Total ring of fractions of Univariate polynomial ring in x over rationals
+
+julia> f = S(x + 1)
+x + 1
+
+julia> g = f//(x^3 + 3x + 1)
+(x + 1)//(x^3 + 3*x + 1)
+
+julia> h = zero(S)
+0
+
+julia> k = one(S)
+1
+
+julia> isone(k)
+true
+
+julia> iszero(f)
+false
+
+julia> r = deepcopy(f)
+x + 1
+
+julia> n = numerator(g)
+x + 1
+
+julia> d = denominator(g)
+x^3 + 3*x + 1

Random generation

Random fractions can be generated using rand. The parameters passed after the total ring of fractions tell rand how to generate random elements of the base ring.

rand(R::TotFracRing, v...)

Examples

julia> R, = residue_ring(ZZ, 12);
+
+julia> K = total_ring_of_fractions(R)
+Total ring of fractions of Residue ring of integers modulo 12
+
+julia> f = rand(K, 0:11)
+7//5
+
+julia> R, x = polynomial_ring(ZZ, "x")
+(Univariate polynomial ring in x over integers, x)
+
+julia> S = total_ring_of_fractions(R)
+Total ring of fractions of Univariate polynomial ring in x over integers
+
+julia> g = rand(S, -1:3, -10:10)
+(4*x + 4)//(-4*x^2 - x + 4)
diff --git a/v0.37.6/types/index.html b/v0.37.6/types/index.html new file mode 100644 index 0000000000..6c5916d84b --- /dev/null +++ b/v0.37.6/types/index.html @@ -0,0 +1,18 @@ + +Type interface of AbstractAlgebra.jl · AbstractAlgebra.jl

Type interface of AbstractAlgebra.jl

Apart from how we usually think of types in programming, we shall in this section discuss why we do not use the typical type interface.

Why types aren't enough

Naively, one might have expected that structures like rings in AbstractAlgebra.jl could be modeled as types and their elements as objects with the given type. But there are various reasons why this is not a good model.

Consider the ring $R = \mathbb{Z}/n\mathbb{Z}$ for a multiprecision integer $n$. If we were to model the ring $R$ as a type, then the type would somehow need to contain the modulus $n$. This is not possible in Julia, and in fact it is not desirable, since the compiler would then recompile all the associated functions every time a different modulus $n$ was used.

We could attach the modulus $n$ to the objects representing elements of the ring, rather than their type.

But now we cannot create new elements of the ring $\mathbb{Z}/n\mathbb{Z}$ given only their type, since the type no longer contains the modulus $n$.

Instead, the way we get around this in AbstractAlgebra.jl is to have special (singleton) objects that act like types, but are really just ordinary Julia objects. These objects, called parent objects, can contain extra information, such as the modulus $n$. In return, we associate this parent object with so called element objects.

In order to create new elements of $\mathbb{Z}/n\mathbb{Z}$ as above, we overload the call operator for the parent object.

In the following AbstractAlgebra.jl example, we create the parent object R corresponding to the ring $\mathbb{Z}/7\mathbb{Z}$. We then create a new element a of this ring by calling the parent object R.

R, = residue_ring(ZZ, 7)
+a = R(3)

Here, R is the parent object, containing the modulus $7$. So this example creates the element $a = 3 \pmod{7}$.

Objects known as parents which contain additional information about groups, rings, fields and modules, etc., that can't be stored in types alone.

These details are technical and can be skipped or skimmed by new users of Julia/AbstractAlgebra.jl. Types are almost never dealt with directly when scripting AbstractAlgebra.jl to do mathematical computations.

In contrast, AbstractAlgebra.jl developers will want to know how we model mathematical objects and their rings, fields, groups, etc.

The abstract type hierarchy in AbstractAlgebra.jl

In AbstractAlgebra.jl, we use the abstract type hierarchy in order to give structure when programming the mathematical structures. For example, abstract types in Julia can belong to one another in a hierarchy.

For example, the Field abstract type belongs to the Ring abstract type. The full hierarchy can be seen in diagrams under the section on visualisation of the abstract types.

In practice this is practical since it means that any generic function designed to work with ring objects will also work with field objects.

In AbstractAlgebra.jl we also distinguish between the elements of a field, say, and the field itself.

For example, we have an object of type Generic.PolyRing to model a generic polynomial ring, and elements of that polynomial ring would have type Generic.PolyRingElem.

For this purpose, we also have a hierarchy of abstract types, such as FieldElem, that the types of element objects can belong to.

More complex example of parent objects

Here is some code which constructs a polynomial ring over the integers, a polynomial in that ring and then does some introspection to illustrate the various relations between the objects and types.

julia> using AbstractAlgebra
+
+julia> R, x = ZZ["x"]
+(Univariate polynomial ring in x over integers, x)
+
+julia> f = x^2 + 3x + 1
+x^2 + 3*x + 1
+
+julia> R isa PolyRing
+true
+
+julia> f isa PolyRingElem
+true
+
+julia> parent(f) == R
+true
diff --git a/v0.37.6/univpolynomial/index.html b/v0.37.6/univpolynomial/index.html new file mode 100644 index 0000000000..9c3f34f0a1 --- /dev/null +++ b/v0.37.6/univpolynomial/index.html @@ -0,0 +1,11 @@ + +Universal polynomial · AbstractAlgebra.jl

Universal polynomial

AbstractAlgebra.jl provides a module, implemented in src/generic/UnivPoly.jl for a universal polynomial ring. This is very similar to the multivariate polynomial rings, except that variables can be added to the ring at any time.

To compensate for the fact that the number of variables may change, many of the functions relax their restrictions on exponent vectors. For example, if one creates a polynomial when the ring only has two variables, each exponent vector would consist of two integers. Later, when the ring has more variable, these exponent vectors will still be accepted. The exponent vectors are simply padded out to the full number of variables behind the scenes.

Generic sparse distributed universal multivariable polynomial types

AbstractAlgebra provides a generic universal polynomial type Generic.UnivPoly{T, U} where T is the type of elements of the coefficient ring and U is the type of the elements of the underlying multivariate polynomial ring. Essentially, U can be any type belonging to MPolyRingElem{T}.

Parent objects of such polynomials have type Generic.UniversalPolyRing{T, U}.

Abstract types

AbstractAlgebra also provides abstract types for universal polynomials and their rings. These are UniversalPolyRingElem{T, U} and UniversalPolyRing{T, U} respectively. These in turn belong to Ring.

Polynomial ring constructors

In order to construct universal polynomials in AbstractAlgebra.jl, one must first construct the universal polynomial ring itself. This is unique given a base ring.

The universal polynomial ring over a given base ring R is constructed with one of the following constructor functions.

UniversalPolynomialRing(R::Ring; cached::Bool = true, ordering::Symbol=:lex)

Given a base ring R and an array S of strings, return an object representing the universal polynomial ring $S = R[\ldots]$ with no variables in it initially.

Examples

julia> S = UniversalPolynomialRing(ZZ)
+Universal Polynomial Ring over Integers

Adding variables

There are two ways to add variables to a universal polynomial ring S.

gen(S::UniversalPolyRing, var::VarName)
+gens(S::UniversalPolyRing, vars::Vector{VarName})

Examples

julia> S = UniversalPolynomialRing(ZZ)
+Universal Polynomial Ring over Integers
+
+julia> x = gen(S, "x")
+x
+
+julia> y, z = gens(S, ["y", "z"])
+(y, z)

Universal polynomial functionality

The universal polynomial ring behaves exactly like a multivariate polynomial ring with the few differences noted above.

The only functionality not implemented is the ability to do divrem by an ideal of polynomials.

The universal polynomial ring is very useful for doing symbolic manipulation. However, it is important to understand that AbstractAlgebra is not a symbolic system and the performance of the universal polynomial ring will closely match that of a multivariate polynomial ring with the same number of variables.

The disadvantage of this approach to symbolic manipulation is that some manipulations that would be offered by a symbolic system are not available, as variables are not identified by their names alone in AbstractAlgebra, as would be the case symbolically, but by objects.

The most powerful symbolic tools we offer are the generalised evaluation functions, the multivariate coefficient functionality, the ability to change coefficient ring and to map coefficients according to a supplied function and the ability to convert a multivariate which happens to have just one variable into a dense univariate polynomial.

Further facilities may be added in future to ease symbolic manipulations.

diff --git a/v0.37.6/visualizing_types/index.html b/v0.37.6/visualizing_types/index.html new file mode 100644 index 0000000000..c4456f4c08 --- /dev/null +++ b/v0.37.6/visualizing_types/index.html @@ -0,0 +1,2 @@ + +Visualization of the types of AbstractAlgebra.jl · AbstractAlgebra.jl

Visualization of the types of AbstractAlgebra.jl

AbstractAlgebra.jl implements a couple of abstract types which can be extended.

Abstract parents

The following diagram shows a complete list of all abstract types in AbstractAlgebra.jl.

Diagram of parent types

Abstract elements

Similarly the following diagram shows a complete list of all abstract types in AbstractAlgebra.jl.

Diagram of element types

Concrete types in AbstractAlgebra.jl

Until now we have discussed the abstract types of AbstractAlgebra.jl. Under this subsection we will instead give some examples of concrete types in AbstractAlgebra.jl.

In parentheses we put the types of the corresponding parent objects.

  • Perm{<:Integer} (SymmetricGroup{<:Integer})
  • GFElem{<:Integer} (GFField{<:Integer})

We also think of various Julia types as though they were AbstractAlgebra.jl types:

  • BigInt (Integers{BigInt})
  • Rational{BigInt} (Rationals{BigInt})

Then there are various types for generic constructions over a base ring. They are all parameterised by a type T which is the type of the elements of the base ring they are defined over.

  • Generic.Poly{T} (Generic.PolyRing{T})
  • Generic.MPoly{T} (Generic.MPolyRing{T})
  • Generic.RelSeries{T} (Generic.RelPowerSeriesRing{T})
  • Generic.AbsSeries{T} (Generic.AbsPowerSeriesRing{T})
  • Generic.LaurentSeriesRingElem{T} (Generic.LaurentSeriesRing{T})
  • Generic.LaurentSeriesFieldElem{T} (Generic.LaurentSeriesField{T})
  • Generic.ResidueRingElem{T} (Generic.ResidueRing{T})
  • Generic.FracFieldElem{T} (Generic.FracField{T})
  • Generic.Mat{T} (Generic.MatSpace{T})
diff --git a/v0.37.6/ytabs/index.html b/v0.37.6/ytabs/index.html new file mode 100644 index 0000000000..b0a00fc148 --- /dev/null +++ b/v0.37.6/ytabs/index.html @@ -0,0 +1,260 @@ + +Partitions and Young tableaux · AbstractAlgebra.jl

Partitions and Young tableaux

AbstractAlgebra.jl provides basic support for computations with Young tableaux, skew diagrams and the characters of permutation groups (implemented src/generic/YoungTabs.jl). All functionality of permutations is accessible in the Generic submodule.

Partitions

The basic underlying object for those concepts is Partition of a number $n$, i.e. a sequence of positive integers $n_1, \ldots, n_k$ which sum to $n$. Partitions in AbstractAlgebra.jl are represented internally by non-increasing Vectors of Ints. Partitions are printed using the standard notation, i.e. $9 = 4 + 2 + 1 + 1 + 1$ is shown as $4_1 2_1 1_3$ with the subscript indicating the count of a summand in the partition.

AbstractAlgebra.Generic.PartitionType
Partition(part::Vector{<:Integer}[, check::Bool=true]) <: AbstractVector{Int}

Represent integer partition in the non-increasing order.

part will be sorted, if necessary. Checks for validity of input can be skipped by calling the (inner) constructor with false as the second argument.

Functionally Partition is a thin wrapper over Vector{Int}.

Fieldnames:

  • n::Int - the partitioned number
  • part::Vector{Int} - a non-increasing sequence of summands of n.

Examples

julia> p = Partition([4,2,1,1,1])
+4₁2₁1₃
+
+julia> p.n == sum(p.part)
+true
source

Array interface

Partition is a concrete (immutable) subtype of AbstractVector{Integer} and implements the standard Array interface.

Base.sizeMethod
size(p::Partition)

Return the size of the vector which represents the partition.

Examples

julia> p = Partition([4,3,1]); size(p)
+(3,)
source
Base.getindexMethod
getindex(p::Partition, i::Integer)

Return the i-th part (in non-increasing order) of the partition.

source

These functions work on the level of p.part vector.

One can easily iterate over all partitions of $n$ using the Generic.partitions function.

AbstractAlgebra.Generic.partitionsFunction
partitions(n::Integer)

Return the vector of all permutations of n. For an unsafe generator version see partitions!.

Examples

julia> Generic.partitions(5)
+7-element Vector{AbstractAlgebra.Generic.Partition{Int64}}:
+ 1₅
+ 2₁1₃
+ 3₁1₂
+ 2₂1₁
+ 4₁1₁
+ 3₁2₁
+ 5₁
source

You may also have a look at JuLie.jl package for more utilities related to partitions.

The number of all partitions can be computed by the hidden function _numpart. Much faster implementation is available in Nemo.jl.

AbstractAlgebra.Generic._numpartFunction
_numpart(n::Integer)

Return the number of all distinct integer partitions of n. The function uses Euler pentagonal number theorem for recursive formula. For more details see OEIS sequence A000041. Note that _numpart(0) = 1 by convention.

source

Since Partition is a subtype of AbstractVector generic functions which operate on vectors should work in general. However the meaning of conj has been changed to agree with the traditional understanding of conjugation of Partitions:

Base.conjMethod
conj(part::Partition)

Return the conjugated partition of part, i.e. the partition corresponding to the Young diagram of part reflected through the main diagonal.

Examples

julia> p = Partition([4,2,1,1,1])
+4₁2₁1₃
+
+julia> conj(p)
+5₁2₁1₂
source
Base.conjMethod
conj(part::Partition, v::Vector)

Return the conjugated partition of part together with permuted vector v.

source

Young Diagrams and Young Tableaux

Mathematically speaking Young diagram is a diagram which consists of rows of square boxes such that the number of boxes in each row is no less than the number of boxes in the previous row. For example partition $4_1 3_2 1$ represents the following diagram.

┌───┬───┬───┬───┐
+│   │   │   │   │
+├───┼───┼───┼───┘
+│   │   │   │
+├───┼───┼───┤
+│   │   │   │
+├───┼───┴───┘
+│   │
+└───┘

Young Tableau is formally a bijection between the set of boxes of a Young Diagram and the set $\{1, \ldots, n\}$. If a bijection is increasing along rows and columns of the diagram it is referred to as standard. For example

┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┼───┤
+│ 8 │ 9 │10 │
+├───┼───┴───┘
+│11 │
+└───┘

is a standard Young tableau of $4_1 3_2 1$ where the bijection assigns consecutive natural numbers to consecutive (row-major) cells.

Constructors

In AbstractAlgebra.jl Young tableau are implemented as essentially row-major sparse matrices, i.e. YoungTableau <: AbstractMatrix{Int} but only the defining Partition and the (row-major) fill-vector is stored.

AbstractAlgebra.Generic.YoungTableauType
YoungTableau(part::Partition[, fill::Vector{Int}=collect(1:sum(part))])  <: AbstractMatrix{Int}

Return the Young tableaux of partition part, filled linearly by fill vector. Note that fill vector is in row-major format.

Fields:

  • part - the partition defining Young diagram
  • fill - the row-major fill vector: the entries of the diagram.

Examples

julia> p = Partition([4,3,1]); y = YoungTableau(p)
+┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┴───┘
+│ 8 │
+└───┘
+
+julia> y.part
+4₁3₁1₁
+
+julia> y.fill
+8-element Vector{Int64}:
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
source

For convenience there exists an alternative constructor of YoungTableau, which accepts a vector of integers and constructs Partition internally.

YoungTableau(p::Vector{Integer}[, fill=collect(1:sum(p))])

Array interface

To make YoungTableaux array-like we implement the following functions:

Base.sizeMethod
size(Y::YoungTableau)

Return size of the smallest array containing Y, i.e. the tuple of the number of rows and the number of columns of Y.

Examples

julia> y = YoungTableau([4,3,1]); size(y)
+(3, 4)
source
Base.getindexMethod
getindex(Y::YoungTableau, n::Integer)

Return the column-major linear index into the size(Y)-array. If a box is outside of the array return 0.

Examples

julia> y = YoungTableau([4,3,1])
+┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┴───┘
+│ 8 │
+└───┘
+
+julia> y[1]
+1
+
+julia> y[2]
+5
+
+julia> y[4]
+2
+
+julia> y[6]
+0
source

Also the double-indexing corresponds to (row, column) access to an abstract array.

julia> y = YoungTableau([4,3,1])
+┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┴───┘
+│ 8 │
+└───┘
+
+julia> y[1,2]
+2
+
+julia> y[2,3]
+7
+
+julia> y[3,2]
+0

Functions defined for AbstractArray type based on those (e.g. length) should work. Again, as in the case of Partition the meaning of conj is altered to reflect the usual meaning for Young tableaux:

Base.conjMethod
conj(Y::YoungTableau)

Return the conjugated tableau, i.e. the tableau reflected through the main diagonal.

Examples

julia> y = YoungTableau([4,3,1])
+┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┴───┘
+│ 8 │
+└───┘
+
+julia> conj(y)
+┌───┬───┬───┐
+│ 1 │ 5 │ 8 │
+├───┼───┼───┘
+│ 2 │ 6 │
+├───┼───┤
+│ 3 │ 7 │
+├───┼───┘
+│ 4 │
+└───┘
source

Pretty-printing

Similarly to permutations we have two methods of displaying Young Diagrams:

AbstractAlgebra.Generic.setyoungtabstyleFunction
setyoungtabstyle(format::Symbol)

Select the style in which Young tableaux are displayed (in REPL or in general as string). This can be either

  • :array - as matrices of integers, or
  • :diagram - as filled Young diagrams (the default).

The difference is purely esthetical.

Examples

julia> Generic.setyoungtabstyle(:array)
+:array
+
+julia> p = Partition([4,3,1]); YoungTableau(p)
+ 1  2  3  4
+ 5  6  7
+ 8
+
+julia> Generic.setyoungtabstyle(:diagram)
+:diagram
+
+julia> YoungTableau(p)
+┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┴───┘
+│ 8 │
+└───┘
source

Ulitility functions

AbstractAlgebra.Generic.matrix_reprMethod
matrix_repr(a::Perm)

Return the permutation matrix as a sparse matrix representing a via natural embedding of the permutation group into the general linear group over $\mathbb{Z}$.

Examples

julia> p = Perm([2,3,1])
+(1,2,3)
+
+julia> matrix_repr(p)
+3×3 SparseArrays.SparseMatrixCSC{Int64, Int64} with 3 stored entries:
+ ⋅  1  ⋅
+ ⋅  ⋅  1
+ 1  ⋅  ⋅
+
+julia> Array(ans)
+3×3 Matrix{Int64}:
+ 0  1  0
+ 0  0  1
+ 1  0  0
source
matrix_repr(Y::YoungTableau)

Construct sparse integer matrix representing the tableau.

Examples

julia> y = YoungTableau([4,3,1]);
+
+
+julia> matrix_repr(y)
+3×4 SparseArrays.SparseMatrixCSC{Int64, Int64} with 8 stored entries:
+ 1  2  3  4
+ 5  6  7  ⋅
+ 8  ⋅  ⋅  ⋅
source
Base.fill!Method
fill!(Y::YoungTableaux, V::Vector{<:Integer})

Replace the fill vector Y.fill by V. No check if the resulting tableau is standard (i.e. increasing along rows and columns) is performed.

Examples

julia> y = YoungTableau([4,3,1])
+┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┴───┘
+│ 8 │
+└───┘
+
+julia> fill!(y, [2:9...])
+┌───┬───┬───┬───┐
+│ 2 │ 3 │ 4 │ 5 │
+├───┼───┼───┼───┘
+│ 6 │ 7 │ 8 │
+├───┼───┴───┘
+│ 9 │
+└───┘
source

Characters of permutation groups

Irreducible characters (at least over field of characteristic $0$) of the full group of permutations $S_n$ correspond via Specht modules to partitions of $n$.

AbstractAlgebra.Generic.characterMethod
character(lambda::Partition)

Return the $\lambda$-th irreducible character of permutation group on sum(lambda) symbols. The returned character function is of the following signature:

chi(p::Perm[, check::Bool=true]) -> BigInt

The function checks (if p belongs to the appropriate group) can be switched off by calling chi(p, false). The values computed by $\chi$ are cached in look-up table.

The computation follows the Murnaghan-Nakayama formula: $\chi_\lambda(\sigma) = \sum_{\text{rimhook }\xi\subset \lambda}(-1)^{ll(\lambda\backslash\xi)} \chi_{\lambda \backslash\xi}(\tilde\sigma)$ where $\lambda\backslash\xi$ denotes the skew diagram of $\lambda$ with $\xi$ removed, $ll$ denotes the leg-length (i.e. number of rows - 1) and $\tilde\sigma$ is permutation obtained from $\sigma$ by the removal of the longest cycle.

For more details see e.g. Chapter 2.8 of Group Theory and Physics by S.Sternberg.

Examples

julia> G = SymmetricGroup(4)
+Full symmetric group over 4 elements
+
+julia> chi = character(Partition([3,1])); # character of the regular representation
+
+
+julia> chi(one(G))
+3
+
+julia> chi(perm"(1,3)(2,4)")
+-1
source
AbstractAlgebra.Generic.characterMethod
character(lambda::Partition, p::Perm, check::Bool=true) -> BigInt

Return the value of lambda-th irreducible character of the permutation group on permutation p.

source
AbstractAlgebra.Generic.characterMethod
character(lambda::Partition, mu::Partition, check::Bool=true) -> BigInt

Return the value of lambda-th irreducible character on the conjugacy class represented by partition mu.

source

The values computed by characters are cached in an internal dictionary Dict{Tuple{BitVector,Vector{Int}}, BigInt}. Note that all of the above functions return BigInts. If you are sure that the computations do not overflow, variants of the last two functions using Int are available:

character(::Type{Int}, lambda::Partition, p::Perm[, check::Bool=true])
+character(::Type{Int}, lambda::Partition, mu::Partition[, check::Bool=true])

The dimension $\dim \lambda$ of the irreducible module corresponding to partition $\lambda$ can be computed using Hook length formula

AbstractAlgebra.Generic.rowlengthFunction
rowlength(Y::YoungTableau, i, j)

Return the row length of Y at box (i,j), i.e. the number of boxes in the i-th row of the diagram of Y located to the right of the (i,j)-th box.

Examples

julia> y = YoungTableau([4,3,1])
+┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┴───┘
+│ 8 │
+└───┘
+
+julia> Generic.rowlength(y, 1,2)
+2
+
+julia> Generic.rowlength(y, 2,3)
+0
+
+julia> Generic.rowlength(y, 3,3)
+0
source
AbstractAlgebra.Generic.collengthFunction
collength(Y::YoungTableau, i, j)

Return the column length of Y at box (i,j), i.e. the number of boxes in the j-th column of the diagram of Y located below of the (i,j)-th box.

Examples

julia> y = YoungTableau([4,3,1])
+┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┴───┘
+│ 8 │
+└───┘
+
+julia> Generic.collength(y, 1,1)
+2
+
+julia> Generic.collength(y, 1,3)
+1
+
+julia> Generic.collength(y, 2,4)
+0
source
AbstractAlgebra.Generic.hooklengthFunction
hooklength(Y::YoungTableau, i, j)

Return the hook-length of an element in Y at position (i,j), i.e the number of cells in the i-th row to the right of (i,j)-th box, plus the number of cells in the j-th column below the (i,j)-th box, plus 1.

Return 0 for (i,j) not in the tableau Y.

Examples

julia> y = YoungTableau([4,3,1])
+┌───┬───┬───┬───┐
+│ 1 │ 2 │ 3 │ 4 │
+├───┼───┼───┼───┘
+│ 5 │ 6 │ 7 │
+├───┼───┴───┘
+│ 8 │
+└───┘
+
+julia> hooklength(y, 1,1)
+6
+
+julia> hooklength(y, 1,3)
+3
+
+julia> hooklength(y, 2,4)
+0
source
AbstractAlgebra.Generic.dimMethod
dim(Y::YoungTableau) -> BigInt

Return the dimension (using hook-length formula) of the irreducible representation of permutation group $S_n$ associated the partition Y.part.

Since the computation overflows easily BigInt is returned. You may perform the computation of the dimension in different type by calling dim(Int, Y).

Examples

julia> dim(YoungTableau([4,3,1]))
+70
+
+julia> dim(YoungTableau([3,1])) # the regular representation of S_4
+3
source

The character associated with Y.part can also be used to compute the dimension, but as it is expected the Murnaghan-Nakayama is much slower even though (due to caching) consecutive calls are fast:

julia> λ = Partition(collect(12:-1:1))
+12₁11₁10₁9₁8₁7₁6₁5₁4₁3₁2₁1₁
+
+julia> @time dim(YoungTableau(λ))
+  0.224430 seconds (155.77 k allocations: 7.990 MiB)
+9079590132732747656880081324531330222983622187548672000
+
+julia> @time dim(YoungTableau(λ))
+  0.000038 seconds (335 allocations: 10.734 KiB)
+9079590132732747656880081324531330222983622187548672000
+
+julia> G = SymmetricGroup(sum(λ))
+Full symmetric group over 78 elements
+
+julia> @time character(λ, one(G))
+  0.000046 seconds (115 allocations: 16.391 KiB)
+9079590132732747656880081324531330222983622187548672000
+
+julia> @time character(λ, one(G))
+  0.001439 seconds (195 allocations: 24.453 KiB)
+9079590132732747656880081324531330222983622187548672000

Low-level functions and characters

As mentioned above character functions use the Murnaghan-Nakayama rule for evaluation. The implementation follows

Dan Bernstein, The computational complexity of rules for the character table of $S_n$ Journal of Symbolic Computation, 37 (6), 2004, p. 727-748,

implementing the following functions. For precise definitions and meaning please consult the paper cited.

AbstractAlgebra.Generic.partitionseqFunction
partitionseq(lambda::Partition)

Return a sequence (as BitVector) of falses and trues constructed from lambda: tracing the lower contour of the Young Diagram associated to lambda from left to right a true is inserted for every horizontal and false for every vertical step. The sequence always starts with true and ends with false.

source
partitionseq(seq::BitVector)

Return the essential part of the sequence seq, i.e. a subsequence starting at first true and ending at last false.

source
AbstractAlgebra.Generic.is_rimhookMethod
is_rimhook(R::BitVector, idx::Integer, len::Integer)

R[idx:idx+len] forms a rim hook in the Young Diagram of partition corresponding to R iff R[idx] == true and R[idx+len] == false.

source
AbstractAlgebra.Generic.MN1innerFunction
MN1inner(R::BitVector, mu::Partition, t::Integer, charvals)

Return the value of $\lambda$-th irreducible character on conjugacy class of permutations represented by partition mu, where R is the (binary) partition sequence representing $\lambda$. Values already computed are stored in charvals::Dict{Tuple{BitVector,Vector{Int}}, Int}. This is an implementation (with slight modifications) of the Murnaghan-Nakayama formula as described in

Dan Bernstein,
+"The computational complexity of rules for the character table of Sn"
+_Journal of Symbolic Computation_, 37(6), 2004, p. 727-748.
source

Skew Diagrams

Skew diagrams are formally differences of two Young diagrams. Given $\lambda$ and $\mu$, two partitions of $n+m$ and $m$ (respectively). Suppose that each of cells of $\mu$ is a cell of $\lambda$ (i.e. parts of $\mu$ are no greater than the corresponding parts of $\lambda$). Then the skew diagram denoted by $\lambda/\mu$ is the set theoretic difference the of sets of boxes, i.e. is a diagram with exactly $n$ boxes:

AbstractAlgebra.Generic.SkewDiagramType
SkewDiagram(lambda::Partition, mu::Partition) <: AbstractMatrix{Int}

Implements a skew diagram, i.e. a difference of two Young diagrams represented by partitions lambda and mu. (below dots symbolise the removed entries)

Examples

julia> l = Partition([4,3,2])
+4₁3₁2₁
+
+julia> m = Partition([3,1,1])
+3₁1₂
+
+julia> xi = SkewDiagram(l,m)
+3×4 AbstractAlgebra.Generic.SkewDiagram{Int64}:
+ ⋅  ⋅  ⋅  1
+ ⋅  1  1
+ ⋅  1
+
source

SkewDiagram implements array interface with the following functions:

Base.sizeMethod
size(xi::SkewDiagram)

Return the size of array where xi is minimally contained. See size(Y::YoungTableau) for more details.

source
Base.inMethod
in(t::Tuple{Integer,Integer}, xi::SkewDiagram)

Check if box at position (i,j) belongs to the skew diagram xi.

source
Base.getindexMethod
getindex(xi::SkewDiagram, n::Integer)

Return 1 if linear index n corresponds to (column-major) entry in xi.lam which is not contained in xi.mu. Otherwise return 0.

source

The support for skew diagrams is very rudimentary. The following functions are available:

AbstractAlgebra.Generic.leglengthFunction
leglength(xi::SkewDiagram[, check::Bool=true])

Compute the leglength of a rim-hook xi, i.e. the number of rows with non-zero entries minus one. If check is false function will not check whether xi is actually a rim-hook.

source
AbstractAlgebra.Generic.matrix_reprMethod
matrix_repr(xi::SkewDiagram)

Return a sparse representation of the diagram xi, i.e. a sparse array A where A[i,j] == 1 if and only if (i,j) is in xi.lam but not in xi.mu.

source
diff --git a/versions.js b/versions.js index 22bb859428..de21b20b31 100644 --- a/versions.js +++ b/versions.js @@ -35,5 +35,5 @@ var DOC_VERSIONS = [ "v0.1", "dev", ]; -var DOCUMENTER_NEWEST = "v0.37.5"; +var DOCUMENTER_NEWEST = "v0.37.6"; var DOCUMENTER_STABLE = "stable";