├── .github └── workflows │ └── documentation.yml ├── .gitignore ├── AUTHORS.md ├── LICENSE.md ├── Project.toml ├── README.md ├── docs ├── Project.toml ├── build │ ├── assets │ │ ├── documenter.js │ │ ├── search.js │ │ ├── themes │ │ │ ├── documenter-dark.css │ │ │ └── documenter-light.css │ │ └── themeswap.js │ ├── index.html │ ├── search.html │ ├── search_index.js │ └── spop.html ├── make.jl └── src │ ├── cpop.md │ ├── index.md │ ├── opf.md │ ├── pmo.md │ ├── pop.md │ ├── sorf.md │ ├── sos.md │ ├── structure.md │ └── technique.md ├── example ├── PolyphaseCodeDesign.jl ├── SumOfRatios.jl ├── chebyshev.jl ├── cpop.jl ├── craig.jl ├── dynamicsystem.jl ├── hpop.jl ├── ljc.jl ├── maxnorm.jl ├── modelopf.jl ├── pmi.jl ├── poly.jl ├── polynomials.jl ├── psatz_linear.jl ├── qpm.jl ├── rhsos.jl ├── runopf.jl ├── sosprogram.jl ├── strengthen.jl └── symmetry.jl ├── src ├── CDK.jl ├── Chebyshev_basis.jl ├── TSSOS.jl ├── add_psatz.jl ├── blockpop.jl ├── chordal_extension.jl ├── clique_merge.jl ├── complex.jl ├── dynamic_system.jl ├── extract_solutions.jl ├── homogenize.jl ├── local_solution.jl ├── matrixsos.jl ├── nblockmix.jl ├── sum_of_ratios.jl ├── symmetry.jl └── utils.jl └── test ├── cpop_test.jl └── runtest.jl /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: '*' 8 | pull_request: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: julia-actions/setup-julia@latest 16 | with: 17 | version: '1' 18 | - name: Install dependencies 19 | shell: julia --project=docs/ {0} 20 | run: | 21 | using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate() 22 | - name: Build and deploy 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token 25 | DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # For authentication with SSH deploy key 26 | run: julia --project=docs/ docs/make.jl -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Manifest.toml -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | Jie Wang (AMSS-CAS Beijing) 2 | Victor Magron (LAAS CNRS Toulouse) 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2019] [Jie Wang, Victor Magron, and Jean B. Lasserre] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Project.toml: -------------------------------------------------------------------------------- 1 | name = "TSSOS" 2 | uuid = "81648402-ffe6-11e9-2394-0de17a9afdad" 3 | authors = ["jwang "] 4 | version = "1.4.5" 5 | 6 | [deps] 7 | AbstractAlgebra = "c3fe647b-3220-5bb0-a1ea-a7954cac585d" 8 | AbstractPermutations = "36d08e8a-54dd-435f-8c9e-38a475050b11" 9 | COSMO = "1e616198-aa4e-51ec-90a2-23f7fbd31d8d" 10 | CliqueTrees = "60701a23-6482-424a-84db-faee86b9b1f8" 11 | Dualization = "191a621a-6537-11e9-281d-650236a99e60" 12 | DynamicPolynomials = "7c1d4256-1411-5781-91ec-d7bc3513ac07" 13 | Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" 14 | Groebner = "0b43b601-686d-58a3-8a1c-6623616c7cd4" 15 | Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" 16 | JuMP = "4076af6c-e467-56ae-b986-b466b2749572" 17 | LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 18 | MetaGraphs = "626554b9-1ddb-594c-aa3c-2596fe9399a5" 19 | Mosek = "6405355b-0ac2-5fba-af84-adbd65488c0e" 20 | MosekTools = "1ec41992-ff65-5c91-ac43-2df89e9693a4" 21 | MultivariateBases = "be282fd4-ad43-11e9-1d11-8bd9d7e43378" 22 | MultivariatePolynomials = "102ac46a-7ee4-5c85-9060-abc95bfdeaa3" 23 | PermutationGroups = "8bc5a954-2dfc-11e9-10e6-cd969bffa420" 24 | Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" 25 | Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 26 | RowEchelon = "af85af4c-bcd5-5d23-b03a-a909639aa875" 27 | SemialgebraicSets = "8e049039-38e8-557d-ae3a-bc521ccf6204" 28 | SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" 29 | SymbolicWedderburn = "858aa9a9-4c7c-4c62-b466-2421203962a2" 30 | 31 | [compat] 32 | MultivariateBases = "0.2.2" 33 | -------------------------------------------------------------------------------- /docs/Project.toml: -------------------------------------------------------------------------------- 1 | [deps] 2 | Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" 3 | 4 | [compat] 5 | Documenter = "0.26" 6 | -------------------------------------------------------------------------------- /docs/build/assets/documenter.js: -------------------------------------------------------------------------------- 1 | // Generated by Documenter.jl 2 | requirejs.config({ 3 | paths: { 4 | 'highlight-julia': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/languages/julia.min', 5 | 'headroom': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.10.3/headroom.min', 6 | 'jqueryui': 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min', 7 | 'katex-auto-render': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/contrib/auto-render.min', 8 | 'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min', 9 | 'headroom-jquery': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.10.3/jQuery.headroom.min', 10 | 'katex': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min', 11 | 'highlight': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/highlight.min', 12 | 'highlight-julia-repl': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/languages/julia-repl.min', 13 | }, 14 | shim: { 15 | "highlight-julia": { 16 | "deps": [ 17 | "highlight" 18 | ] 19 | }, 20 | "katex-auto-render": { 21 | "deps": [ 22 | "katex" 23 | ] 24 | }, 25 | "headroom-jquery": { 26 | "deps": [ 27 | "jquery", 28 | "headroom" 29 | ] 30 | }, 31 | "highlight-julia-repl": { 32 | "deps": [ 33 | "highlight" 34 | ] 35 | } 36 | } 37 | }); 38 | //////////////////////////////////////////////////////////////////////////////// 39 | require(['jquery', 'katex', 'katex-auto-render'], function($, katex, renderMathInElement) { 40 | $(document).ready(function() { 41 | renderMathInElement( 42 | document.body, 43 | { 44 | "delimiters": [ 45 | { 46 | "left": "$", 47 | "right": "$", 48 | "display": false 49 | }, 50 | { 51 | "left": "$$", 52 | "right": "$$", 53 | "display": true 54 | }, 55 | { 56 | "left": "\\[", 57 | "right": "\\]", 58 | "display": true 59 | } 60 | ] 61 | } 62 | 63 | ); 64 | }) 65 | 66 | }) 67 | //////////////////////////////////////////////////////////////////////////////// 68 | require(['jquery', 'highlight', 'highlight-julia', 'highlight-julia-repl'], function($, hljs) { 69 | $(document).ready(function() { 70 | hljs.initHighlighting(); 71 | }) 72 | 73 | }) 74 | //////////////////////////////////////////////////////////////////////////////// 75 | require(['jquery', 'headroom', 'headroom-jquery'], function($, Headroom) { 76 | 77 | // Manages the top navigation bar (hides it when the user starts scrolling down on the 78 | // mobile). 79 | window.Headroom = Headroom; // work around buggy module loading? 80 | $(document).ready(function() { 81 | $('#documenter .docs-navbar').headroom({ 82 | "tolerance": {"up": 10, "down": 10}, 83 | }); 84 | }) 85 | 86 | }) 87 | //////////////////////////////////////////////////////////////////////////////// 88 | require(['jquery'], function($) { 89 | 90 | // Modal settings dialog 91 | $(document).ready(function() { 92 | var settings = $('#documenter-settings'); 93 | $('#documenter-settings-button').click(function(){ 94 | settings.toggleClass('is-active'); 95 | }); 96 | // Close the dialog if X is clicked 97 | $('#documenter-settings button.delete').click(function(){ 98 | settings.removeClass('is-active'); 99 | }); 100 | // Close dialog if ESC is pressed 101 | $(document).keyup(function(e) { 102 | if (e.keyCode == 27) settings.removeClass('is-active'); 103 | }); 104 | }); 105 | 106 | }) 107 | //////////////////////////////////////////////////////////////////////////////// 108 | require(['jquery'], function($) { 109 | 110 | // Manages the showing and hiding of the sidebar. 111 | $(document).ready(function() { 112 | var sidebar = $("#documenter > .docs-sidebar"); 113 | var sidebar_button = $("#documenter-sidebar-button") 114 | sidebar_button.click(function(ev) { 115 | ev.preventDefault(); 116 | sidebar.toggleClass('visible'); 117 | if (sidebar.hasClass('visible')) { 118 | // Makes sure that the current menu item is visible in the sidebar. 119 | $("#documenter .docs-menu a.is-active").focus(); 120 | } 121 | }); 122 | $("#documenter > .docs-main").bind('click', function(ev) { 123 | if ($(ev.target).is(sidebar_button)) { 124 | return; 125 | } 126 | if (sidebar.hasClass('visible')) { 127 | sidebar.removeClass('visible'); 128 | } 129 | }); 130 | }) 131 | 132 | // Resizes the package name / sitename in the sidebar if it is too wide. 133 | // Inspired by: https://github.com/davatron5000/FitText.js 134 | $(document).ready(function() { 135 | e = $("#documenter .docs-autofit"); 136 | function resize() { 137 | var L = parseInt(e.css('max-width'), 10); 138 | var L0 = e.width(); 139 | if(L0 > L) { 140 | var h0 = parseInt(e.css('font-size'), 10); 141 | e.css('font-size', L * h0 / L0); 142 | // TODO: make sure it survives resizes? 143 | } 144 | } 145 | // call once and then register events 146 | resize(); 147 | $(window).resize(resize); 148 | $(window).on('orientationchange', resize); 149 | }); 150 | 151 | // Scroll the navigation bar to the currently selected menu item 152 | $(document).ready(function() { 153 | var sidebar = $("#documenter .docs-menu").get(0); 154 | var active = $("#documenter .docs-menu .is-active").get(0); 155 | if(typeof active !== 'undefined') { 156 | sidebar.scrollTop = active.offsetTop - sidebar.offsetTop - 15; 157 | } 158 | }) 159 | 160 | }) 161 | //////////////////////////////////////////////////////////////////////////////// 162 | require(['jquery'], function($) { 163 | 164 | function set_theme(theme) { 165 | var active = null; 166 | var disabled = []; 167 | for (var i = 0; i < document.styleSheets.length; i++) { 168 | var ss = document.styleSheets[i]; 169 | var themename = ss.ownerNode.getAttribute("data-theme-name"); 170 | if(themename === null) continue; // ignore non-theme stylesheets 171 | // Find the active theme 172 | if(themename === theme) active = ss; 173 | else disabled.push(ss); 174 | } 175 | if(active !== null) { 176 | active.disabled = false; 177 | if(active.ownerNode.getAttribute("data-theme-primary") === null) { 178 | document.getElementsByTagName('html')[0].className = "theme--" + theme; 179 | } else { 180 | document.getElementsByTagName('html')[0].className = ""; 181 | } 182 | disabled.forEach(function(ss){ 183 | ss.disabled = true; 184 | }); 185 | } 186 | 187 | // Store the theme in localStorage 188 | if(typeof(window.localStorage) !== "undefined") { 189 | window.localStorage.setItem("documenter-theme", theme); 190 | } else { 191 | console.error("Browser does not support window.localStorage"); 192 | } 193 | } 194 | 195 | // Theme picker setup 196 | $(document).ready(function() { 197 | // onchange callback 198 | $('#documenter-themepicker').change(function themepick_callback(ev){ 199 | var themename = $('#documenter-themepicker option:selected').attr('value'); 200 | set_theme(themename); 201 | }); 202 | 203 | // Make sure that the themepicker displays the correct theme when the theme is retrieved 204 | // from localStorage 205 | if(typeof(window.localStorage) !== "undefined") { 206 | var theme = window.localStorage.getItem("documenter-theme"); 207 | if(theme !== null) { 208 | $('#documenter-themepicker option').each(function(i,e) { 209 | e.selected = (e.value === theme); 210 | }) 211 | } 212 | } 213 | }) 214 | 215 | }) 216 | //////////////////////////////////////////////////////////////////////////////// 217 | require(['jquery'], function($) { 218 | 219 | // update the version selector with info from the siteinfo.js and ../versions.js files 220 | $(document).ready(function() { 221 | var version_selector = $("#documenter .docs-version-selector"); 222 | var version_selector_select = $("#documenter .docs-version-selector select"); 223 | 224 | version_selector_select.change(function(x) { 225 | target_href = version_selector_select.children("option:selected").get(0).value; 226 | window.location.href = target_href; 227 | }); 228 | 229 | // add the current version to the selector based on siteinfo.js, but only if the selector is empty 230 | if (typeof DOCUMENTER_CURRENT_VERSION !== 'undefined' && $('#version-selector > option').length == 0) { 231 | var option = $(""); 232 | version_selector_select.append(option); 233 | } 234 | 235 | if (typeof DOC_VERSIONS !== 'undefined') { 236 | var existing_versions = version_selector_select.children("option"); 237 | var existing_versions_texts = existing_versions.map(function(i,x){return x.text}); 238 | DOC_VERSIONS.forEach(function(each) { 239 | var version_url = documenterBaseURL + "/../" + each; 240 | var existing_id = $.inArray(each, existing_versions_texts); 241 | // if not already in the version selector, add it as a new option, 242 | // otherwise update the old option with the URL and enable it 243 | if (existing_id == -1) { 244 | var option = $(""); 245 | version_selector_select.append(option); 246 | } else { 247 | var option = existing_versions[existing_id]; 248 | option.value = version_url; 249 | option.disabled = false; 250 | } 251 | }); 252 | } 253 | 254 | // only show the version selector if the selector has been populated 255 | if (version_selector_select.children("option").length > 0) { 256 | version_selector.toggleClass("visible"); 257 | } 258 | }) 259 | 260 | }) 261 | -------------------------------------------------------------------------------- /docs/build/assets/search.js: -------------------------------------------------------------------------------- 1 | // Generated by Documenter.jl 2 | requirejs.config({ 3 | paths: { 4 | 'lunr': 'https://cdnjs.cloudflare.com/ajax/libs/lunr.js/2.3.6/lunr.min', 5 | 'lodash': 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min', 6 | 'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min', 7 | } 8 | }); 9 | //////////////////////////////////////////////////////////////////////////////// 10 | require(['jquery', 'lunr', 'lodash'], function($, lunr, _) { 11 | 12 | $(document).ready(function() { 13 | // parseUri 1.2.2 14 | // (c) Steven Levithan 15 | // MIT License 16 | function parseUri (str) { 17 | var o = parseUri.options, 18 | m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), 19 | uri = {}, 20 | i = 14; 21 | 22 | while (i--) uri[o.key[i]] = m[i] || ""; 23 | 24 | uri[o.q.name] = {}; 25 | uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { 26 | if ($1) uri[o.q.name][$1] = $2; 27 | }); 28 | 29 | return uri; 30 | }; 31 | parseUri.options = { 32 | strictMode: false, 33 | key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], 34 | q: { 35 | name: "queryKey", 36 | parser: /(?:^|&)([^&=]*)=?([^&]*)/g 37 | }, 38 | parser: { 39 | strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, 40 | loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ 41 | } 42 | }; 43 | 44 | $("#search-form").submit(function(e) { 45 | e.preventDefault() 46 | }) 47 | 48 | // list below is the lunr 2.1.3 list minus the intersect with names(Base) 49 | // (all, any, get, in, is, only, which) and (do, else, for, let, where, while, with) 50 | // ideally we'd just filter the original list but it's not available as a variable 51 | lunr.stopWordFilter = lunr.generateStopWordFilter([ 52 | 'a', 53 | 'able', 54 | 'about', 55 | 'across', 56 | 'after', 57 | 'almost', 58 | 'also', 59 | 'am', 60 | 'among', 61 | 'an', 62 | 'and', 63 | 'are', 64 | 'as', 65 | 'at', 66 | 'be', 67 | 'because', 68 | 'been', 69 | 'but', 70 | 'by', 71 | 'can', 72 | 'cannot', 73 | 'could', 74 | 'dear', 75 | 'did', 76 | 'does', 77 | 'either', 78 | 'ever', 79 | 'every', 80 | 'from', 81 | 'got', 82 | 'had', 83 | 'has', 84 | 'have', 85 | 'he', 86 | 'her', 87 | 'hers', 88 | 'him', 89 | 'his', 90 | 'how', 91 | 'however', 92 | 'i', 93 | 'if', 94 | 'into', 95 | 'it', 96 | 'its', 97 | 'just', 98 | 'least', 99 | 'like', 100 | 'likely', 101 | 'may', 102 | 'me', 103 | 'might', 104 | 'most', 105 | 'must', 106 | 'my', 107 | 'neither', 108 | 'no', 109 | 'nor', 110 | 'not', 111 | 'of', 112 | 'off', 113 | 'often', 114 | 'on', 115 | 'or', 116 | 'other', 117 | 'our', 118 | 'own', 119 | 'rather', 120 | 'said', 121 | 'say', 122 | 'says', 123 | 'she', 124 | 'should', 125 | 'since', 126 | 'so', 127 | 'some', 128 | 'than', 129 | 'that', 130 | 'the', 131 | 'their', 132 | 'them', 133 | 'then', 134 | 'there', 135 | 'these', 136 | 'they', 137 | 'this', 138 | 'tis', 139 | 'to', 140 | 'too', 141 | 'twas', 142 | 'us', 143 | 'wants', 144 | 'was', 145 | 'we', 146 | 'were', 147 | 'what', 148 | 'when', 149 | 'who', 150 | 'whom', 151 | 'why', 152 | 'will', 153 | 'would', 154 | 'yet', 155 | 'you', 156 | 'your' 157 | ]) 158 | 159 | // add . as a separator, because otherwise "title": "Documenter.Anchors.add!" 160 | // would not find anything if searching for "add!", only for the entire qualification 161 | lunr.tokenizer.separator = /[\s\-\.]+/ 162 | 163 | // custom trimmer that doesn't strip @ and !, which are used in julia macro and function names 164 | lunr.trimmer = function (token) { 165 | return token.update(function (s) { 166 | return s.replace(/^[^a-zA-Z0-9@!]+/, '').replace(/[^a-zA-Z0-9@!]+$/, '') 167 | }) 168 | } 169 | 170 | lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'juliaStopWordFilter') 171 | lunr.Pipeline.registerFunction(lunr.trimmer, 'juliaTrimmer') 172 | 173 | var index = lunr(function () { 174 | this.ref('location') 175 | this.field('title',{boost: 100}) 176 | this.field('text') 177 | documenterSearchIndex['docs'].forEach(function(e) { 178 | this.add(e) 179 | }, this) 180 | }) 181 | var store = {} 182 | 183 | documenterSearchIndex['docs'].forEach(function(e) { 184 | store[e.location] = {title: e.title, category: e.category} 185 | }) 186 | 187 | $(function(){ 188 | searchresults = $('#documenter-search-results'); 189 | searchinfo = $('#documenter-search-info'); 190 | searchbox = $('#documenter-search-query'); 191 | function update_search(querystring) { 192 | tokens = lunr.tokenizer(querystring) 193 | results = index.query(function (q) { 194 | tokens.forEach(function (t) { 195 | q.term(t.toString(), { 196 | fields: ["title"], 197 | boost: 100, 198 | usePipeline: true, 199 | editDistance: 0, 200 | wildcard: lunr.Query.wildcard.NONE 201 | }) 202 | q.term(t.toString(), { 203 | fields: ["title"], 204 | boost: 10, 205 | usePipeline: true, 206 | editDistance: 2, 207 | wildcard: lunr.Query.wildcard.NONE 208 | }) 209 | q.term(t.toString(), { 210 | fields: ["text"], 211 | boost: 1, 212 | usePipeline: true, 213 | editDistance: 0, 214 | wildcard: lunr.Query.wildcard.NONE 215 | }) 216 | }) 217 | }) 218 | searchinfo.text("Number of results: " + results.length) 219 | searchresults.empty() 220 | results.forEach(function(result) { 221 | data = store[result.ref] 222 | link = $(''+data.title+'') 223 | link.attr('href', documenterBaseURL+'/'+result.ref) 224 | cat = $('('+data.category+')') 225 | li = $('
  • ').append(link).append(" ").append(cat) 226 | searchresults.append(li) 227 | }) 228 | } 229 | 230 | function update_search_box() { 231 | querystring = searchbox.val() 232 | update_search(querystring) 233 | } 234 | 235 | searchbox.keyup(_.debounce(update_search_box, 250)) 236 | searchbox.change(update_search_box) 237 | 238 | search_query_uri = parseUri(window.location).queryKey["q"] 239 | if(search_query_uri !== undefined) { 240 | search_query = decodeURIComponent(search_query_uri.replace(/\+/g, '%20')) 241 | searchbox.val(search_query) 242 | } 243 | update_search_box(); 244 | }) 245 | }) 246 | 247 | }) 248 | -------------------------------------------------------------------------------- /docs/build/assets/themeswap.js: -------------------------------------------------------------------------------- 1 | // Small function to quickly swap out themes. Gets put into the tag.. 2 | function set_theme_from_local_storage() { 3 | // Browser does not support Web Storage, bail early. 4 | if(typeof(window.localStorage) === "undefined") return; 5 | // Get the user-picked theme from localStorage. May be `null`, which means the default 6 | // theme. 7 | var theme = window.localStorage.getItem("documenter-theme"); 8 | // Initialize a few variables for the loop: 9 | // 10 | // - active: will contain the index of the theme that should be active. Note that there 11 | // is no guarantee that localStorage contains sane values. If `active` stays `null` 12 | // we either could not find the theme or it is the default (primary) theme anyway. 13 | // Either way, we then need to stick to the primary theme. 14 | // 15 | // - disabled: style sheets that should be disabled (i.e. all the theme style sheets 16 | // that are not the currently active theme) 17 | var active = null; var disabled = []; 18 | for (var i = 0; i < document.styleSheets.length; i++) { 19 | var ss = document.styleSheets[i]; 20 | // The tag of each style sheet is expected to have a data-theme-name attribute 21 | // which must contain the name of the theme. The names in localStorage much match this. 22 | var themename = ss.ownerNode.getAttribute("data-theme-name"); 23 | // attribute not set => non-theme stylesheet => ignore 24 | if(themename === null) continue; 25 | // To distinguish the default (primary) theme, it needs to have the data-theme-primary 26 | // attribute set. 27 | var isprimary = (ss.ownerNode.getAttribute("data-theme-primary") !== null); 28 | // If we find a matching theme (and it's not the default), we'll set active to non-null 29 | if(!isprimary && themename === theme) active = i; 30 | // Store the style sheets of inactive themes so that we could disable them 31 | if(themename !== theme) disabled.push(ss); 32 | } 33 | if(active !== null) { 34 | // If we did find an active theme, we'll (1) add the theme--$(theme) class to 35 | document.getElementsByTagName('html')[0].className = "theme--" + theme; 36 | // and (2) disable all the other theme stylesheets 37 | disabled.forEach(function(ss){ 38 | ss.disabled = true; 39 | }); 40 | } 41 | } 42 | set_theme_from_local_storage(); 43 | -------------------------------------------------------------------------------- /docs/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | Home · TSSOS

    TSSOS

    TSSOS is a sparse polynomial optimization package based on the sparsity adapted moment-SOS hierarchies.


    Authors

    Installation

    TSSOS is simply installed by running

    pkg> add https://github.com/wangjie212/TSSOS

    References

    1. TSSOS: A Moment-SOS hierarchy that exploits term sparsity, Jie Wang, Victor Magron and Jean B. Lasserre, 2020.
    2. Chordal-TSSOS: a moment-SOS hierarchy that exploits term sparsity with chordal extension, Jie Wang, Victor Magron and Jean B. Lasserre, 2020.
    3. CS-TSSOS: Correlative and term sparsity for large-scale polynomial optimization, Jie Wang, Victor Magron, Jean B. Lasserre and Ngoc H. A. Mai, 2020.
    3 | -------------------------------------------------------------------------------- /docs/build/search.html: -------------------------------------------------------------------------------- 1 | 2 | Search · TSSOS

    Loading search...

      3 | -------------------------------------------------------------------------------- /docs/build/search_index.js: -------------------------------------------------------------------------------- 1 | var documenterSearchIndex = {"docs": 2 | [{"location":"index.html#TSSOS","page":"Home","title":"TSSOS","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"TSSOS is a sparse polynomial optimization package based on the sparsity adapted moment-SOS hierarchies.","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"","category":"page"},{"location":"index.html#Authors","page":"Home","title":"Authors","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"Jie Wang, LAAS-CNRS.","category":"page"},{"location":"index.html#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"TSSOS is simply installed by running","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"pkg> add https://github.com/wangjie212/TSSOS","category":"page"},{"location":"index.html#Related-packages","page":"Home","title":"Related packages","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"DynamicPolynomials: Polynomial definition\nMultivariatePolynomials: Polynomials manipulations\nNCTSSOS: Noncommutative polynomial optimization\nChordalGraph: Chordal graphs and chordal extentions\nSparseJSR: Computing joint spetral radius","category":"page"},{"location":"index.html#References","page":"Home","title":"References","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"TSSOS: A Moment-SOS hierarchy that exploits term sparsity, Jie Wang, Victor Magron and Jean B. Lasserre, 2020.\nChordal-TSSOS: a moment-SOS hierarchy that exploits term sparsity with chordal extension, Jie Wang, Victor Magron and Jean B. Lasserre, 2020.\nCS-TSSOS: Correlative and term sparsity for large-scale polynomial optimization, Jie Wang, Victor Magron, Jean B. Lasserre and Ngoc H. A. Mai, 2020.","category":"page"},{"location":"spop.html#Sparse-polynomial-optimization","page":"Sparse Polynomial Optimization","title":"Sparse polynomial optimization","text":"","category":"section"},{"location":"spop.html","page":"Sparse Polynomial Optimization","title":"Sparse Polynomial Optimization","text":"tssos_first\r\ntssos_higher!\r\ncs_tssos_first\r\ncs_tssos_higher!\r\nrefine_sol","category":"page"},{"location":"spop.html#TSSOS.tssos_first","page":"Sparse Polynomial Optimization","title":"TSSOS.tssos_first","text":"opt,sol,data = tssos_first(f, x; nb=0, newton=true, reducebasis=false, TS=\"block\", merge=false,\nsolver=\"Mosek\", QUIET=false, solve=true, MomentOne=false, solution=false, tol=1e-4)\n\nCompute the first step of the TSSOS hierarchy for unconstrained polynomial optimization. If newton=true, then compute a monomial basis by the Newton polytope method. If reducebasis=true, then remove monomials from the monomial basis by diagonal inconsistency. If TS=\"block\", use maximal chordal extensions; if TS=\"MD\", use approximately smallest chordal extensions. If merge=true, perform the PSD block merging. If MomentOne=true, add an extra first order moment matrix to the moment relaxation. Return the optimum, the (near) optimal solution (if solution=true) and other data.\n\nArguments\n\nf: the objective function for unconstrained polynomial optimization.\nx: the set of variables.\nnb: the number of binary variables in x.\ntol: the relative tolerance to certify global optimality.\n\n\n\n\n\nopt,sol,data = tssos_first(pop, x, d; nb=0, numeq=0, quotient=true, basis=nothing,\nreducebasis=false, TS=\"block\", merge=false, solver=\"Mosek\", QUIET=false, solve=true,\nMomentOne=false, solution=false, tol=1e-4)\n\nCompute the first step of the TSSOS hierarchy for constrained polynomial optimization with relaxation order d. If quotient=true, then exploit the quotient ring structure defined by the equality constraints. Return the optimum, the (near) optimal solution (if solution=true) and other data.\n\nArguments\n\npop: the vector of the objective function, inequality constraints, and equality constraints.\nx: the set of variables.\nd: the relaxation order of the moment-SOS hierarchy.\nnb: the number of binary variables in x.\nnumeq: the number of equality constraints.\n\n\n\n\n\n","category":"function"},{"location":"spop.html#TSSOS.tssos_higher!","page":"Sparse Polynomial Optimization","title":"TSSOS.tssos_higher!","text":"opt,sol,data = tssos_higher!(data; TS=\"block\", merge=false, QUIET=false, solve=true,\nMomentOne=false, solution=false, tol=1e-4)\n\nCompute higher steps of the TSSOS hierarchy. Return the optimum, the (near) optimal solution (if solution=true) and other data.\n\n\n\n\n\n","category":"function"},{"location":"spop.html#TSSOS.cs_tssos_first","page":"Sparse Polynomial Optimization","title":"TSSOS.cs_tssos_first","text":"opt,sol,data = cs_tssos_first(pop, x, d; nb=0, numeq=0, foc=100, CS=\"MF\", minimize=true,\nassign=\"first\", TS=\"block\", solver=\"Mosek\", QUIET=false, solve=true, solution=false,\nMomentOne=true, tol=1e-4)\n\nCompute the first step of the CS-TSSOS hierarchy for constrained polynomial optimization with relaxation order d.\n\nArguments\n\npop: the vector of the objective function, inequality constraints, and equality constraints.\nx: the set of variables.\nd: the relaxation order of the moment-SOS hierarchy.\nnb: the number of binary variables in x.\nnumeq: the number of equality constraints.\n\n\n\n\n\nopt,sol,data = cs_tssos_first(supp::Vector{Vector{Vector{UInt16}}}, coe::Vector{Vector{Float64}},\nn, d; numeq=0, nb=0, foc=100, CS=\"MF\", minimize=true, assign=\"first\", TS=\"block\", QUIET=false,\nsolver=\"Mosek\", solve=true, solution=false, MomentOne=true, tol=1e-4)\n\nCompute the first step of the CS-TSSOS hierarchy for constrained polynomial optimization with relaxation order d. Here the polynomial optimization problem is defined by supp and coe, corresponding to the supports and coeffients of pop respectively.\n\nArguments\n\npop: the vector of the objective function, inequality constraints, and equality constraints.\nx: the set of variables.\nd: the relaxation order of the moment-SOS hierarchy.\nnb: the number of binary variables in x.\nnumeq: the number of equality constraints.\n\n\n\n\n\n","category":"function"},{"location":"spop.html#TSSOS.cs_tssos_higher!","page":"Sparse Polynomial Optimization","title":"TSSOS.cs_tssos_higher!","text":"opt,sol,data = cs_tssos_higher!(data; TS=\"block\", QUIET=false, solve=true,\nsolution=false, MomentOne=false)\n\nCompute higher steps of the CS-TSSOS hierarchy. Return the optimum, the (near) optimal solution (if solution=true) and other data.\n\n\n\n\n\n","category":"function"},{"location":"spop.html#TSSOS.refine_sol","page":"Sparse Polynomial Optimization","title":"TSSOS.refine_sol","text":"ref_sol,upper_bound,rel_gap = refine_sol(opt, sol, data, QUIET=false, tol=1e-4)\n\nRefine the obtained solution by a local solver. Return the refined solution, the upper bound given by the local solver and the relative optimality gap.\n\n\n\n\n\n","category":"function"}] 3 | } 4 | -------------------------------------------------------------------------------- /docs/build/spop.html: -------------------------------------------------------------------------------- 1 | 2 | Sparse Polynomial Optimization · TSSOS

      Sparse polynomial optimization

      TSSOS.tssos_firstFunction
      opt,sol,data = tssos_first(f, x; nb=0, newton=true, reducebasis=false, TS="block", merge=false,
       3 | solver="Mosek", QUIET=false, solve=true, MomentOne=false, solution=false, tol=1e-4)

      Compute the first step of the TSSOS hierarchy for unconstrained polynomial optimization. If newton=true, then compute a monomial basis by the Newton polytope method. If reducebasis=true, then remove monomials from the monomial basis by diagonal inconsistency. If TS="block", use maximal chordal extensions; if TS="MD", use approximately smallest chordal extensions. If merge=true, perform the PSD block merging. If MomentOne=true, add an extra first order moment matrix to the moment relaxation. Return the optimum, the (near) optimal solution (if solution=true) and other data.

      Arguments

      • f: the objective function for unconstrained polynomial optimization.
      • x: the set of variables.
      • nb: the number of binary variables in x.
      • tol: the relative tolerance to certify global optimality.
      opt,sol,data = tssos_first(pop, x, d; nb=0, numeq=0, quotient=true, basis=nothing,
       4 | reducebasis=false, TS="block", merge=false, solver="Mosek", QUIET=false, solve=true,
       5 | MomentOne=false, solution=false, tol=1e-4)

      Compute the first step of the TSSOS hierarchy for constrained polynomial optimization with relaxation order d. If quotient=true, then exploit the quotient ring structure defined by the equality constraints. Return the optimum, the (near) optimal solution (if solution=true) and other data.

      Arguments

      • pop: the vector of the objective function, inequality constraints, and equality constraints.
      • x: the set of variables.
      • d: the relaxation order of the moment-SOS hierarchy.
      • nb: the number of binary variables in x.
      • numeq: the number of equality constraints.
      TSSOS.tssos_higher!Function
      opt,sol,data = tssos_higher!(data; TS="block", merge=false, QUIET=false, solve=true,
       6 | MomentOne=false, solution=false, tol=1e-4)

      Compute higher steps of the TSSOS hierarchy. Return the optimum, the (near) optimal solution (if solution=true) and other data.

      TSSOS.cs_tssos_firstFunction
      opt,sol,data = cs_tssos_first(pop, x, d; nb=0, numeq=0, foc=100, CS="MF", minimize=true,
       7 | assign="first", TS="block", solver="Mosek", QUIET=false, solve=true, solution=false,
       8 | MomentOne=true, tol=1e-4)

      Compute the first step of the CS-TSSOS hierarchy for constrained polynomial optimization with relaxation order d.

      Arguments

      • pop: the vector of the objective function, inequality constraints, and equality constraints.
      • x: the set of variables.
      • d: the relaxation order of the moment-SOS hierarchy.
      • nb: the number of binary variables in x.
      • numeq: the number of equality constraints.
      opt,sol,data = cs_tssos_first(supp::Vector{Vector{Vector{UInt16}}}, coe::Vector{Vector{Float64}},
       9 | n, d; numeq=0, nb=0, foc=100, CS="MF", minimize=true, assign="first", TS="block", QUIET=false,
      10 | solver="Mosek", solve=true, solution=false, MomentOne=true, tol=1e-4)

      Compute the first step of the CS-TSSOS hierarchy for constrained polynomial optimization with relaxation order d. Here the polynomial optimization problem is defined by supp and coe, corresponding to the supports and coeffients of pop respectively.

      Arguments

      • pop: the vector of the objective function, inequality constraints, and equality constraints.
      • x: the set of variables.
      • d: the relaxation order of the moment-SOS hierarchy.
      • nb: the number of binary variables in x.
      • numeq: the number of equality constraints.
      TSSOS.cs_tssos_higher!Function
      opt,sol,data = cs_tssos_higher!(data; TS="block", QUIET=false, solve=true,
      11 | solution=false, MomentOne=false)

      Compute higher steps of the CS-TSSOS hierarchy. Return the optimum, the (near) optimal solution (if solution=true) and other data.

      TSSOS.refine_solFunction
      ref_sol,upper_bound,rel_gap = refine_sol(opt, sol, data, QUIET=false, tol=1e-4)

      Refine the obtained solution by a local solver. Return the refined solution, the upper bound given by the local solver and the relative optimality gap.

      12 | -------------------------------------------------------------------------------- /docs/make.jl: -------------------------------------------------------------------------------- 1 | using Documenter 2 | using TSSOS 3 | 4 | makedocs( 5 | sitename = "TSSOS", 6 | pages = ["Home" => "index.md", 7 | "Polynomial Optimization" => "pop.md", 8 | "Structures" => "structure.md", 9 | "Techniques" => "technique.md", 10 | "Sum-Of-Squares Optimization" => "sos.md", 11 | "Polynomial Matrix Optimization" => "pmo.md", 12 | "Complex Polynomial Optimization" => "cpop.md", 13 | "Examples" => ["AC Optimal Power Flow" => "opf.md", 14 | "Sum-Of-Rational-Functions Optimization" => "sorf.md", 15 | ], 16 | ], 17 | modules = [TSSOS], 18 | format = Documenter.HTML( 19 | prettyurls = get(ENV, "CI", nothing) == "true") 20 | ) 21 | 22 | deploydocs( 23 | repo = "github.com/wangjie212/TSSOS.git" 24 | ) 25 | -------------------------------------------------------------------------------- /docs/src/cpop.md: -------------------------------------------------------------------------------- 1 | # Complex Polynomial Optimization 2 | 3 | A general complex polynomial optimization problem could be formulized as 4 | 5 | $$\mathrm{inf}_{\mathbf{z}\in\mathbf{K}}\ f(\mathbf{z},\bar{\mathbf{z}}),$$ 6 | 7 | with 8 | 9 | $$\mathbf{K}\coloneqq\lbrace \mathbf{z}\in\mathbb{C}^n \mid g_i(\mathbf{z},\bar{\mathbf{z}})\ge0, i=1,\ldots,m,\ h_j(\mathbf{z},\bar{\mathbf{z}})=0, j=1,\ldots,\ell\rbrace,$$ 10 | 11 | where $\bar{\mathbf{z}}$ stands for the conjugate of $\mathbf{z}:=(z_1,\ldots,z_n)$, and $f, g_i, i=1,\ldots,m, h_j, j=1,\ldots,\ell$ are real-valued complex polynomials satisfying $\bar{f}=f$ and $\bar{g}_i=g_i$, $\bar{h}_j=h_j$. 12 | 13 | Let us consider the following example: 14 | 15 | $$\mathrm{inf}\ 3-|z_1|^2-0.5\mathbf{i}z_1\bar{z}_2^2+0.5\mathbf{i}z_2^2\bar{z}_1$$ 16 | 17 | $$\mathrm{s.t.}\ z_2+\bar{z}_2\ge0,|z_1|^2-0.25z_1^2-0.25\bar{z}_1^2=1,|z_1|^2+|z_2|^2=3,\mathbf{i}z_2-\mathbf{i}\bar{z}_2=0.$$ 18 | 19 | ```Julia 20 | using DynamicPolynomials 21 | n = 2 # set the number of complex variables 22 | @complex_polyvar z[1:n] 23 | f = 3 - x[1]*conj(x[1]) - 0.5im*x[1]*conj(x[2])^2 + 0.5im*x[2]^2*conj(x[1]) 24 | g1 = x[2] + conj(x[2]) 25 | g2 = x[1]*conj(x[1]) - 0.25*x[1]^2 - 0.25*conj(x[1])^2 - 1 26 | g3 = x[1]*conj(x[1]) + x[2]*conj(x[2]) - 3 27 | g4 = im*x[2] - im*conj(x[2]) 28 | pop = [f, g1, g2, g3, g4] 29 | order = 2 # set the relaxation order 30 | opt,sol,data = complex_tssos_first(pop, z, order, numeq=3, TS="block", solution=true) # no correlative sparsity 31 | opt,sol,data = complex_cs_tssos_first(pop, z, order, numeq=3, TS="block", solution=true) 32 | ``` 33 | 34 | ### Keyword arguments 35 | Argument | Description | Default value 36 | --- | :--- | :--- 37 | nb | Specify the first **nb** complex variables to be of unit norm | 0 38 | numeq | Specify the last **numeq** constraints to be equality constraints | 0 39 | CS | Types of chordal extensions in exploiting correlative sparsity: "MF" (approximately smallest chordal extension), "NC" (not performing chordal extension), false (invalidating correlative sparsity exploitation) | "MF" 40 | cliques | Use customized variable cliques | [] 41 | TS | Types of chordal extensions used in term sparsity iterations: "block"(maximal chordal extension), "MD" (approximately smallest chordal extension), false (invalidating term sparsity iterations) | "block" 42 | ConjugateBasis | include conjugate variables in monomial bases | false 43 | normality | Impose normality condtions of order **normality** | 1 44 | merge | Merge overlapping PSD blocks | false 45 | md | Parameter for tunning the merging strength | 3 46 | MomentOne | add a first-order moment PSD constraint for each variable clique | false 47 | solver | Specify an SDP solver: "Mosek" or "COSMO" | "Mosek" 48 | cosmo\_setting | Parameters for the COSMO solver: cosmo\_para(eps\_abs, eps\_rel, max\_iter, time\_limit) | cosmo\_para(1e-5, 1e-5, 1e4, 0) 49 | mosek\_setting | Parameters for the Mosek solver: mosek\_para(tol\_pfeas, tol\_dfeas, tol\_relgap, time\_limit, num\_threads) | mosek\_para(1e-8, 1e-8, 1e-8, -1, 0) 50 | QUIET | Silence the output| false 51 | solve | Solve the SDP relaxation | true 52 | dualize | Solve the dual SDP problem | false 53 | Gram | Output Gram matrices | false 54 | solution | Extract an optimal solution | false 55 | rtol | tolerance for rank | 1e-2 56 | gtol | tolerance for global optimality gap | 1e-2 57 | ftol | tolerance for feasibility | 1e-3 58 | 59 | ### References 60 | 61 | 1. [Exploiting Sparsity in Complex Polynomial Optimization](https://link.springer.com/article/10.1007/s10957-021-01975-z), Jie Wang and Victor Magron, 2021. -------------------------------------------------------------------------------- /docs/src/index.md: -------------------------------------------------------------------------------- 1 | # TSSOS 2 | 3 | [TSSOS](https://github.com/wangjie212/TSSOS) aims to provide a user-friendly and efficient tool for solving optimization problems with polynomials, which is based on the structured moment-SOS hierarchy. 4 | 5 | ### Authors 6 | 7 | - [Jie Wang](https://wangjie212.github.io/jiewang), Academy of Mathematics and Systems Science, Chinese Academy of Sciences. 8 | 9 | - [Victor Magron](https://homepages.laas.fr/vmagron), Laboratoire d'Architecture et Analyse des Systèmes, CNRS. 10 | 11 | ### Installation 12 | 13 | [TSSOS](https://github.com/wangjie212/TSSOS) could be installed by running 14 | 15 | ```julia 16 | pkg> add https://github.com/wangjie212/TSSOS 17 | ``` 18 | 19 | ### Related packages 20 | 21 | - [DynamicPolynomials](https://github.com/JuliaAlgebra/DynamicPolynomials.jl): Polynomial definition 22 | - [MultivariatePolynomials](https://github.com/JuliaAlgebra/MultivariatePolynomials.jl): Polynomial manipulation 23 | - [NCTSSOS](https://github.com/wangjie212/NCTSSOS): Noncommutative polynomial optimization 24 | - [ChordalGraph](https://github.com/wangjie212/ChordalGraph): Chordal graphs and chordal extentions 25 | - [SparseJSR](https://github.com/wangjie212/SparseJSR): Computing joint spetral radius 26 | 27 | ### References 28 | 29 | 1. [TSSOS: A Moment-SOS hierarchy that exploits term sparsity](https://epubs.siam.org/doi/abs/10.1137/19M1307871), Jie Wang, Victor Magron, and Jean B. Lasserre, 2021. 30 | 2. [Chordal-TSSOS: a moment-SOS hierarchy that exploits term sparsity with chordal extension](https://epubs.siam.org/doi/10.1137/20M1323564), Jie Wang, Victor Magron, and Jean B. Lasserre, 2021. 31 | 3. [CS-TSSOS: Correlative and term sparsity for large-scale polynomial optimization](https://dl.acm.org/doi/abs/10.1145/3569709), Jie Wang, Victor Magron, Jean B. Lasserre, and Ngoc H. A. Mai, 2022. 32 | 4. [TSSOS: a Julia library to exploit sparsity for large-scale polynomial optimization](https://arxiv.org/abs/2103.00915), Victor Magron and Jie Wang, 2021. 33 | -------------------------------------------------------------------------------- /docs/src/opf.md: -------------------------------------------------------------------------------- 1 | # AC Optimal Power Flow -------------------------------------------------------------------------------- /docs/src/pmo.md: -------------------------------------------------------------------------------- 1 | # Polynomial Matrix Optimization 2 | 3 | The polynomial matrix optimization problem aims to minimize the smallest eigenvalue of a polynomial matrix subject to a tuple of polynomial matrix inequalties (PMIs), which could be formulized as 4 | 5 | $$\mathrm{inf}_{\mathbf{x}\in\mathbf{K}}\ \lambda_{\mathrm{min}}(F(\mathbf{x})),$$ 6 | 7 | where $F\in\mathbb{S}[\mathbf{x}]^p$ is a $p\times p$ symmetric polynomial matrix and $\mathbf{K}$ is the basic semialgebraic set 8 | 9 | $$\mathbf{K}\coloneqq\lbrace \mathbf{x}\in\mathbb{R}^n \mid G_j(\mathbf{x})\succeq0, j=1,\ldots,m\rbrace,$$ 10 | 11 | for some symmetric polynomial matrices $G_j\in\mathbb{S}[\mathbf{x}]^{q_j}, j=1,\ldots,m$. Note that when $p=1$, $\lambda_{\min}(F(\mathbf{x}))=F(\mathbf{x})$. More generally, one may consider 12 | 13 | $$\mathrm{inf}_{\mathbf{y}\in\mathbb{R}^t}\ \mathbf{c}^{\intercal}\mathbf{y}$$ 14 | 15 | $$\mathrm{s.t.}\ F_{0}(\mathbf{x})+y_1F_{1}(\mathbf{x})+\cdots+y_tF_{t}(\mathbf{x})\succeq0 \textrm{ on } K,$$ 16 | 17 | where $F_i\in\mathbb{S}[\mathbf{x}]^{p}, i=0,1,\ldots,t$ are a tuple of symmetric polynomial matrices. 18 | 19 | The following is a simple exmaple. 20 | 21 | ```Julia 22 | using DynamicPolynomials 23 | using TSSOS 24 | 25 | @polyvar x[1:5] 26 | F = [x[1]^4 x[1]^2 - x[2]*x[3] x[3]^2 - x[4]*x[5] x[1]*x[4] x[1]*x[5]; 27 | x[1]^2 - x[2]*x[3] x[2]^4 x[2]^2 - x[3]*x[4] x[2]*x[4] x[2]*x[5]; 28 | x[3]^2 - x[4]*x[5] x[2]^2 - x[3]*x[4] x[3]^4 x[4]^2 - x[1]*x[2] x[5]^2 - x[3]*x[5]; 29 | x[1]*x[4] x[2]*x[4] x[4]^2 - x[1]*x[2] x[4]^4 x[4]^2 - x[1]*x[3]; 30 | x[1]*x[5] x[2]*x[5] x[5]^2 - x[3]*x[5] x[4]^2 - x[1]*x[3] x[5]^4] 31 | G = Vector{Matrix{Polynomial{true, Int}}}(undef, 2) 32 | G[1] = [1 - x[1]^2 - x[2]^2 x[2]*x[3]; x[2]*x[3] 1 - x[3]^2] 33 | G[2] = [1 - x[4]^2 x[4]*x[5]; x[4]*x[5] 1 - x[5]^2] 34 | @time opt,data = tssos_first(F, G, x, 3, TS="MD") # compute the first TS step of the TSSOS hierarchy 35 | @time opt,data = tssos_higher!(data, TS="MD") # compute higher TS steps of the TSSOS hierarchy 36 | ``` 37 | 38 | ### Keyword arguments 39 | Argument | Description | Default value 40 | --- | :--- | :--- 41 | CS | Types of chordal extensions in exploiting correlative sparsity: "MF" (approximately smallest chordal extension), "NC" (not performing chordal extension), false (invalidating correlative sparsity exploitation) | "MF" 42 | cliques | Use customized variable cliques | [] 43 | TS | Types of chordal extensions used in term sparsity iterations: "block"(maximal chordal extension), "MD" (approximately smallest chordal extension), false (invalidating term sparsity iterations) | "block" 44 | QUIET | Silence the output| false 45 | solve | Solve the SDP relaxation | true 46 | Gram | Output Gram matrices | false 47 | 48 | ### References 49 | 50 | 1. [Sparse Polynomial Matrix Optimization](https://arxiv.org/abs/2411.15479), Jared Miller, Jie Wang, and Feng Guo, 2024. -------------------------------------------------------------------------------- /docs/src/pop.md: -------------------------------------------------------------------------------- 1 | # Polynomial Optimization 2 | 3 | Polynomial optimization concerns minimizing a polynomial subject to a tuple of polynomial inequality constraints and equality constraints, which in general takes the form: 4 | 5 | $$\mathrm{inf}_{\mathbf{x}\in\mathbb{R}^n}\ f(\mathbf{x})\ \text{ s.t. }\ g_1(\mathbf{x})\ge0,\ldots,g_m(\mathbf{x})\ge0,h_1(\mathbf{x})=0,\ldots,h_{\ell}(\mathbf{x})=0,$$ 6 | 7 | where $f,g_1,\ldots,g_m,h_1,\ldots,h_{\ell}\in\mathbb{R}[\mathbf{x}]$ are polynomials in variables $\mathbf{x}$. 8 | 9 | To illustrate how to solve a polynomial optimization problem with TSSOS, let us consider $f=1+x_1^4+x_2^4+x_3^4+x_1x_2x_3+x_2$ and $g=1-x_1^2-2x_2^2, h=x_2^2+x_3^2-1$. 10 | 11 | ```Julia 12 | @polyvar x[1:3] 13 | f = 1 + x[1]^4 + x[2]^4 + x[3]^4 + x[1]*x[2]*x[3] + x[2] 14 | g = 1 - x[1]^2 - 2*x[2]^2 15 | h = x[2]^2 + x[3]^2 - 1 16 | pop = [f, g, h] 17 | d = 2 # set the relaxation order 18 | opt,sol,data = tssos_first(pop, x, d, numeq=1, TS="block", solution=true) # compute the first TS step of the TSSOS hierarchy 19 | opt,sol,data = tssos_higher!(data, TS="block", solution=true) # compute higher TS steps of the TSSOS hierarchy 20 | ``` 21 | 22 | ### Keyword arguments 23 | Argument | Description | Default value 24 | --- | :--- | :--- 25 | nb | Specify the first **nb** variables to be $\pm1$ binary variables | 0 26 | numeq | Specify the last **numeq** constraints to be equality constraints | 0 27 | GroebnerBasis | Work in the quotient ring by computing a Gröbner basis | true 28 | basis | Use customized monomial bases | [] 29 | reducebasis | Reduce the monomial bases | false 30 | TS | Types of chordal extensions used in term sparsity iterations: "block"(maximal chordal extension), "signsymmetry" (sign symmetries), "MD" (approximately smallest chordal extension), false (invalidating term sparsity exploitation) | "block" 31 | normality | Impose normality condtions | false 32 | merge | Merge overlapping PSD blocks | false 33 | md | Parameter for tunning the merging strength | 3 34 | MomentOne | add a first-order moment PSD constraint | false 35 | solver | Specify an SDP solver: "Mosek" or "COSMO" | "Mosek" 36 | cosmo\_setting | Parameters for the COSMO solver: cosmo\_para(eps\_abs, eps\_rel, max\_iter, time\_limit) | cosmo\_para(1e-5, 1e-5, 1e4, 0) 37 | mosek\_setting | Parameters for the Mosek solver: mosek\_para(tol\_pfeas, tol\_dfeas, tol\_relgap, time\_limit, num\_threads) | mosek\_para(1e-8, 1e-8, 1e-8, -1, 0) 38 | QUIET | Silence the output| false 39 | solve | Solve the SDP relaxation | true 40 | dualize | Solve the dual SDP problem | false 41 | Gram | Output Gram matrices | false 42 | solution | Extract optimal solutions | false 43 | rtol | tolerance for rank | 1e-2 44 | gtol | tolerance for global optimality gap | 1e-2 45 | ftol | tolerance for feasibility | 1e-3 46 | 47 | ## Correlative sparsity 48 | The following is an example where one exploits correlative sparsity and term sparsity simultaneously. 49 | 50 | ```Julia 51 | using DynamicPolynomials 52 | n = 6 53 | @polyvar x[1:n] 54 | f = 1 + sum(x.^4) + x[1]*x[2]*x[3] + x[3]*x[4]*x[5] + x[3]*x[4]*x[6]+x[3]*x[5]*x[6] + x[4]*x[5]*x[6] 55 | pop = [f, 1-sum(x[1:3].^2), 1-sum(x[3:6].^2)] 56 | order = 2 # set the relaxation order 57 | opt,sol,data = cs_tssos_first(pop, x, order, numeq=0, TS="MD", solution=true) # compute the first TS step of the CS-TSSOS hierarchy 58 | opt,sol,data = cs_tssos_higher!(data, TS="MD", solution=true) # compute higher TS steps of the CS-TSSOS hierarchy 59 | ``` 60 | 61 | ### Keyword arguments 62 | Argument | Description | Default value 63 | --- | :--- | :--- 64 | nb | Specify the first **nb** variables to be $\pm1$ binary variables | 0 65 | numeq | Specify the last **numeq** constraints to be equality constraints | 0 66 | CS | Types of chordal extensions in exploiting correlative sparsity: "MF" (approximately smallest chordal extension), "NC" (not performing chordal extension), false (invalidating correlative sparsity exploitation) | "MF" 67 | basis | Use customized monomial bases | [] 68 | hbasis | Use customized monomial bases associated with equality constraints | [] 69 | cliques | Use customized variable cliques | [] 70 | TS | Types of chordal extensions used in term sparsity iterations: "block"(maximal chordal extension), "signsymmetry" (sign symmetries), "MD" (approximately smallest chordal extension), false (invalidating term sparsity iterations) | "block" 71 | merge | Merge overlapping PSD blocks | false 72 | md | Parameter for tunning the merging strength | 3 73 | MomentOne | add a first-order moment PSD constraint for each variable clique | false 74 | solver | Specify an SDP solver: "Mosek" or "COSMO" | "Mosek" 75 | cosmo\_setting | Parameters for the COSMO solver: cosmo\_para(eps\_abs, eps\_rel, max\_iter, time\_limit) | cosmo\_para(1e-5, 1e-5, 1e4, 0) 76 | mosek\_setting | Parameters for the Mosek solver: mosek\_para(tol\_pfeas, tol\_dfeas, tol\_relgap, time\_limit, num\_threads) | mosek\_para(1e-8, 1e-8, 1e-8, -1, 0) 77 | QUIET | Silence the output| false 78 | solve | Solve the SDP relaxation | true 79 | dualize | Solve the dual SDP problem | false 80 | Gram | Output Gram matrices | false 81 | solution | Extract an optimal solution | false 82 | rtol | tolerance for rank | 1e-2 83 | gtol | tolerance for global optimality gap | 1e-2 84 | ftol | tolerance for feasibility | 1e-3 85 | 86 | ## Compute a locally optimal solution 87 | Moment-SOS relaxations provide lower bounds on the optimum of the polynomial optimization problem. As the complementary side, one could compute a locally optimal solution which provides an upper bound on the optimum of the polynomial optimization problem. The upper bound is useful in evaluating the quality (tightness) of those lower bounds provided by moment-SOS relaxations. In TSSOS, for a given polynomial optimization problem, a locally optimal solution could be obtained via the nonlinear programming solver [Ipopt](https://github.com/jump-dev/Ipopt.jl): 88 | 89 | ```Julia 90 | obj,sol,status = local_solution(data.n, data.m, data.supp, data.coe, numeq=data.numeq, startpoint=rand(data.n)) 91 | ``` 92 | 93 | ## Methods 94 | ```@docs 95 | tssos_first 96 | tssos_higher! 97 | cs_tssos_first 98 | cs_tssos_higher! 99 | local_solution 100 | refine_sol 101 | extract_solutions 102 | extract_solutions_robust 103 | ``` 104 | -------------------------------------------------------------------------------- /docs/src/sorf.md: -------------------------------------------------------------------------------- 1 | # Sum-Of-Rational-Functions Optimization 2 | 3 | The sum-of-rational-functions optimization problem could be formulized as 4 | 5 | $$\mathrm{inf}_{\mathbf{x}\in\mathbf{K}}\ \sum_{i=1}^N\frac{p_i(\mathbf{x})}{q_i(\mathbf{x})},$$ 6 | 7 | where $p_i,q_i\in\mathbb{R}[\mathbf{x}]$ are polynomials and $\mathbf{K}$ is the basic semialgebraic set 8 | 9 | $$\mathbf{K}\coloneqq\lbrace \mathbf{x}\in\mathbb{R}^n \mid g_i(\mathbf{x})\ge0, i=1,\ldots,m,\ h_j(\mathbf{x})=0, j=1,\ldots,\ell\rbrace,$$ 10 | 11 | for some polynomials $g_i,h_j\in\mathbb{R}[\mathbf{x}]$. 12 | 13 | The following is a simple example. 14 | 15 | ```Julia 16 | @polyvar x y z 17 | p = [x^2 + y^2 - y*z, y^2 + x^2*z, z^2 - x + y] # define the vector of denominators 18 | q = [1 + 2x^2 + y^2 + z^2, 1 + x^2 + 2y^2 + z^2, 1 + x^2 + y^2 + 2z^2] # define the vector of numerator 19 | g = [1 - x^2 - y^2 - z^2] 20 | d = 2 # set the relaxation order 21 | opt = SumOfRatios(p, q, g, [], [x;y;z], d, QUIET=true, SignSymmetry=true) # Without correlative sparsity 22 | opt = SparseSumOfRatios(p, q, g, [], [x;y;z], d, QUIET=true, SignSymmetry=true) # With correlative sparsity 23 | ``` 24 | 25 | ### Keyword arguments 26 | Argument | Description | Default value 27 | --- | :--- | :--- 28 | SignSymmetry | Exploit sign symmetries | true 29 | GroebnerBasis | Work in the quotient ring by computing a Gröbner basis | false 30 | 31 | ## Methods 32 | ```@docs 33 | SumOfRatios 34 | SparseSumOfRatios 35 | ``` 36 | 37 | ### References 38 | 39 | 1. [Exploiting Sign Symmetries in Minimizing Sums of Rational Functions](https://arxiv.org/abs/2405.09419), Feng Guo, Jie Wang, and Jianhao Zheng, 2024. -------------------------------------------------------------------------------- /docs/src/sos.md: -------------------------------------------------------------------------------- 1 | # Sum-Of-Squares Optimization 2 | 3 | A general [sum-of-squares optimization](https://en.wikipedia.org/wiki/Sum-of-squares_optimization) (including polynomial optimization as a special case) problem takes the form: 4 | 5 | $$\mathrm{inf}_{\mathbf{y}\in\mathbb{R}^n}\ \mathbf{c}^{\intercal}\mathbf{y}$$ 6 | 7 | $$\mathrm{s.t.}\ a_{k0}+y_1a_{k1}+\cdots+y_na_{kn}\in\mathrm{SOS},\ k=1,\ldots,m.$$ 8 | 9 | where $\mathbf{c}\in\mathbb{R}^n$ and $a_{ki}\in\mathbb{R}[\mathbf{x}]$ are polynomials. In TSSOS, SOS constraints could be handled with the routine **add_psatz!**: 10 | 11 | ```Julia 12 | info = add_psatz!(model, nonneg, vars, ineq_cons, eq_cons, order, TS="block", SO=1, GroebnerBasis=false) 13 | ``` 14 | where **nonneg** is a nonnegative polynomial constrained to admit a Putinar's style SOS representation on the semialgebraic set defined by **ineq_cons** and **eq_cons**, and **SO** is the sparse order. 15 | 16 | The following is a simple exmaple. 17 | 18 | $$\mathrm{sup}\ \lambda$$ 19 | 20 | $$\mathrm{s.t.}\ x_1^2 + x_1x_2 + x_2^2 + x_2x_3 + x_3^2 - \lambda(x_1^2+x_2^2+x_3^2)=\sigma+\tau_1(x_1^2+x_2^2+y_1^2-1)+\tau_2(x_2^2+x_3^2+y_2^2-1),$$ 21 | 22 | $$\sigma\in\mathrm{SOS},\deg(\sigma)\le2d,\ \tau_1,\tau_2\in\mathbb{R}[\mathbf{x}],\deg(\tau_1),\deg(\tau_2)\le2d-2.$$ 23 | 24 | ```Julia 25 | using JuMP 26 | using MosekTools 27 | using DynamicPolynomials 28 | using MultivariatePolynomials 29 | using TSSOS 30 | 31 | @polyvar x[1:3] 32 | f = x[1]^2 + x[1]*x[2] + x[2]^2 + x[2]*x[3] + x[3]^2 33 | d = 2 # set the relaxation order 34 | @polyvar y[1:2] 35 | h = [x[1]^2+x[2]^2+y[1]^2-1, x[2]^2+x[3]^2+y[2]^2-1] 36 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 37 | @variable(model, lower) 38 | nonneg = f - lower*sum(x.^2) 39 | info = add_psatz!(model, nonneg, [x; y], [], h, d, TS="block", GroebnerBasis=true) 40 | @objective(model, Max, lower) 41 | optimize!(model) 42 | ``` 43 | 44 | ### Keyword arguments 45 | Argument | Description | Default value 46 | --- | :--- | :--- 47 | CS | Types of chordal extensions in exploiting correlative sparsity: "MF" (approximately smallest chordal extension), "NC" (not performing chordal extension), false (invalidating correlative sparsity exploitation) | "MF" 48 | cliques | Use customized variable cliques | [] 49 | TS | Types of chordal extensions used in term sparsity iterations: "block"(maximal chordal extension), "signsymmetry" (sign symmetries), "MD" (approximately smallest chordal extension), false (invalidating term sparsity iterations) | "block" 50 | QUIET | Silence the output| false 51 | SO | Specify the sparse order | 1 52 | GroebnerBasis | Work in the quotient ring by computing a Gröbner basis | false 53 | 54 | ## Image of a semialgebraic set by a polynomial map 55 | Example 1, Section 6.1 from [arXiv:1507.06143](https://arxiv.org/pdf/1507.06143). 56 | The goal is to approximate the image of the two-dimensional unit ball $\mathbf{S} =$ { $\mathbf{x} \in \mathbb{R}^2 : x_1^2 + x_2^2 \leq 1$ } under the polynomial application $f(\mathbf{x})=(x_1+x_1 x_2, x_2-x_1^3)/2$. 57 | We choose $\mathbf{B}=\mathbf{S}$ since it can be checked that $f(\mathbf{S}) \subset \mathbf{B}$. 58 | 59 | 60 | ```Julia 61 | using JuMP 62 | using MosekTools 63 | using DynamicPolynomials 64 | using MultivariatePolynomials 65 | using SpecialFunctions 66 | using TSSOS 67 | using Plots 68 | 69 | # Moments of the Lebesgue measure on the unit ball 70 | function momball(a) 71 | n,m = size(a) 72 | y = zeros(m) 73 | for k = 1:m 74 | if all(.!Bool.(rem.(a[:,k],2))) 75 | y[k]=prod(gamma.((a[:,k].+1)/2))/gamma(1+(n+sum(a[:,k]))/2) 76 | end 77 | end 78 | return y 79 | end 80 | 81 | # Half-degree of polynomials w(x) and v(x) 82 | d = 5 83 | 84 | n = 2 85 | @polyvar x[1:n] 86 | f = [x[1] + x[1]*x[2]; x[2] - x[1]^3] * 0.5 87 | gS = 1 - x[1]^2 - x[2]^2 88 | gB = gS 89 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 90 | #set_optimizer_attribute(model, MOI.Silent(), true) 91 | 92 | v, vc, vb = add_poly!(model, x, 2d) 93 | w, wc, wb = add_poly!(model, x, 2d) 94 | vf = subs(v, x[1]=>f[1], x[2]=>f[2]) 95 | dv = Int(ceil(maxdegree(vf)/2)) 96 | 97 | # Constraints 98 | info1 = add_psatz!(model, vf, x, [gS], [], dv, QUIET=false, CS=false, TS=false, GroebnerBasis=false) # v o f >= 0 on S 99 | info2 = add_psatz!(model, w-1-v, x, [gB], [], d, QUIET=false, CS=false, TS=false, GroebnerBasis=false) # w >= v + 1 on B 100 | info3 = add_psatz!(model, w, x, [gB], [], d, QUIET=false, CS=false, TS=false, GroebnerBasis=false) # w >= 0 on B 101 | 102 | supp = TSSOS.get_basis(n, 2d) 103 | 104 | # Lebesgue moments on B 105 | 106 | moment = momball(supp) 107 | @objective(model, Min, moment'*wc) # minimization of int w d_lambda 108 | 109 | 110 | optimize!(model) 111 | status = termination_status(model) 112 | if status != MOI.OPTIMAL 113 | println("termination status: $status") 114 | status = primal_status(model) 115 | println("solution status: $status") 116 | end 117 | objv = objective_value(model) 118 | wp = value.(wc)'*wb 119 | 120 | # Plot the superlevel set of w-1 121 | x1 = range(-1, 1, length=1000) 122 | x2 = range(-1, 1, length=1000) 123 | hw(x1, x2) = if x1^2 + x2^2 <= 1.0 wp(x1,x2) else 0.0 end 124 | zw = @. hw(x1', x2) 125 | p = contour(x1, x2, zw, level=[1], color=[:white,:gray], levels=1, cbar=false, grid=false, fill=true) 126 | 127 | # Sample the image set f(S) 128 | N = 10^5 129 | X = randn(2, N) 130 | X = mapslices(c -> rand(1)[1]*c/sqrt(sum(c.^2)), X, dims=1) 131 | f1 = mapslices(c->f[1](c), X, dims=1)[1, :] 132 | f2 = mapslices(c->f[2](c), X, dims=1)[1, :] 133 | scatter!(p, f1, f2, mc=:black, legend=false) 134 | 135 | # Draw the unit circle 136 | t = range(0, 2*pi, length=100) 137 | xt = cos.(t) 138 | yt = sin.(t) 139 | plot!(p, xt, yt, color=:black, legend=false, ylimits=(-1,1), xlimits=(-1,1), aspect_ratio=:equal) 140 | ``` 141 | 142 | ![Image approximation](https://homepages.laas.fr/vmagron/files/tssos/image5.png) 143 | 144 | 145 | The black dots correspond to the image set of the points obtained by uniform sampling of $\mathbf{S}$ under $f$. 146 | The outer approximation obtained at the 5-th relaxation order is represented in light gray. 147 | 148 | ## Region of attraction of the Van der Pol oscillator 149 | Section 9.2 from [arXiv:1208.1751](https://arxiv.org/abs/1208.1751). 150 | The goal is to approximate the region of attraction of the uncontrolled reversed-time Van der Pol oscillator given by 151 | 152 | $$\dot{x}_1 = -2 x_2$$ 153 | 154 | $$\dot{x}_2 = 0.8 x_1 + 10 (x_1^2-0.21)x_2$$ 155 | 156 | with general state constraints $\mathbf{X}=[-1.2, 1.2]^2$, terminal state constraints $\mathbf{X}_T =$ { $\mathbf{x} \in \mathbb{R}^2 : x_1^2 + x_2^2 \leq 0.01^2$ }, and final time $T=100$. 157 | 158 | 159 | ```Julia 160 | using JuMP 161 | using MosekTools 162 | using DynamicPolynomials 163 | using MultivariatePolynomials 164 | using TSSOS 165 | using Plots 166 | 167 | n = 2 168 | @polyvar x[1:n] t 169 | 170 | # Half-degree of polynomials w(x) and v(t,x) 171 | d = 8 172 | 173 | # Constraint set X = {x : ||x||_inf <= xb} 174 | xb = 1.2 175 | gx1 = xb^2 - x[1]^2 176 | gx2 = xb^2 - x[2]^2 177 | gX = [gx1; gx2] 178 | 179 | # Final time 180 | T = 100 181 | 182 | # Dynamics (scaled by final time) 183 | f = -[2*x[2], -0.8*x[1] - 10*(x[1]^2 - 0.20)*x[2]] * T 184 | 185 | # X_T 186 | gxT = (0.1^2 - x'*x) 187 | 188 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 189 | set_optimizer_attribute(model, MOI.Silent(), true) 190 | 191 | # Define polynomials w(x) and v(t,x) 192 | v, vc, vb = add_poly!(model, [x;t], 2d) 193 | w, wc, wb = add_poly!(model, x, 2d) 194 | Lv = sum([f;1] .* differentiate(v, [x;t])) 195 | dv = Int(ceil(maxdegree(Lv)/2)) 196 | 197 | # Constraints (Note that the dynamics was scaled by T, so there T = 1) 198 | 199 | info1 = add_psatz!(model, -Lv, [x;t], [gX; t*(1-t)], [], dv, QUIET=false, CS=false, TS=false, GroebnerBasis=false) # Lv <= 0 on [0 T] x X 200 | info2 = add_psatz!(model, subs(v,t=>1), x, [gxT], [], d, QUIET=false, CS=false, TS=false, GroebnerBasis=false) # v >= 0 on {T} x X_T 201 | info3 = add_psatz!(model, w-1-subs(v,t=>0), x, gX, [], d, QUIET=false, CS=false, TS=false, GroebnerBasis=false) # w >= v + 1 on {0} x X 202 | info4 = add_psatz!(model, w, x, gX, [], d, QUIET=false, CS=false, TS=false, GroebnerBasis=false) # w >= 0 on X 203 | 204 | supp = TSSOS.get_basis(n, 2d) 205 | 206 | # Lebesgue moments on X 207 | 208 | moment = get_moment(n, supp, -xb*ones(n), xb*ones(n)) 209 | @objective(model, Min, moment'*wc) # minimization of int w d_lambda 210 | 211 | optimize!(model) 212 | status = termination_status(model) 213 | if status != MOI.OPTIMAL 214 | println("termination status: $status") 215 | status = primal_status(model) 216 | println("solution status: $status") 217 | end 218 | objv = objective_value(model) 219 | 220 | 221 | # Plots 222 | 223 | # Plot the superlevel set of v 224 | vp = subs(value.(vc)'*vb, t=>0) 225 | wp = value.(wc)'*wb 226 | 227 | x1 = range(-xb, xb, length=1000) 228 | x2 = range(-xb, xb, length=1000) 229 | hw(x1,x2) = wp(x1, x2) 230 | hv(x1,x2) = max(vp(x1,x2), -0.1) 231 | zw = @. hw(x1', x2) 232 | zv = @. hv(x1', x2) 233 | 234 | p = contour(x1, x2, zv, level=[0], color=[:white,:gray], levels=1, cbar=false,grid=false,fill=true, ylimits=(-xb,xb), xlimits=(-xb,xb), aspect_ratio=:equal) 235 | 236 | # Simulate trajectory with reversed time to get the boundary of the true ROA 237 | using DifferentialEquations 238 | 239 | roafun(X, p, t) = [2*X[2]; -0.8*X[1] - 10*(X[1]^2-0.21)*X[2]] 240 | prob = ODEProblem(roafun, [0.1;0.1], (0.0,100.0)) 241 | solode = solve(prob,DP5(), reltol=1e-8, abstol=1e-8) 242 | xt = map(v -> v[1], solode.u) 243 | yt = map(v -> v[2], solode.u) 244 | 245 | plot!(p, xt[1500:end], yt[1500:end], color=:black, legend=false, ylimits=(-xb,xb), xlimits=(-xb,xb), aspect_ratio=:equal) 246 | ``` 247 | 248 | ![ROA approximation](https://homepages.laas.fr/vmagron/files/tssos/roa8.png) 249 | 250 | The black curve corresponds to the boundary of the true region of attraction. 251 | The outer approximation obtained at the 8-th relaxation order is represented in light gray. 252 | 253 | 254 | ## Methods 255 | ```@docs 256 | add_psatz! 257 | add_poly! 258 | add_SOS! 259 | ``` 260 | -------------------------------------------------------------------------------- /docs/src/structure.md: -------------------------------------------------------------------------------- 1 | # Structures 2 | 3 | ## Quotient ring 4 | 5 | ## Correlative sparsity 6 | 7 | ## Term Sparsity 8 | 9 | ## Symmetry 10 | 11 | ```@docs 12 | tssos_symmetry 13 | ``` -------------------------------------------------------------------------------- /docs/src/technique.md: -------------------------------------------------------------------------------- 1 | # Techniques 2 | 3 | ## Homogenization 4 | 5 | 6 | ## Christoffel-Darboux Kernels 7 | 8 | Here is the list of functions implemented in TSSOS that are based on computing Christiffel-Darboux kernels associated to a given POP: 9 | 10 | ```@docs 11 | run_H1 12 | run_H1CS 13 | run_H2 14 | run_H2CS 15 | construct_CDK 16 | construct_marginal_CDK 17 | construct_CDK_cs 18 | construct_marginal_CDK_cs 19 | ``` 20 | 21 | We provide below some illustrations. 22 | Let us consider the following POP (Example 3.2 from [[Sparse polynomial optimization: theory and practice]](https://arxiv.org/abs/2208.11158)): 23 | ```julia 24 | n = 6 25 | @polyvar x[1:n] 26 | f = x[2]*x[5] + x[3]*x[6] - x[2]*x[3] - x[5]*x[6] + x[1]*(-x[1] + x[2] + x[3] - x[4] + x[5] + x[6]) 27 | g = [(6.36 - x[i]) * (x[i] - 4) for i in 1:6] 28 | pop = [f, g...] 29 | d = 1 30 | ``` 31 | We can solve the problem using the dense moment-SOS hierarchy: 32 | ```julia 33 | opt, sol, data = cs_tssos_first(pop, x, d, TS=false, CS=false, solution=true) 34 | ``` 35 | Afterwards, one can try strenghtening the bound via **H1**: 36 | ```julia 37 | N = 5 38 | eps = 0.05 39 | dc = 1 40 | gap_tol = 0.1 41 | resultH1 = run_H1(pop,x,d,dc,N,eps,gap_tol) 42 | ``` 43 | or via **H2** 44 | ```julia 45 | dc = 1 46 | local_sol = sol 47 | tau = 1.1 48 | resultH2 = run_H2(pop,x,d,dc,local_sol,tau) 49 | ``` 50 | Alternatively, the problem can be solved using the correlatively sparse moment-SOS hierarchy: 51 | ```julia 52 | opt, sol, data = cs_tssos_first(pop, x, d, TS=false, solution=true) 53 | ``` 54 | Afterwards, the bound can be strengthened either via **H1CS**: 55 | ```julia 56 | N = 5 57 | eps = 0.05 58 | dc = 1 59 | gap_tol = 0.1 60 | resultH1CS = run_H1CS(pop,x,d,dc,N,eps,gap_tol) 61 | ``` 62 | or via **H2CS** 63 | ```julia 64 | dc = 1 65 | local_sol = sol 66 | tau = 1.1 67 | resultH2CS = run_H2CS(pop,x,d,dc,local_sol,tau) 68 | ``` 69 | 70 | Moreover, here is how different Christoffel polynomials can be constructed using the output of the: 71 | - dense Moment-SOS relaxation of order 2 72 | ```julia 73 | d = 2 74 | opt, sol, data = cs_tssos_first(pop, x, d, TS=false, CS=false, solution=true, Mommat=true) 75 | 76 | k = 4 77 | dc = 1 78 | CDK_order1 = construct_CDK(x, dc, data.moment[1]) # Constructs multivariate Christoffel polynomial of order dc=1 (quadratic CDK) 79 | CDK_4_order1 = construct_marginal_CDK(x, k, dc, data.moment[1]) # Constructs marginal Christoffel polynomial, associated to x_4, of order dc=1 80 | 81 | dc = 2 82 | CDK_order2 = construct_CDK(x, dc, data.moment[1]) # Construct multivariate Christoffel polynomial of order dc=2 (quartic CDK) 83 | CDK_4_order2 = construct_marginal_CDK(x, k, dc, data.moment[1]) # Constructs marginal Christoffel polynomial, associated to x_4, of order dc=2 84 | 85 | ``` 86 | - sparse Moment-SOS relaxation of order 2 87 | ```julia 88 | d = 2 89 | opt, sol, data = cs_tssos_first(pop, x, d, TS=false, solution=true, Mommat=true) 90 | 91 | k = 4 92 | dc = 1 93 | CDK_sparse_order1 = construct_CDK_cs(x, dc, data.moment, data.cliques) # Constructs multivariate Christoffel polynomial of order dc=1 for each identified clique. 94 | CDK_sparse_4_order1 = construct_marginal_CDK_cs(x, k, dc, data.moment, data.cliques) # Constructs marginal Christoffel polynomial, associated to x_4, of order dc=1 95 | 96 | dc = 2 97 | CDK_sparse_order2 = construct_CDK_cs(x, dc, data.moment, data.cliques) # Constructs multivariate Christoffel polynomial of order dc=2 for each identified clique. 98 | CDK_sparse_4_order2 = construct_marginal_CDK_cs(x, k, dc, data.moment, data.cliques) # Constructs marginal Christoffel polynomial, associated to x_4, of order dc=2 99 | 100 | ``` 101 | 102 | ## Tips for modelling polynomial optimization problems 103 | - When possible, explictly include a sphere/ball constraint (or multi-sphere/multi-ball constraints). 104 | - When the feasible set is unbounded, try the homogenization technique introduced in [Homogenization for polynomial optimization with unbounded sets](https://link.springer.com/article/10.1007/s10107-022-01878-5). 105 | - Scale the coefficients of the polynomial optimization problem to $[-1, 1]$. 106 | - Scale the variables so that they take values in $[-1, 1]$ or $[0, 1]$. 107 | - Try to include more (redundant) inequality constraints. 108 | -------------------------------------------------------------------------------- /example/PolyphaseCodeDesign.jl: -------------------------------------------------------------------------------- 1 | using TSSOS 2 | using DynamicPolynomials 3 | 4 | ## Polyphase Code Waveform Design 5 | ## formulation with inequality constraints 6 | N = 6 7 | @complex_polyvar z[1:N+1] 8 | f = z[N+1]^2 + conj(z[N+1])^2 9 | cons = Vector{typeof(f)}(undef, N-2) 10 | for k = 1:N-2 11 | cons[k] = z[N+1]^2 + conj(z[N+1])^2 - sum(z[i]*z[j+k]*conj(z[j]*z[i+k]) for i = 1:N-k, j = 1:N-k) 12 | end 13 | 14 | order = 4 15 | @time begin 16 | opt,sol,data = complex_tssos_first([f; cons], z, order, nb=N+1, TS="block", ConjugateBasis=true, normality=0, QUIET=false) 17 | end 18 | println(opt^0.5) 19 | 20 | # writetofile="D:/project/ManiDSDP/polyphasecode4.sdpa" 21 | 22 | ## formulation with equality constraints 23 | N = 8 24 | @complex_polyvar z[1:2N-1] 25 | f = z[N+1]^2 + conj(z[N+1])^2 26 | cons = Vector{typeof(f)}(undef, N-2) 27 | for k = 1:N-2 28 | cons[k] = z[N+1]^2 + conj(z[N+1])^2 - z[N+1+k]^2 - conj(z[N+1+k]^2) - 2 - sum(z[i]*z[j+k]*conj(z[j]*z[i+k]) for i = 1:N-k, j = 1:N-k) 29 | # z[N+1+k]*conj(z[N+1+k]) 30 | end 31 | 32 | order = 3 33 | @time begin 34 | opt,sol,data = complex_tssos_first([f; cons], z, order, numeq=N-2, nb=2N-1, CS=false, TS="block", QUIET=false) 35 | opt,sol,data = complex_tssos_higher!(data, TS="block", solve=true, QUIET=false) 36 | end 37 | println(opt^0.5) 38 | 39 | # find a solution 40 | mm = data.moment[1] 41 | b = [acos(mm[N+3+2k][1,2]) for k=1:N-2] 42 | # b[1] = b[8] = -b[1] 43 | # b[2] = b[7] = -b[2] 44 | # b[3] = b[6] = -b[3] 45 | # b[4] = b[5] = -b[4] 46 | A = diagm(2*ones(N-2)) 47 | A[1,2] = A[N-2,N-3] = -1 48 | for k = 2:N-3 49 | A[k,k-1] = A[k,k+1] = -1 50 | end 51 | θ = A\b 52 | θ = [0;θ;0] 53 | sol = cos.(θ)+sin.(θ)*im 54 | abs.([pop[j+1](z=>sol) for j=1:N-2]) 55 | 56 | # compute a local solution 57 | N = 15 58 | @polyvar x[1:N] 59 | @polyvar y[1:N] 60 | @polyvar t 61 | pop = Vector{Poly}(undef, 2N-1) 62 | pop[1] = t^2 63 | for k = 1:N-2 64 | pop[k+1] = t^2 - sum(x[j]*x[j+k]+y[j]*y[j+k] for j=1:N-k)^2 - sum(x[j]*y[j+k]-y[j]*x[j+k] for j=1:N-k)^2 65 | end 66 | for k = 1:N 67 | pop[k+N-1] = 1 - x[k]^2 - y[k]^2 68 | end 69 | 70 | @time begin 71 | opt,sol,data = tssos_first(pop, [x;y;t], 2, numeq=N, GroebnerBasis=false, TS=false, QUIET=true, solve=false) 72 | # opt,sol,data = tssos_higher!(data, TS="block", QUIET=true) 73 | end 74 | # println(opt^0.5) 75 | 76 | opt,sol = local_solution(data.n, data.m, data.supp, data.coe, numeq=N, startpoint=rand(2N+1), QUIET=false) 77 | println(opt^0.5) 78 | 79 | # Another model 80 | N = 6 81 | @complex_polyvar z[1:N] 82 | f = sum(sum(z[i]*conj(z[i+j]) for i = 1:N-j)*sum(conj(z[i])*z[i+j] for i = 1:N-j) for j = 1:N-2) 83 | order = 4 84 | @time begin 85 | opt,sol,data = complex_tssos_first([f], z, order, nb=N, TS="block", QUIET=false) 86 | end 87 | 88 | N = 12 89 | @polyvar x[1:N] 90 | @polyvar y[1:N] 91 | f = sum(sum(x[j]*x[j+k]+y[j]*y[j+k] for j=1:N-k)^2 + sum(x[j]*y[j+k]-y[j]*x[j+k] for j=1:N-k)^2 for k=1:N-2) 92 | cons = Vector{typeof(f)}(undef, N) 93 | for k = 1:N 94 | cons[k] = 1 - x[k]^2 - y[k]^2 95 | end 96 | @time begin 97 | opt,sol,data = tssos_first([f; cons], [x;y], 2, numeq=N, TS=false, GroebnerBasis=false, QUIET=true, solve=false) 98 | # opt,sol,data = tssos_higher!(data, TS="block", QUIET=true) 99 | end 100 | 101 | opt,sol = local_solution(data.n, data.m, data.supp, data.coe, numeq=N, startpoint=rand(2N), QUIET=false) 102 | 103 | # extract a pair of conjugate solutions 104 | using LinearAlgebra 105 | using LDLFactorizations 106 | using DynamicPolynomials 107 | 108 | n = 5 109 | @complex_polyvar z[1:n] 110 | # Q = rand(n, n) 111 | # c = rand(n) 112 | basis = cbasis(z) 113 | Q = rand(length(basis), length(basis)) 114 | # ind = [Int.(floor.(rand(2)*length(basis)).+1) for i = 1:5] 115 | # for item in ind 116 | # Q[item[1],item[2]] = rand(1)[1] 117 | # end 118 | Q = (Q+Q')/2 119 | f = basis'*Q*basis 120 | # f = z'*Q*z + c'*(z+conj(z)) 121 | # f = (1+im)*z[1]*z[2]*z[3] + (1+im)*z[2]*z[3]*z[4] + (1-im)*conj(z[1]*z[2]*z[3]) + (1-im)*conj(z[2]*z[3]*z[4]) 122 | h = 1 - z'*z 123 | opt,sol,data = complex_tssos_first([f; h], z, 2, numeq=1, QUIET=true, TS=false) 124 | M = Matrix{Float64}(data.moment[1][1][1:n+1,1:n+1]) 125 | F = ldl(M) 126 | ind = findall(diag(F.D).>1e-4) 127 | if length(ind) > 1 128 | temp = F.L[2:end, ind[2]] 129 | temp[ind[2]-1] = 1 130 | v = sqrt(M[ind[2],ind[2]]-F.L[ind[2],1]^2) 131 | sol = Matrix([F.L[2:end, 1] v*temp]) 132 | obj = f(z=>sol[:,1]+im*sol[:,2]) 133 | println([rank(M, 1e-4), abs(opt-obj)]) 134 | end 135 | -------------------------------------------------------------------------------- /example/SumOfRatios.jl: -------------------------------------------------------------------------------- 1 | using DynamicPolynomials 2 | using TSSOS 3 | using JuMP 4 | using MosekTools 5 | using Random 6 | 7 | # Example 4.8 8 | @polyvar x y z 9 | p = [x^2+y^2-y*z, y^2+x^2*z, z^2-x+y] 10 | q = [1+2x^2+y^2+z^2, 1+x^2+2y^2+z^2, 1+x^2+y^2+2z^2] 11 | g = [1-x^2-y^2-z^2] 12 | 13 | d = 4 14 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 15 | set_optimizer_attribute(model, MOI.Silent(), true) 16 | h1 = add_poly!(model, [x;y;z], 2d-2, signsymmetry=get_signsymmetry([p[2]; q[2]; g], [x;y;z]))[1] 17 | h2 = add_poly!(model, [x;y;z], 2d-2, signsymmetry=get_signsymmetry([p[3]; q[3]; g], [x;y;z]))[1] 18 | c = @variable(model) 19 | add_psatz!(model, p[1]+(h1+h2-c)*q[1], [x;y;z], g, [], d, QUIET=true, CS=false, TS=false, SO=1, GroebnerBasis=false) 20 | add_psatz!(model, p[2]-h1*q[2], [x;y;z], g, [], d, QUIET=true, CS=false, TS="block", SO=1, GroebnerBasis=false) 21 | add_psatz!(model, p[3]-h2*q[3], [x;y;z], g, [], d, QUIET=true, CS=false, TS="block", SO=1, GroebnerBasis=false) 22 | @objective(model, Max, c) 23 | optimize!(model) 24 | objv = objective_value(model) 25 | @show objv 26 | 27 | d = 4 28 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 29 | set_optimizer_attribute(model, MOI.Silent(), true) 30 | h1 = add_poly!(model, [x;y;z], 2d-2, signsymmetry=get_signsymmetry([p[1]; q[1]; g], [x;y;z]))[1] 31 | h2 = add_poly!(model, [x;y;z], 2d-2, signsymmetry=get_signsymmetry([p[3]; q[3]; g], [x;y;z]))[1] 32 | c = @variable(model) 33 | add_psatz!(model, p[1]-h1*q[1], [x;y;z], g, [], d, QUIET=true, CS=false, TS="block", SO=1, GroebnerBasis=false) 34 | add_psatz!(model, p[2]+(h1+h2-c)*q[2], [x;y;z], g, [], d, QUIET=true, CS=false, TS=false, SO=1, GroebnerBasis=false) 35 | add_psatz!(model, p[3]-h2*q[3], [x;y;z], g, [], d, QUIET=true, CS=false, TS="block", SO=1, GroebnerBasis=false) 36 | @objective(model, Max, c) 37 | optimize!(model) 38 | objv = objective_value(model) 39 | @show objv 40 | 41 | d = 4 42 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 43 | set_optimizer_attribute(model, MOI.Silent(), true) 44 | h1 = add_poly!(model, [x;y;z], 2d-2, signsymmetry=get_signsymmetry([p[1]; q[1]; g], [x;y;z]))[1] 45 | h2 = add_poly!(model, [x;y;z], 2d-2, signsymmetry=get_signsymmetry([p[2]; q[2]; g], [x;y;z]))[1] 46 | c = @variable(model) 47 | add_psatz!(model, p[1]-h1*q[1], [x;y;z], g, [], d, QUIET=true, CS=false, TS="block", SO=1, GroebnerBasis=false) 48 | add_psatz!(model, p[2]-h2*q[2], [x;y;z], g, [], d, QUIET=true, CS=false, TS="block", SO=1, GroebnerBasis=false) 49 | add_psatz!(model, p[3]+(h1+h2-c)*q[3], [x;y;z], g, [], d, QUIET=true, CS=false, TS=false, SO=1, GroebnerBasis=false) 50 | @objective(model, Max, c) 51 | optimize!(model) 52 | objv = objective_value(model) 53 | @show objv 54 | 55 | opt = SumOfRatios(p, q, g, [], [x;y;z], 3, QUIET=true, SignSymmetry=false) 56 | 57 | @polyvar w[1:3] 58 | pop = [sum(w), 1-x^2-y^2-z^2, p[1]-w[1]*q[1], p[2]-w[2]*q[2], p[3]-w[3]*q[3]] 59 | opt,sol,data = cs_tssos_first(pop, [x;y;z;w], 3, numeq=3, TS=false, solution=false, QUIET=true) 60 | 61 | # Example 5.1 62 | @polyvar x[1:3] 63 | @polyvar a 64 | d = 2 65 | M = 6 66 | p = [a^4*(x[1]^(6d) + x[2]^(6d) + x[3]^(6d)) + (x[1]^(4d)*x[2]^(2d) + x[2]^(4d)*x[3]^(2d) + x[3]^(4d)*x[1]^(2d)) + 67 | a^8*(x[1]^(2d)*x[2]^(4d) + x[2]^(2d)*x[3]^(4d) + x[3]^(2d)*x[1]^(4d)) for a in Vector(1:M-1)/M] 68 | q = [2*a^6*(x[1]^(4d)*x[2]^(2d) + x[2]^(4d)*x[3]^(2d) + x[3]^(4d)*x[1]^(2d)) + 2*a^2*(x[1]^(2d)*x[2]^(4d) + 69 | x[2]^(2d)*x[3]^(4d) + x[3]^(2d)*x[1]^(4d)) + 3*(1-2*a^2+a^4-2*a^6+a^8)*x[1]^(2d)*x[2]^(2d)*x[3]^(2d) for a in Vector(1:M-1)/M] 70 | h = [3.0 - sum(x.^2)] 71 | 72 | @time opt = SumOfRatios(p, q, [], h, x, 3d, QUIET=false, SignSymmetry=true) 73 | @time opt = SumOfRatios(p, q, [], h, x, 3d, QUIET=false, SignSymmetry=false) 74 | @time opt = SumOfRatios(p, q, [], h, x, 3d, QUIET=false, dualize=true, SignSymmetry=false) 75 | 76 | @polyvar w[1:M-1] 77 | pop = [sum(w); h; [p[i]-w[i]*q[i] for i=1:M-1]] 78 | @time opt,sol,data = cs_tssos_first(pop, [x;w], 3d+1, numeq=M, TS="block", solution=false, QUIET=true) 79 | 80 | # Example 5.2 81 | c = [0.806; 0.517; 0.100; 0.908; 0.965; 0.669; 0.524; 0.902; 0.531; 0.876; 0.462; 0.491; 0.463; 0.714; 0.352; 82 | 0.869; 0.813; 0.811; 0.828; 0.964; 0.789; 0.360; 0.369; 0.992; 0.332; 0.817; 0.632; 0.883; 0.608; 0.326] 83 | A = [9.681 0.667 4.783 9.095 3.517 9.325 6.544 0.211 5.122 2.020; 84 | 9.400 2.041 3.788 7.931 2.882 2.672 3.568 1.284 7.033 7.374; 85 | 8.025 9.152 5.114 7.621 4.564 4.711 2.996 6.126 0.734 4.982; 86 | 2.196 0.415 5.649 6.979 9.510 9.166 6.304 6.054 9.377 1.426; 87 | 8.074 8.777 3.467 1.863 6.708 6.349 4.534 0.276 7.633 1.567; 88 | 7.650 5.658 0.720 2.764 3.278 5.283 7.474 6.274 1.409 8.208; 89 | 1.256 3.605 8.623 6.905 4.584 8.133 6.071 6.888 4.187 5.448; 90 | 8.314 2.261 4.224 1.781 4.124 0.932 8.129 8.658 1.208 5.762; 91 | 0.226 8.858 1.420 0.945 1.622 4.698 6.228 9.096 0.972 7.637; 92 | 7.305 2.228 1.242 5.928 9.133 1.826 4.060 5.204 8.713 8.247; 93 | 0.652 7.027 0.508 4.876 8.807 4.632 5.808 6.937 3.291 7.016; 94 | 2.699 3.516 5.874 4.119 4.461 7.496 8.817 0.690 6.593 9.789; 95 | 8.327 3.897 2.017 9.570 9.825 1.150 1.395 3.885 6.354 0.109; 96 | 2.132 7.006 7.136 2.641 1.882 5.943 7.273 7.691 2.880 0.564; 97 | 4.707 5.579 4.080 0.581 9.698 8.542 8.077 8.515 9.231 4.670; 98 | 8.304 7.559 8.567 0.322 7.128 8.392 1.472 8.524 2.277 7.826; 99 | 8.632 4.409 4.832 5.768 7.050 6.715 1.711 4.323 4.405 4.591; 100 | 4.887 9.112 0.170 8.967 9.693 9.867 7.508 7.770 8.382 6.740; 101 | 2.440 6.686 4.299 1.007 7.008 1.427 9.398 8.480 9.950 1.675; 102 | 6.306 8.583 6.084 1.138 4.350 3.134 7.853 6.061 7.457 2.258; 103 | 0.652 2.343 1.370 0.821 1.310 1.063 0.689 8.819 8.833 9.070; 104 | 5.558 1.272 5.756 9.857 2.279 2.764 1.284 1.677 1.244 1.234; 105 | 3.352 7.549 9.817 9.437 8.687 4.167 2.570 6.540 0.228 0.027; 106 | 8.798 0.880 2.370 0.168 1.701 3.680 1.231 2.390 2.499 0.064; 107 | 1.460 8.057 1.336 7.217 7.914 3.615 9.981 9.198 5.292 1.224; 108 | 0.432 8.645 8.774 0.249 8.081 7.461 4.416 0.652 4.002 4.644; 109 | 0.679 2.800 5.523 3.049 2.968 7.225 6.730 4.199 9.614 9.229; 110 | 4.263 1.074 7.286 5.599 8.291 5.200 9.214 8.272 4.398 4.506; 111 | 9.496 4.830 3.150 8.270 5.079 1.231 5.731 9.494 1.883 9.732; 112 | 4.138 2.562 2.532 9.661 5.611 5.500 6.886 2.341 9.699 6.500] 113 | 114 | N = 30 115 | n = 5 116 | @polyvar x[1:n] 117 | p = -ones(N) 118 | q = [sum((x[j]^2-A[i,j]/10)^2 for j=1:n) + c[i]/100 for i = 1:N] 119 | g = [0.6 - sum((x[i]^2-0.5)^2 for i=1:n)] 120 | k = 3 121 | @time opt = SumOfRatios(p, q, g, [], x, k, QUIET=true, dualize=true, SignSymmetry=false) 122 | @time opt = SumOfRatios(p, q, g, [], x, k, QUIET=true, SignSymmetry=false) 123 | @time opt = SumOfRatios(p, q, g, [], x, k, QUIET=true, SignSymmetry=true) 124 | 125 | @polyvar w[1:N] 126 | pop = [sum(w); g; [p[i]-w[i]*q[i] for i=1:N]] 127 | @time opt,sol,data = cs_tssos_first(pop, [x;w], 4, numeq=N, TS="block", solution=false, QUIET=true) 128 | 129 | # Example 5.3 130 | using MultivariatePolynomials 131 | Random.seed!(1) 132 | N = 10 133 | n = 6 134 | d = 4 135 | pp = 0.05 136 | s = 3 137 | @polyvar x[1:n] 138 | p = -ones(N) 139 | mons = monomials(x, 0:d) 140 | ind = shuffle(Vector(1:length(mons)))[1:Int(floor(length(mons)*pp))] 141 | q = Vector{Polynomial{true, Float64}}(undef, N) 142 | for i = 1:N 143 | loc = shuffle(Vector(1:length(ind)))[1:s] 144 | q[i] = 1 + (rand(s)'*mons[ind[loc]])^2 145 | end 146 | g = [1 - sum(x.^2)] 147 | @time opt = SumOfRatios(p, q, g, [], x, d, QUIET=true, dualize=true, SignSymmetry=false) 148 | @time opt = SumOfRatios(p, q, g, [], x, d, QUIET=true, SignSymmetry=false) 149 | @time opt = SumOfRatios(p, q, g, [], x, d, QUIET=true, SignSymmetry=true) 150 | 151 | @polyvar w[1:N] 152 | pop = [sum(w); g; [p[i]-w[i]*q[i] for i=1:N]] 153 | @time opt,sol,data = cs_tssos_first(pop, [x;w], d+1, numeq=N, TS="block", solution=false, QUIET=true) 154 | 155 | 156 | # Example 5.4 157 | N = 20 158 | n = 2*N + 2 159 | @polyvar x[1:n] 160 | p = [sum(x[2*i-1:2*i+1].^2)*prod(x[2*i-1:2*i+1].^2) + x[2*i+2]^8 for i=1:N] 161 | q = [prod(x[2*i-1:2*i+2].^2) for i=1:N] 162 | h = [4 - sum(x[2*i-1:2*i+2].^2) for i=1:N] 163 | d = 5 164 | @time opt = SparseSumOfRatios(p, q, [], h, x, d, QUIET=true, dualize=true, SignSymmetry=false) 165 | @time opt = SparseSumOfRatios(p, q, [], h, x, d, QUIET=true, SignSymmetry=false) 166 | @time opt = SparseSumOfRatios(p, q, [], h, x, d, QUIET=true, SignSymmetry=true) 167 | 168 | @polyvar w[1:N] 169 | pop = [sum(w); h; [p[i]-w[i]*q[i] for i=1:N]] 170 | @time opt,sol,data = cs_tssos_first(pop, [x;w], d+1, numeq=2N, TS="block", solution=false, QUIET=true) 171 | @time opt,sol,data = cs_tssos_higher!(data, TS="block", solution=false, QUIET=true) 172 | 173 | 174 | # Example 5.5 175 | N = 5 176 | d = 2 177 | n = 2*N + 1 178 | @polyvar x[1:n] 179 | p = [x[2*i-1]^(6d) + x[2i]^(6d) + x[2i+1]^(6d) + 3*x[2i-1]^(2d)*x[2i]^(2d)*x[2i+1]^(2d) for i = 1:N] 180 | q = [x[2i-1]^(4d)*x[2i]^(2d) + x[2i-1]^(2d)*x[2i]^(4d) + x[2i-1]^(4d)*x[2i+1]^(2d) + x[2i-1]^(2d)*x[2i+1]^(4d) + x[2i]^(4d)*x[2i+1]^(2d) + x[2i]^(2d)*x[2i+1]^(4d) for i = 1:N] 181 | h = [3 - sum(x[2*i-1:2*i+1].^2) for i = 1:N] 182 | 183 | @time opt = SparseSumOfRatios(p, q, [], h, x, 3d, QUIET=true, SignSymmetry=true) 184 | @time opt = SparseSumOfRatios(p, q, [], h, x, 3d, QUIET=true, SignSymmetry=false) 185 | @time opt = SparseSumOfRatios(p, q, [], h, x, 3d, QUIET=true, dualize=true, SignSymmetry=false) 186 | 187 | @polyvar w[1:N] 188 | pop = [sum(w); h; [p[i]-w[i]*q[i] for i=1:N]] 189 | @time opt,sol,data = cs_tssos_first(pop, [x;w], 3d+1, numeq=2N, TS="block", solution=false, QUIET=true) 190 | @time opt,sol,data = cs_tssos_higher!(data, TS="block", solution=false, QUIET=true) 191 | 192 | 193 | # Example 5.6 194 | n = 51 195 | @polyvar x[1:n] 196 | p = ones(n-1) 197 | q = [100(x[i+1]^2-x[i]^2)^2 + (x[i]^2-1)^2 + 1 for i = 1:n-1] 198 | g = [16-x[i]^2 for i=1:n] 199 | @time opt = SparseSumOfRatios(-p, q, g, [], x, 2, QUIET=true, SignSymmetry=true) 200 | @time opt = SparseSumOfRatios(-p, q, g, [], x, 2, QUIET=true, SignSymmetry=false) 201 | @time opt = SparseSumOfRatios(-p, q, g, [], x, 2, QUIET=true, dualize=true, SignSymmetry=false) 202 | @polyvar w[1:n-1] 203 | pop = [-sum(w); g; [p[i]-w[i]*q[i] for i=1:n-1]] 204 | @time opt,sol,data = cs_tssos_first(pop, [x;w], 4, numeq=n-1, TS="block", solution=false, QUIET=true) 205 | 206 | # Example 5.7 207 | N = 20 208 | s = 6 209 | n = N + s 210 | @polyvar x[1:n] 211 | p = [sum(x[i+j-1]*x[i+j] for j=1:s) for i=1:N] 212 | q = [1 + sum(j*x[i+j-1]^2 for j=1:s+1) for i = 1:N] 213 | g = [1 - x[i]^2 for i=1:n] 214 | @time opt = SparseSumOfRatios(p, q, g, [], x, 3, QUIET=true, SignSymmetry=true) 215 | @time opt = SparseSumOfRatios(p, q, g, [], x, 3, QUIET=true, SignSymmetry=false) 216 | @time opt = SparseSumOfRatios(p, q, g, [], x, 3, QUIET=true, dualize=true, SignSymmetry=false) 217 | 218 | @polyvar w[1:N] 219 | pop = [sum(w); g; [p[i]-w[i]*q[i] for i=1:N]] 220 | @time begin 221 | opt,sol,data = cs_tssos_first(pop, [x;w], 3, numeq=N, TS="block", solve=false, solution=false, QUIET=true) 222 | opt,sol,data = cs_tssos_higher!(data, TS="block", solution=false, QUIET=true) 223 | end 224 | 225 | # Example 6.1 226 | Random.seed!(0) 227 | n = 4 228 | N = 10 229 | @polyvar x[1:2*n] 230 | p = Polynomial{true, Float64}[] 231 | q = Polynomial{true, Float64}[] 232 | for i in 1:N 233 | A = rand(n, n) 234 | B = rand(n, n) 235 | push!(p, x[1:n]'*(A+A')*x[1:n] - 2*x[1:n]'*(B-B')*x[n+1:2*n] + x[n+1:2*n]'*(A+A')*x[n+1:2*n]) 236 | C = rand(n, n) 237 | D = rand(n, n) 238 | push!(q, x[1:n]'*(C'*C + D'*D)*x[1:n] - 2*x[1:n]'*(C'*D - D'*C)*x[n+1:2*n] + x[n+1:2*n]'*(C'*C + D'*D)*x[n+1:2*n]) 239 | end 240 | h = [1.0 - sum(x.^2)] 241 | 242 | d = 2 243 | @time opt = SumOfRatios(-p, q, [], h, x, d, QUIET=true, SignSymmetry=true) 244 | @time opt = SumOfRatios(-p, q, [], h, x, d, QUIET=true, SignSymmetry=false) 245 | @time opt = SumOfRatios(-p, q, [], h, x, d, QUIET=true, dualize=true, SignSymmetry=false) 246 | -------------------------------------------------------------------------------- /example/chebyshev.jl: -------------------------------------------------------------------------------- 1 | using DynamicPolynomials 2 | using TSSOS 3 | using JuMP 4 | using MosekTools 5 | 6 | @polyvar x[1:3] 7 | f = x[1]*x[2]*x[3] 8 | g = [1-x[1]^2, 1-x[2]^2, 1-x[3]^2] 9 | 10 | opt,sol,data = tssos_first([f; g], x, 2, TS="block", QUIET=false) 11 | # opt,sol,data = tssos_higher!(data, TS="block", QUIET=false) 12 | 13 | d = 2 14 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 15 | set_optimizer_attribute(model, MOI.Silent(), false) 16 | @variable(model, lower) 17 | info = add_psatz_cheby!(model, f-lower, x, g, [], d, TS="block", SO=1) 18 | @objective(model, Max, lower) 19 | optimize!(model) 20 | objv = objective_value(model) 21 | @show objv 22 | -------------------------------------------------------------------------------- /example/cpop.jl: -------------------------------------------------------------------------------- 1 | using DynamicPolynomials 2 | using TSSOS 3 | using Random 4 | 5 | function cbasis(z) 6 | basis = Poly{Int}[1] 7 | for i = 1:length(z) 8 | push!(basis, z[i]) 9 | end 10 | for i = 1:length(z), j = i:length(z) 11 | push!(basis, z[i]*z[j]) 12 | end 13 | return basis 14 | end 15 | 16 | # minimizing a random complex quartic polynomial over the unit sphere 17 | Random.seed!(1) 18 | n = 10 19 | @complex_polyvar z[1:n] 20 | basis = cbasis(z) 21 | P = randn(length(basis), length(basis)) 22 | Q = randn(length(basis), length(basis)) 23 | f = basis'*((P+P')/2+im*(Q-Q')/2)*basis 24 | @time opt,sol,data = complex_tssos_first([f; z'*z - 1], z, 2, numeq=1, QUIET=true, solve=true, TS=false) 25 | @time opt,sol,data = complex_tssos_first([f; z'*z - 1], z, 3, numeq=1, QUIET=true, solve=true, TS=false) 26 | 27 | using LinearAlgebra 28 | Random.seed!(1) 29 | n = 1 30 | @complex_polyvar x 31 | basis = cbasis([x]) 32 | P = rand(length(basis), length(basis)) 33 | # Q = rand(length(basis), length(basis)) 34 | # A = (P+P')/2 + im*(Q-Q')/2 + 3*I(length(basis)) 35 | A = (P+P')/2 + I(length(basis)) 36 | A = [0 1 1; 1 1 0; 1 0 1] 37 | f = basis'*A*basis + 0.5 38 | @time opt,sol,data = complex_tssos_first([f], [x], 2, QUIET=true, normality=0, ConjugateBasis=false, TS=false) 39 | @time opt,sol,data = complex_tssos_first([f], [x], 2, QUIET=true, ConjugateBasis=true, Gram=true, TS=false) 40 | 41 | # minimizing a random complex quartic polynomial with unit-norm variables 42 | Random.seed!(1) 43 | n = 5 44 | @complex_polyvar z[1:n] 45 | basis = cbasis(z) 46 | P = rand(length(basis), length(basis)) 47 | Q = rand(length(basis), length(basis)) 48 | pop = [basis'*((P+P')/2+im*(Q-Q')/2)*basis] 49 | # pop = [basis'*((P+P')/2)*basis] 50 | @time opt1,sol,data = complex_tssos_first(pop, z, 2, nb=n, QUIET=true, CS=false, ConjugateBasis=false) 51 | @time opt2,sol,data = complex_tssos_first(pop, z, 2, nb=n, QUIET=true, CS=false, ConjugateBasis=true) 52 | 53 | # minimizing large-scale randomly generated complex QCQPs 54 | Random.seed!(1) 55 | b = 10 56 | l = 120 57 | n = (b-5)*l + 5 58 | supp = Vector{Vector{Vector{Vector{UInt16}}}}(undef, l+1) 59 | coe = Vector{Vector{ComplexF64}}(undef, l+1) 60 | supp[1] = [] 61 | coe[1] = [] 62 | for i = 1:l, j = 1:2b 63 | if j < 3 64 | p1 = sort(ceil.(UInt16, ((b-5)*i-(b-5)).+rand(1).*b)) 65 | push!(supp[1], [p1, []], [[], p1]) 66 | elseif j < 7 67 | p1 = sort(ceil.(UInt16, ((b-5)*i-(b-5)).+rand(1).*b)) 68 | p2 = sort(ceil.(UInt16, ((b-5)*i-(b-5)).+rand(1).*b)) 69 | push!(supp[1], [p1, p2], [p2, p1]) 70 | elseif j < 13 71 | p1 = sort(ceil.(UInt16, ((b-5)*i-(b-5)).+rand(1).*b)) 72 | p2 = sort(ceil.(UInt16, ((b-5)*i-(b-5)).+rand(2).*b)) 73 | push!(supp[1], [p1, p2], [p2, p1]) 74 | else 75 | p1 = sort(ceil.(UInt16, ((b-5)*i-(b-5)).+rand(2).*b)) 76 | p2 = sort(ceil.(UInt16, ((b-5)*i-(b-5)).+rand(2).*b)) 77 | push!(supp[1], [p1, p2], [p2, p1]) 78 | end 79 | c1 = 2*rand(1)[1]-1 80 | c2 = 2*rand(1)[1]-1 81 | push!(coe[1], c1+c2*im, c1-c2*im) 82 | end 83 | supp[1],coe[1] = TSSOS.resort(supp[1],coe[1]) 84 | for i = 1:l 85 | supp[i+1] = [[[[], []]]; [[[j], [j]] for j=(b-5)*i-(b-6):(b-5)*i+5]] 86 | coe[i+1] = [1; -ones(b)] 87 | end 88 | 89 | @time opt,sol,data = complex_cs_tssos_first(supp, coe, n, 2, numeq=l, TS="MD") 90 | 91 | # AC-OPF problem 92 | include("D:/Programs/TSSOS/example/modelopf.jl") 93 | cd("D:/Programs/PolyOPF/pglib") 94 | silence() 95 | 96 | case = "pglib_opf_case30_as" 97 | AC = 2178.08 98 | opfdata = parse_file(case * ".m") 99 | model = pop_opf_com_vol(opfdata, normal=true, AngleCons=true, LineLimit=true) 100 | n = model.n 101 | m = model.m 102 | numeq = model.numeq 103 | supp = model.supp 104 | coe = model.coe 105 | mc = maximum(abs.(coe[1])) 106 | coe[1] = coe[1]./mc 107 | 108 | t = @elapsed begin 109 | opt,_,popd = complex_cs_tssos_first(supp, coe, n, "min", numeq=numeq, CS="MF", TS="block", QUIET=true, MomentOne=false) 110 | end 111 | opt *= mc 112 | maxc = maximum(popd.cliquesize) # maximal clique size 113 | mb = 2*maximum(maximum.([maximum.(popd.blocksize[i]) for i = 1:popd.cql])) # maximal block size 114 | gap = 100*(AC-opt)/AC # optimality gap 115 | println("n = $n, m = $m") 116 | println("mc = $maxc, opt = $opt, time = $t, mb = $mb, gap = $gap%") -------------------------------------------------------------------------------- /example/craig.jl: -------------------------------------------------------------------------------- 1 | using JuMP 2 | using MosekTools 3 | using DynamicPolynomials 4 | using MultivariatePolynomials 5 | using TSSOS 6 | 7 | ## Example 2 8 | @polyvar x[1:5] 9 | Φ = [1 - x[1]^4 - x[2]^4 + 0.1*x[3]^4, 10*x[3]^4 - x[1]^4 - x[2]^4] 10 | ψ = [4*x[4]^2*(x[1]^2 + x[2]^2) - (sum(x[1:4].^2) - x[5]^2)^2, 6 - x[4], x[4] - 4, 1 - x[5], x[5] - 0.5] 11 | @polyvar z # homogenization variable 12 | Φ = homogenize.(Φ, z) 13 | ψ = homogenize.(ψ, z) 14 | d = 2 # relaxation order 15 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 16 | set_optimizer_attribute(model, MOI.Silent(), false) 17 | # generate an interpolant polynomial 18 | # hc = @variable(model, [1:3]) 19 | # hb = x[1:3].^2 20 | # h = 1 + hc'*hb 21 | h,hc,hb = add_poly!(model, x[1:3], 2) 22 | @constraint(model, sum(hc)==1) 23 | hh = homogenize(h, z) 24 | add_psatz!(model, hh, [x[1:3]; z], [Φ; z], [1-z^2-sum(x[1:3].^2)], d, QUIET=true, CS=false, TS=false) 25 | add_psatz!(model, -hh, [x; z], [ψ; z], [1-z^2-sum(x.^2)], d, QUIET=true, CS=false, TS=false) 26 | optimize!(model) 27 | status = termination_status(model) 28 | if status != MOI.OPTIMAL 29 | println("termination status: $status") 30 | status = primal_status(model) 31 | println("solution status: $status") 32 | end 33 | 34 | # retrieve the interpolant polynomial 35 | p = value.(hc)'*hb 36 | @show p -------------------------------------------------------------------------------- /example/dynamicsystem.jl: -------------------------------------------------------------------------------- 1 | using JuMP 2 | using MosekTools 3 | using DynamicPolynomials 4 | using TSSOS 5 | 6 | n = 3 7 | @polyvar x[1:n] 8 | f = [(x[1]^2+x[2]^2-1/4)*x[1], (x[2]^2+x[3]^2-1/4)*x[2], (x[2]^2+x[3]^2-1/4)*x[3]] 9 | g = [1-x[1]^2, 1-x[2]^2, 1-x[3]^2] 10 | 11 | d = 3 12 | vsupp,vblocks,wsupp,wblocks,status = get_dynamic_sparsity(f, g, x, d, TS=["block","block"], SO=[2,1]) 13 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 14 | set_optimizer_attribute(model, MOI.Silent(), true) 15 | v, vc, vb = add_poly!(model, x, vsupp) 16 | w, wc, wb = add_poly!(model, x, wsupp) 17 | Lv = v - sum(f .* differentiate(v, x)) 18 | info1 = add_psatz!(model, Lv, x, g, [], d, blocks=[vblocks], constrs="con1") 19 | info2 = add_psatz!(model, w, x, g, [], d, blocks=[wblocks], constrs="con2") 20 | info3 = add_psatz!(model, w-v-1, x, g, [], d, blocks=[wblocks], constrs="con3") 21 | moment = get_moment(wb, -ones(n), ones(n)) 22 | @objective(model, Min, sum(moment.*wc)) 23 | optimize!(model) 24 | objv = objective_value(model) 25 | @show objv 26 | ## objv = 3.437648 27 | -------------------------------------------------------------------------------- /example/hpop.jl: -------------------------------------------------------------------------------- 1 | using DynamicPolynomials 2 | using TSSOS 3 | using Random 4 | 5 | # Example 5.1 6 | @polyvar x[1:4] 7 | f = x[3]^2*(x[1]^2 + x[1]^4*x[2]^2 + x[3]^4 - 3x[1]^2*x[2]^2) + x[2]^8 + x[1]^2*x[2]^2*x[4]^2 8 | # Homogenization without CS 9 | solve_hpop(f, x, [], [], 5, QUIET=true, CS=false, TS="block") 10 | # Homogenization with CS type 1 11 | solve_hpop(f, x, [], [], 5, QUIET=true, type=1, TS="block", SO=2, nnhomovar=true) 12 | # Homogenization with CS type 2 13 | solve_hpop(f, x, [], [], 5, QUIET=true, type=2, TS="block") 14 | # Homogenization with CS type 3 15 | solve_hpop(f, x, [], [], 5, QUIET=true, type=3, TS="block") 16 | # No homogenization with CS 17 | opt,sol,data = cs_tssos_first([f], x, 5, TS="block", solution=true, QUIET=true) 18 | 19 | ####################################################################### 20 | # Example 5.0 21 | @polyvar x[1:6] 22 | f = x[1]^6 + x[2]^6 + 1 + 3*x[1]^2*x[2]^2 - x[1]^4*(x[2]^2 + 1) - x[2]^4*(x[1]^2 + 1) - (x[1]^2 + x[2]^2) + x[3]^2*(x[1]^2 + x[5]^2 - 2)^2 + 23 | (x[4] + x[5] + 1)^2*x[6]^2 + (x[6] - 1)^6 24 | # Homogenization without CS 25 | solve_hpop(f, x, [], [], 4, QUIET=true, CS=false, TS="block", SO=2, nnhomovar=true) 26 | # Homogenization with CS type 1 27 | solve_hpop(f, x, [], [], 5, QUIET=true, type=1, ε=1e-4, TS="block", SO=2, nnhomovar=true) 28 | # Homogenization with CS type 2 29 | solve_hpop(f, x, [], [], 5, QUIET=true, type=2, TS="block", SO=2, nnhomovar=true) 30 | # Homogenization with CS type 3 31 | solve_hpop(f, x, [], [], 5, QUIET=true, type=3, TS="block", SO=2, nnhomovar=true) 32 | # No homogenization with CS 33 | @time begin 34 | opt,sol,data = cs_tssos_first([f], x, 7, TS="block", solution=true, QUIET=true) 35 | end 36 | # Find a local solution 37 | obj,sol,status = local_solution(data.n, data.m, data.supp, data.coe, startpoint=rand(data.n)) 38 | 39 | ####################################################################### 40 | # Example 5.2 41 | @polyvar x[1:10] 42 | f1 = sum(x[1:4].^4) + (1-x[1])*(1-x[2])*(1-x[3])*(1-x[4]) + (x[1]-1)*(x[1]-x[2])*(x[1]-x[3])*(x[1]-x[4]) + (x[2]-1)*(x[2]-x[1])*(x[2]-x[3])*(x[2]-x[4]) + (x[3]-1)*(x[3]-x[1])*(x[3]-x[2])*(x[3]-x[4]) + (x[4]-1)*(x[4]-x[1])*(x[4]-x[2])*(x[4]-x[3]) 43 | f2 = sum(x[4:7].^4) + (1-x[4])*(1-x[5])*(1-x[6])*(1-x[7]) + (x[4]-1)*(x[4]-x[5])*(x[4]-x[6])*(x[4]-x[7]) + (x[5]-1)*(x[5]-x[4])*(x[5]-x[6])*(x[5]-x[7]) + (x[6]-1)*(x[6]-x[4])*(x[6]-x[5])*(x[6]-x[7]) + (x[7]-1)*(x[7]-x[4])*(x[7]-x[5])*(x[7]-x[6]) 44 | f3 = sum(x[7:10].^4) + (1-x[7])*(1-x[8])*(1-x[9])*(1-x[10]) + (x[7]-1)*(x[7]-x[8])*(x[7]-x[9])*(x[7]-x[10]) + (x[8]-1)*(x[8]-x[7])*(x[8]-x[9])*(x[8]-x[10]) + (x[9]-1)*(x[9]-x[7])*(x[9]-x[8])*(x[9]-x[10]) + (x[10]-1)*(x[10]-x[7])*(x[10]-x[8])*(x[10]-x[9]) 45 | f = f1 + f2 + f3 46 | # Homogenization without CS 47 | solve_hpop(f, x, [], [], 2, QUIET=true, CS=false, TS="block") 48 | # Homogenization with CS type 1 49 | solve_hpop(f, x, [], [], 2, QUIET=true, type=1, TS="block", SO=2, nnhomovar=true) 50 | # Homogenization with CS type 2 51 | solve_hpop(f, x, [], [], 2, QUIET=true, type=2, TS="block") 52 | # Homogenization with CS type 3 53 | solve_hpop(f, x, [], [], 2, QUIET=true, type=3, TS="block") 54 | # No homogenization with CS 55 | @time begin 56 | opt,sol,data = cs_tssos_first([f], x, 4, TS="block", solution=true, QUIET=true) 57 | end 58 | 59 | ####################################################################### 60 | # Example 5.3 61 | @polyvar x[1:20] 62 | f1 = x[1]^2*(x[1]-1)^2 + x[2]^2*(x[2]-1)^2 + x[3]^2*(x[3]-1)^2 + 2*x[1]*x[2]*x[3]*(sum(x[1:3])-2) + 0.25*((x[1]-1)^2+(x[2]-1)^2+(x[3]-1)^2+(x[4]-1)^2) + (x[4]*x[5]-1)^2 63 | f2 = x[1]^2*(x[1]-1)^2 + x[2]^2*(x[2]-1)^2 + x[6]^2*(x[6]-1)^2 + 2*x[1]*x[2]*x[6]*(sum(x[1:2])+x[6]-2) + 0.25*((x[1]-1)^2+(x[2]-1)^2+(x[6]-1)^2+(x[7]-1)^2) + (x[7]*x[8]-1)^2 64 | f3 = x[1]^2*(x[1]-1)^2 + x[2]^2*(x[2]-1)^2 + x[9]^2*(x[9]-1)^2 + 2*x[1]*x[2]*x[9]*(sum(x[1:2])+x[9]-2) + 0.25*((x[1]-1)^2+(x[2]-1)^2+(x[9]-1)^2+(x[10]-1)^2) + (x[10]*x[11]-1)^2 65 | f4 = x[1]^2*(x[1]-1)^2 + x[2]^2*(x[2]-1)^2 + x[12]^2*(x[12]-1)^2 + 2*x[1]*x[2]*x[12]*(sum(x[1:2])+x[12]-2) + 0.25*((x[1]-1)^2+(x[2]-1)^2+(x[12]-1)^2+(x[13]-1)^2) + (x[13]*x[14]-1)^2 66 | f5 = x[1]^2*(x[1]-1)^2 + x[2]^2*(x[2]-1)^2 + x[15]^2*(x[15]-1)^2 + 2*x[1]*x[2]*x[15]*(sum(x[1:2])+x[15]-2) + 0.25*((x[1]-1)^2+(x[2]-1)^2+(x[15]-1)^2+(x[16]-1)^2) + (x[16]*x[17]-1)^2 67 | f6 = x[1]^2*(x[1]-1)^2 + x[2]^2*(x[2]-1)^2 + x[18]^2*(x[18]-1)^2 + 2*x[1]*x[2]*x[18]*(sum(x[1:2])+x[18]-2) + 0.25*((x[1]-1)^2+(x[2]-1)^2+(x[18]-1)^2+(x[19]-1)^2) + (x[19]*x[20]-1)^2 68 | f = f1 + f2 + f3 + f4 + f5 + f6 69 | # Homogenization without CS 70 | solve_hpop(f, x, [], [], 2, QUIET=true, CS=false, TS="block") 71 | # Homogenization with CS type 1 72 | solve_hpop(f, x, [], [], 2, QUIET=true, type=1, TS="block", SO=2, nnhomovar=true) 73 | # Homogenization with CS type 2 74 | solve_hpop(f, x, [], [], 3, QUIET=true, type=2, TS="block", SO=1, nnhomovar=true) 75 | # Homogenization with CS type 3 76 | solve_hpop(f, x, [], [], 3, QUIET=true, type=3, TS="block", SO=1, nnhomovar=true) 77 | # No homogenization with CS 78 | @time begin 79 | opt,sol,data = cs_tssos_first([f], x, 2, TS="block", solution=false, QUIET=true) 80 | end 81 | 82 | ####################################################################### 83 | # Example 5.4 84 | @polyvar x[1:5] 85 | f = x[1]^2 + 3x[2]^2 - 2x[2]*x[3]^2 + x[3]^4 - x[2]*(x[4]^2 + x[5]^2) 86 | g = [x[2]-1; x[1]^2-2*x[1]*x[2]-1; x[1]^2+2*x[1]*x[2]-1; x[2]-x[4]^2-x[5]^2] 87 | # Homogenization without CS 88 | solve_hpop(f, x, g, [], 4, QUIET=true, CS=false, TS="block", SO=2) 89 | # Homogenization with CS type 1 90 | solve_hpop(f, x, g, [], 4, QUIET=true, type=1, ε=1e-4, TS="block", SO=2) 91 | # Homogenization with CS type 2 92 | solve_hpop(f, x, g, [], 4, QUIET=true, type=2, TS="block", SO=2) 93 | # Homogenization with CS type 3 94 | solve_hpop(f, x, g, [], 4, QUIET=true, type=3, TS="block", SO=2) 95 | # No homogenization with CS 96 | @time begin 97 | opt,sol,data = cs_tssos_first([f; g], x, 2, TS="block", solution=false, QUIET=true) 98 | end 99 | # Find a local solution 100 | # obj,sol,status = local_solution(data.n, data.m, data.supp, data.coe, startpoint=rand(data.n)) 101 | 102 | ####################################################################### 103 | # Example 5.5 104 | @polyvar x[1:7] 105 | f = x[1]^4*x[2]^2 + x[2]^4*x[3]^2 + x[1]^2*x[3]^4 - 3*(x[1]*x[2]*x[3])^2 + x[2]^2 + x[7]^2*(sum(x[1:3].^2)) + 106 | x[4]^2*x[5]^2*(10 - x[6]^2) + x[7]^2*(x[4]^2 + 2x[5]^2 + 3x[6]^2) 107 | g = [x[1]-x[2]*x[3], -x[2]+x[3]^2, 1-sum(x[4:6].^2)] 108 | # Homogenization without CS 109 | solve_hpop(f, x, g, [], 5, QUIET=true, CS=false, TS="block", SO=2, nnhomovar=true) 110 | # Homogenization with CS type 1 111 | solve_hpop(f, x, g, [], 5, QUIET=true, type=1, ε=1e-4, TS="block", SO=2, nnhomovar=true) 112 | # Homogenization with CS type 2 113 | solve_hpop(f, x, g, [], 5, QUIET=true, type=2, TS="block", SO=2, nnhomovar=true) 114 | # Homogenization with CS type 3 115 | solve_hpop(f, x, g, [], 5, QUIET=true, type=3, TS="block", SO=2, nnhomovar=true) 116 | # No homogenization with CS 117 | @time begin 118 | opt,sol,data = cs_tssos_first([f; g], x, 3, TS="block", solution=true, QUIET=true) 119 | end 120 | 121 | ####################################################################### 122 | # Example 5.6 123 | p = 3 124 | @polyvar x[1:8*p+2] 125 | f = 0 126 | for i = 1:p 127 | f += (sum(x[8*i-7:8*i+2].^2)+1)^2 - 4*(x[8*i-7]^2*x[8*i-6]^2+x[8*i-6]^2*x[8*i-5]^2+x[8*i-5]^2*x[8*i-4]^2+x[8*i-4]^2*x[8*i-3]^2+x[8*i-3]^2*x[8*i-7]^2) - 4*(x[8*i-2]^2*x[8*i-1]^2+x[8*i-1]^2*x[8*i]^2+x[8*i]^2*x[8*i+1]^2+x[8*i+1]^2*x[8*i+2]^2+x[8*i+2]^2*x[8*i-2]^2) + 0.2*sum(x[8*i-7:8*i+2].^4) 128 | end 129 | g = [sum(x[8*i-7:8*i+2].^2) - 1 for i=1:p] 130 | # Homogenization without CS 131 | solve_hpop(f, x, g, [], 4, QUIET=true, CS=false, TS="block") 132 | # Homogenization with CS type 1 133 | solve_hpop(f, x, g, [], 4, QUIET=true, type=1, ε=1e-4, TS="block") 134 | # Homogenization with CS type 2 135 | solve_hpop(f, x, g, [], 4, QUIET=true, type=2, TS="block") 136 | # Homogenization with CS type 3 137 | solve_hpop(f, x, g, [], 4, QUIET=true, type=3, TS="block") 138 | # No homogenization with CS 139 | @time begin 140 | opt,sol,data = cs_tssos_first([f; g], x, 4, TS="block", solution=true, QUIET=true) 141 | end 142 | 143 | ####################################################################### 144 | # Example 5.7 145 | Random.seed!(0) 146 | n = 40 147 | u = 3 148 | p = trunc(Int, n/u) 149 | @polyvar x[1:n] 150 | A = rand(u, u) 151 | b = rand(u) 152 | f = (x[1:u].^2)'*A'*A*(x[1:u].^2) + b'*(x[1:u].^2) 153 | g = [sum(x[1:u].^4) - 1] 154 | for i = 2:p-1 155 | A = rand(u+1, u+1) 156 | b = rand(u+1) 157 | f += (x[u*(i-1):u*i].^2)'*A'*A*(x[u*(i-1):u*i].^2) + b'*(x[u*(i-1):u*i].^2) 158 | g = [g; sum(x[u*(i-1):u*i].^4) - 1] 159 | end 160 | A = rand(n-u*(p-1)+1, n-u*(p-1)+1) 161 | b = rand(n-u*(p-1)+1) 162 | f += (x[u*(p-1):n].^2)'*A'*A*(x[u*(p-1):n].^2) + b'*(x[u*(p-1):n].^2) 163 | g = [g; sum(x[u*(p-1):n].^4) - 1] 164 | # Homogenization without CS 165 | solve_hpop(f, x, g, [], 4, QUIET=true, CS=false, TS="block") 166 | # Homogenization with CS type 1 167 | solve_hpop(f, x, g, [], 4, QUIET=true, type=1, ε=1e-4, TS="block") 168 | # Homogenization with CS type 2 169 | solve_hpop(f, x, g, [], 4, QUIET=true, type=2, TS="block") 170 | # Homogenization with CS type 3 171 | solve_hpop(f, x, g, [], 4, QUIET=true, type=3, TS="block") 172 | # No homogenization with CS 173 | @time begin 174 | opt,sol,data = cs_tssos_first([f; g], x, 2, TS="block", solution=false, QUIET=true) 175 | end 176 | # Find a local solution 177 | obj,sol,status = local_solution(data.n, data.m, data.supp, data.coe, startpoint=rand(data.n)) 178 | -------------------------------------------------------------------------------- /example/ljc.jl: -------------------------------------------------------------------------------- 1 | using TSSOS 2 | using DynamicPolynomials 3 | 4 | N = 20 5 | @polyvar x[1:N] 6 | @polyvar y[1:N] 7 | @polyvar z[1:N] 8 | @polyvar τ[1:Int(N*(N-1)/2)] 9 | 10 | f = 0 11 | for i = 1:N-1, j = i+1:N 12 | f += τ[(i-1)*N - Int(i*(i+1)/2) + j]^6 - τ[(i-1)*N - Int(i*(i+1)/2) + j]^3 13 | end 14 | pop = [f] 15 | for i = 1:N-1, j = i+1:N 16 | push!(pop, τ[(i-1)*N - Int(i*(i+1)/2) + j]*((x[i]-x[j])^2 + (y[i]-y[j])^2 + (z[i]-z[j])^2) - 1) 17 | end 18 | 19 | opt,sol,data = cs_tssos_first(pop, [x;y;z;τ], 3, numeq=length(pop)-1) 20 | -------------------------------------------------------------------------------- /example/pmi.jl: -------------------------------------------------------------------------------- 1 | using DynamicPolynomials 2 | using TSSOS 3 | using LinearAlgebra 4 | using Random 5 | 6 | ## Inf mineig(F(x)) s.t. G1(x) >= 0, ..., Gm(x) >= 0 7 | @polyvar x[1:2] 8 | Q = [1/sqrt(2) -1/sqrt(3) 1/sqrt(6); 0 1/sqrt(3) 2/sqrt(6); 1/sqrt(2) 1/sqrt(3) -1/sqrt(6)] 9 | F = Q*[-x[1]^2-x[2]^2 0 0; 0 -1/4*(x[1]+1)^2-1/4*(x[2]-1)^2 0; 0 0 -1/4*(x[1]-1)^2-1/4*(x[2]+1)^2]*Q' 10 | G = [1-4x[1]*x[2] x[1]; x[1] 4-x[1]^2-x[2]^2] 11 | opt,data = tssos_first(F, [G], x, 2, TS="block", QUIET=true) 12 | opt,data = tssos_higher!(data, QUIET=true) 13 | 14 | @polyvar x[1:3] 15 | F = [1+x[1]^2 x[1]^2 x[2]^2; x[1]^2 1 x[3]^2; x[2]^2 x[3]^2 1] 16 | G = [2-x[1]^2 1 x[1]+x[2]+x[3]; 1 2-x[2]^2 1; x[1]+x[2]+x[3] 1 2-x[3]^2] 17 | opt,data = tssos_first(F, [G], x, 2, TS="block", Gram=true, QUIET=true) 18 | opt,data = tssos_higher!(data, QUIET=true) 19 | 20 | ## polynomial matrix optimization with term sparsity 21 | @polyvar x[1:5] 22 | F = [x[1]^4 x[1]^2-x[2]*x[3] x[3]^2-x[4]*x[5] x[1]*x[4] x[1]*x[5]; 23 | x[1]^2-x[2]*x[3] x[2]^4 x[2]^2-x[3]*x[4] x[2]*x[4] x[2]*x[5]; 24 | x[3]^2-x[4]*x[5] x[2]^2-x[3]*x[4] x[3]^4 x[4]^2-x[1]*x[2] x[5]^2-x[3]*x[5]; 25 | x[1]*x[4] x[2]*x[4] x[4]^2-x[1]*x[2] x[4]^4 x[4]^2-x[1]*x[3]; 26 | x[1]*x[5] x[2]*x[5] x[5]^2-x[3]*x[5] x[4]^2-x[1]*x[3] x[5]^4] 27 | G = Vector{Matrix{Poly}}(undef, 2) 28 | G[1] = [1-x[1]^2-x[2]^2 x[2]*x[3]; x[2]*x[3] 1-x[3]^2] 29 | G[2] = [1-x[4]^2 x[4]*x[5]; x[4]*x[5] 1-x[5]^2] 30 | r = 4 31 | @time opt,data = tssos_first(F, G, x, r, TS=false, QUIET=true) 32 | @time opt,data = tssos_first(F, G, x, r, TS="block", QUIET=true) 33 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 34 | @time opt,data = tssos_higher!(data, TS="block", QUIET=true) 35 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 36 | @time opt,data = tssos_first(F, G, x, r, TS="MD", QUIET=true, merge=true, md=1.1) 37 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 38 | @time opt,data = tssos_higher!(data, TS="MD", QUIET=true, merge=true, md=1.1) 39 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 40 | 41 | ## polynomial matrix optimization with term sparsity 42 | Random.seed!(1) 43 | @polyvar x[1:3] 44 | p = 60 45 | A = rand(p, p) 46 | A = (A+A')/2 47 | B = rand(p, p) 48 | B = (B+B')/2 49 | F = (1-x[1]^2-x[2]^2)*I(p) + (x[1]^2-x[3]^2)*A + (x[1]^2*x[3]^2-2x[2]^2)*B 50 | G = [1-x[1]^2-x[2]^2 x[2]*x[3]; x[2]*x[3] 1-x[3]^2] 51 | r = 2 52 | @time opt,data = tssos_first(F, [G], x, r, TS="block", QUIET=true) 53 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 54 | @time opt,data = tssos_higher!(data, TS="block", QUIET=true) 55 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 56 | @time opt,data = tssos_first(F, [G], x, r, TS="MD", QUIET=true, merge=true) 57 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 58 | @time opt,data = tssos_higher!(data, TS="MD", QUIET=true, merge=true) 59 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 60 | @time opt,data = tssos_first(F, [G], x, r, TS=false, QUIET=false) 61 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 62 | 63 | 64 | ## Inf b'*λ s.t. F0 + λ1*F1 + ... λt*Ft >=0 on {x ∈ R^n | G1(x) >= 0, ..., Gm(x) >= 0} 65 | ## polynomial matrix optimization with term sparsity 66 | @polyvar x[1:3] 67 | F = Vector{Matrix{Poly}}(undef, 3) 68 | F[1] = sum(x.^2)*[x[2]^4 0 0; 0 x[3]^4 0; 0 0 x[1]^4] 69 | F[2] = sum(x.^2)*[0 x[1]^2*x[2]^2 0; x[1]^2*x[2]^2 0 0; 0 0 0] 70 | F[3] = sum(x.^2)*[x[1]^4 0 0; 0 x[2]^4 x[2]^2*x[3]^2; 0 x[2]^2*x[3]^2 x[3]^4] 71 | G = [1 - sum(x.^2)] 72 | @time opt,data = LinearPMI_first([-10, 1], F, G, x, 3, TS="block", QUIET=true) 73 | @time opt,data = LinearPMI_higher!(data, TS="block", QUIET=true) 74 | 75 | 76 | ## polynomial matrix optimization with correlative sparsity 77 | @polyvar x[1:2] 78 | F = [2 0; 0 0]*(x[1]-1)^2 + [0 0; 0 2]*(x[1]-2)^2 + [1 -1; -1 1]*(x[2]-1)^2 + [1 1; 1 1]*(x[2]-2)^2 79 | G = [4 - x[1]^2, 4 - x[2]^2] 80 | d = 2 81 | opt,data = cs_tssos_first(F, G, x, d, TS=false, QUIET=true, Moment=true) 82 | sol = extract_solutions_pmo(1, d, 2, data.moment[2]) 83 | W = extract_weight_matrix(1, d, 2, sol, data.moment[2]) 84 | sol = extract_solutions_pmo_robust(1, d, 2, data.moment[1]) 85 | 86 | @polyvar x[1:2] 87 | @polyvar y[1:2] 88 | F = [2 0; 0 0]*(x[1]-1)^2 + [0 0; 0 2]*(x[1]-2)^2 + [1 -1; -1 1]*(x[2]-1)^2 + [1 1; 1 1]*(x[2]-2)^2 89 | G = [4 - x[1]^2, 4 - x[2]^2] 90 | d = 2 91 | opt,sol,data = cs_tssos_first([y'*F*y; G; 1-sum(y.^2)], [x;y], d, numeq=1, TS=false, QUIET=true) 92 | 93 | @polyvar x[1:3] 94 | Q = [1/sqrt(2) -1/sqrt(3) 1/sqrt(6); 0 1/sqrt(3) 2/sqrt(6); 1/sqrt(2) 1/sqrt(3) -1/sqrt(6)] 95 | F = (-x[1]^2 + x[2])*(Q[:,1]*Q[:,1]'+Q[:,2]*Q[:,2]') + (x[2]^2 + x[3]^2)*Q[:,3]*Q[:,3]' 96 | G = [1 - x[1]^2 - x[2]^2, 1 - x[2]^2 - x[3]^2, -1 + x[2]^2 + x[3]^2] 97 | opt,data = cs_tssos_first(F, G, x, 2, TS=false, QUIET=true, Moment=true) 98 | sol = extract_solutions_pmo(2, 2, 3, data.moment[2]) 99 | W = extract_weight_matrix(2, 2, 3, sol, data.moment[2]) 100 | sol = extract_solutions_pmo_robust(2, 2, 3, data.moment[1]) 101 | 102 | 103 | ## polynomial matrix optimization with correlative sparsity 104 | @polyvar x[1:5] 105 | F = [x[1]^4 x[1]^2-x[2]*x[3] x[3]^2-x[4]*x[5] 0.5 0.5; 106 | x[1]^2-x[2]*x[3] x[2]^4 x[2]^2-x[3]*x[4] 0.5 0.5; 107 | x[3]^2-x[4]*x[5] x[2]^2-x[3]*x[4] x[3]^4 x[4]^2-x[1]*x[2] x[5]^2-x[3]*x[4]; 108 | 0.5 0.5 x[4]^2-x[1]*x[2] x[4]^4 x[4]^2-x[1]*x[3]; 109 | 0.5 0.5 x[5]^2-x[3]*x[4] x[4]^2-x[1]*x[3] x[5]^4] 110 | G = Vector{Matrix{Poly}}(undef, 2) 111 | G[1] = [1-x[1]^2-x[2]^2 x[2]*x[3]; x[2]*x[3] 1-x[3]^2] 112 | G[2] = [1-x[4]^2 x[4]*x[5]; x[4]*x[5] 1-x[5]^2] 113 | r = 4 114 | @time opt,data = tssos_first(F, G, x, r, TS=false, QUIET=true) 115 | @time opt,data = cs_tssos_first(F, G, x, r, TS=false, QUIET=true) 116 | @time opt,data = cs_tssos_first(F, G, x, r, TS="block", QUIET=true) 117 | @time opt,data = cs_tssos_first(F, G, x, r, TS="MD", QUIET=true, merge=true, md=1.5) 118 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 119 | 120 | 121 | ## polynomial matrix optimization with correlative sparsity 122 | n = 13 123 | r = 2 124 | @polyvar x[1:n] 125 | F = [sum(x[k]^2 for k = 1:n-2) sum(x[k]*x[k+1] for k = 1:n-1) 1.0; 126 | sum(x[k]*x[k+1] for k = 1:n-1) sum(x[k]^2 for k = 2:n-1) sum(x[k]*x[k+2] for k = 1:n-2); 127 | 1 sum(x[k]*x[k+2] for k = 1:n-2) sum(x[k]^2 for k = 3:n)] 128 | G = Vector{Matrix{Poly}}(undef, n-2) 129 | for k = 1:n-2 130 | G[k] = [1-x[k]^2-x[k+1]^2 x[k+1]+0.5; x[k+1]+0.5 1-x[k+2]^2] 131 | end 132 | @time opt,data = tssos_first(F, G, x, r, TS=false, QUIET=true) 133 | @time opt,data = cs_tssos_first(F, G, x, r, TS=false, QUIET=true) 134 | @time opt,data = cs_tssos_first(F, G, x, r, TS="block", QUIET=true) 135 | @time opt,data = cs_tssos_first(F, G, x, r, TS="MD", QUIET=true) 136 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 137 | 138 | 139 | ## polynomial matrix optimization with matrix sparsity 140 | @polyvar x[1:5] 141 | F = [x[1]^4 x[1]^2-x[2]*x[3] x[3]^2-x[4]*x[5] 0 0; 142 | x[1]^2-x[2]*x[3] x[2]^4 x[2]^2-x[3]*x[4] 0 0; 143 | x[3]^2-x[4]*x[5] x[2]^2-x[3]*x[4] x[3]^4 x[4]^2-x[1]*x[2] x[5]^2-x[3]*x[4]; 144 | 0 0 x[4]^2-x[1]*x[2] x[4]^4 x[4]^2-x[1]*x[3]; 145 | 0 0 x[5]^2-x[3]*x[4] x[4]^2-x[1]*x[3] x[5]^4] 146 | G = Vector{Matrix{Poly{Float64}}}(undef, 2) 147 | G[1] = [1-x[1]^2-x[2]^2 x[2]*x[3]; x[2]*x[3] 1-x[3]^2] 148 | G[2] = [1-x[4]^2 x[4]*x[5]; x[4]*x[5] 1-x[5]^2] 149 | r = 4 150 | @time opt,data = tssos_first(F, G, x, r, TS=false, QUIET=true) 151 | @time opt,mb = sparseobj(F, G, x, r, TS=false, QUIET=true) 152 | @time opt,mb = sparseobj(F, G, x, r, TS="block", QUIET=true) 153 | @time opt,mb = sparseobj(F, G, x, r, TS="MD", QUIET=true, merge=true, md=1.3) 154 | 155 | 156 | ## polynomial matrix optimization with matrix sparsity 157 | @polyvar x[1:5] 158 | F = [x[1]^4+x[2]^4+1 x[1]*x[3]; x[1]*x[3] x[3]^4+x[4]^4+x[5]^4+0.5] 159 | G = Vector{Matrix{Poly}}(undef, 1) 160 | G[1] = [1-x[1]^2 x[1]*x[2] x[1]*x[3] 0 0; x[1]*x[2] 1-x[2]^2 x[2]*x[3] 0 0; x[1]*x[3] x[2]*x[3] 1-x[3]^2 x[3]*x[4] x[3]*x[5]; 0 0 x[3]*x[4] 1-x[4]^2 x[4]*x[5]; 0 0 x[3]*x[5] x[4]*x[5] 1-x[5]^2] 161 | @time opt,data = tssos_first(F, G, x, 4, TS=false, QUIET=true) 162 | 163 | @polyvar x[1:6] 164 | F = [x[1]^4+x[2]^4+1 x[1]*x[3]; x[1]*x[3] x[3]^4+x[4]^4+x[5]^4+0.5] 165 | G = Vector{Matrix{Poly}}(undef, 2) 166 | G[1] = [1-x[1]^2 x[1]*x[2] x[1]*x[3]; x[1]*x[2] 1-x[2]^2 x[2]*x[3]; x[1]*x[3] x[2]*x[3] x[6]^2] 167 | G[2] = [1-x[3]^2-x[6]^2 x[3]*x[4] x[3]*x[5]; x[3]*x[4] 1-x[4]^2 x[4]*x[5]; x[3]*x[5] x[4]*x[5] 1-x[5]^2] 168 | r = 4 169 | @time opt,data = cs_tssos_first(F, G, x, r, TS=false, QUIET=true) 170 | @time opt,data = cs_tssos_first(F, G, x, r, TS="block", QUIET=true) 171 | @time opt,data = cs_tssos_first(F, G, x, r, TS="MD", QUIET=true) 172 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 173 | 174 | 175 | ## polynomial matrix optimization with matrix sparsity 176 | n = 13 177 | @polyvar x[1:2n-2] 178 | F = [1 x[1]*x[2]; x[1]*x[2] 1+x[n]^2] 179 | G = Vector{Matrix{Poly}}(undef, n-1) 180 | G[1] = [1-x[1]^4 x[1]*x[2]; x[1]*x[2] x[n+1]^2] 181 | for k = 2:n-2 182 | G[k] = [1-x[k]^4 x[k]*x[k+1]; x[k]*x[k+1] x[n+k]^2-x[n+k-1]^2] 183 | end 184 | G[n-1] = [1-x[n-1]^4 x[n-1]*x[n]; x[n-1]*x[n] 1-x[n]^4-x[2n-2]^2] 185 | @time opt,data = cs_tssos_first(F, G, x, 4, TS=false, QUIET=true) 186 | @time opt,data = cs_tssos_first(F, G, x, 4, TS="block", QUIET=true) 187 | @time opt,data = cs_tssos_first(F, G, x, 4, TS="MD", QUIET=true) 188 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 189 | 190 | n = 7 191 | @polyvar x[1:n] 192 | F = [1 x[1]*x[2]; x[1]*x[2] 1+x[n]^2] 193 | G = Matrix{Poly}(undef, n, n) 194 | for i = 1:n, j = 1:n 195 | G[i,j] = 0 196 | end 197 | for k = 1:n 198 | G[k,k] = 1-x[k]^4 199 | end 200 | for k = 1:n-1 201 | G[k,n] = G[n,k] = x[k]*x[k+1] 202 | end 203 | @time opt,data = tssos_first(F, [G], x, 4, TS=false, QUIET=true) 204 | 205 | 206 | ## polynomial matrix optimization with matrix sparsity 207 | @polyvar x[1:3] 208 | p = 30 209 | mul = sum(x.^2)^3 210 | F = Vector{Matrix{Poly}}(undef, 3) 211 | F[1] = zeros(3p, 3p) 212 | F[2] = zeros(3p, 3p) 213 | F[3] = zeros(3p, 3p) 214 | for i = 1:p 215 | F[1][3*(i-1)+1,3*(i-1)+1] = mul*x[2]^4 216 | F[1][3*(i-1)+2,3*(i-1)+2] = mul*x[3]^4 217 | F[1][3*(i-1)+3,3*(i-1)+3] = mul*x[1]^4 218 | F[3][3*(i-1)+1,3*(i-1)+1] = mul*x[1]^4 219 | F[3][3*(i-1)+2,3*(i-1)+2] = mul*x[2]^4 220 | F[3][3*(i-1)+3,3*(i-1)+3] = mul*x[3]^4 221 | end 222 | for i = 2:2:3p 223 | if mod(i, 3) == 2 224 | F[2][i,i-1] = F[2][i-1,i] = mul*x[1]^2*x[2]^2 225 | elseif mod(i, 3) == 0 226 | F[2][i,i-1] = F[2][i-1,i] = mul*x[2]^2*x[3]^2 227 | else 228 | F[2][i,i-1] = F[2][i-1,i] = mul*x[1]^2*x[3]^2 229 | end 230 | end 231 | for i = 3:2:3p-1 232 | if mod(i, 3) == 2 233 | F[3][i,i-1] = F[3][i-1,i] = mul*x[1]^2*x[2]^2 234 | elseif mod(i, 3) == 0 235 | F[3][i,i-1] = F[3][i-1,i] = mul*x[2]^2*x[3]^2 236 | else 237 | F[3][i,i-1] = F[3][i-1,i] = mul*x[1]^2*x[3]^2 238 | end 239 | end 240 | @time opt,mb = sparseobj([-10, 1], F, [], x, 5, TS="block", QUIET=true) 241 | @time opt,mb = sparseobj([-10, 1], F, [], x, 5, TS=false, QUIET=true) 242 | 243 | 244 | n = 3 245 | @polyvar x[1:n] 246 | Q = [sqrt(1/2) -sqrt(1/3) sqrt(1/6); 0 sqrt(1/3) sqrt(2/3); sqrt(1/2) sqrt(1/3) -sqrt(1/6)] 247 | f1 = sum((x.-1).^2)/(n*(sqrt(1/2)-1)^2) 248 | f2 = sum((x[i]-x[i+1])^2 for i = 1:n-1) + 2 249 | f3 = sum((x[i]+x[i+1])^2 for i = 1:n-1) + 2 250 | F = Q*Diagonal([f1, f2, f3])*Q' 251 | G = [[1-x[i]^2 x[i]*x[i+1]; x[i]*x[i+1] 1-x[i+1]^2] for i = 1:n-1] 252 | @time opt,data = cs_tssos_first(F, G, x, 1, TS=false, QUIET=true) 253 | sol = extract_solutions_pmo(n, 2, 3, data.moment[1]) 254 | 255 | function basis(x) 256 | basis = Poly{Int}[1] 257 | # append!(basis, x) 258 | for i = 1:length(x), j = i:length(x) 259 | push!(basis, x[i]*x[j]) 260 | end 261 | return basis 262 | end 263 | 264 | function sparse_poly(basis, p) 265 | ind = ceil.(Int, rand(ceil(Int, length(basis)*p))*length(basis)) 266 | return randn(length(ind))'*basis[ind] 267 | end 268 | 269 | function sparse_polymat(x, p, d) 270 | P = Matrix{Poly}(undef, d, d) 271 | bas = basis(x) 272 | for i = 1:d, j = i:d 273 | P[i,j] = P[j,i] = sparse_poly(bas, p) 274 | end 275 | return P 276 | end 277 | 278 | # random exmaples 279 | Random.seed!(1) 280 | n = 4 281 | d = 4 282 | p = 0.04 283 | @polyvar x[1:3n+2] 284 | F = sum(sparse_polymat(x[3i-2:3i+2], p, d) for i = 1:n) 285 | G = Vector{Matrix{Poly}}(undef, 2n) 286 | for i = 1:n 287 | G[i] = sparse_polymat(x[3i-2:3i+2], p, d) + 2*sum(x[3i-2:3i+2].^2)*I(d) 288 | G[i+n] = [1 - sum(x[3i-2:3i+2].^2);;] 289 | end 290 | @time opt,data = cs_tssos_first(F, G, x, 2, TS="block", QUIET=true) 291 | # println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 292 | @time opt,data = cs_tssos_first(F, G, x, 2, TS="MD", QUIET=true) 293 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 294 | @time opt,data = cs_tssos_first(F, G, x, 2, TS=false, QUIET=true) 295 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 296 | @time opt,data = tssos_first(F, G, x, 2, TS=false, QUIET=true) 297 | println(maximum(maximum.([maximum.(data.blocksize[i]) for i = 1:data.cql]))) 298 | 299 | ## Extract solutions 300 | n = 2 301 | @polyvar x[1:n] 302 | F = [x[1]^4+1 x[1]*x[2]; x[1]*x[2] x[2]^4+1] 303 | G = [1 - sum(x.^2)] 304 | @time opt,data = tssos_first(F, G, x, 2, TS=false, QUIET=true) 305 | sol = extract_solutions_pmo(n, 2, 2, data.moment[1]) 306 | -------------------------------------------------------------------------------- /example/poly.jl: -------------------------------------------------------------------------------- 1 | function bfind(A, l, a) 2 | low = 1 3 | high = l 4 | while low <= high 5 | mid = Int(ceil(1/2*(low+high))) 6 | temp = A[mid] 7 | if temp == a 8 | return mid 9 | elseif temp < a 10 | low = mid+1 11 | else 12 | high = mid-1 13 | end 14 | end 15 | return nothing 16 | end 17 | 18 | function resort(supp, coe) 19 | nsupp = copy(supp) 20 | sort!(nsupp) 21 | unique!(nsupp) 22 | l = length(nsupp) 23 | ncoe = zeros(l) 24 | for i = 1:length(supp) 25 | locb = bfind(nsupp, l, supp[i]) 26 | ncoe[locb] += coe[i] 27 | end 28 | return nsupp,ncoe 29 | end 30 | 31 | # Broyden banded polynomial 32 | n = 20 33 | @polyvar x[1:n] 34 | f = 0 35 | for i = 1:n 36 | jset = max(1,i-5):min(n,i+1) 37 | jset = setdiff(jset,i) 38 | global f += (2x[i]+5*x[i]^3+1)^2 39 | global f -= sum([4x[i]*x[j]+10x[i]^3*x[j]+2x[j]+4x[i]*x[j]^2+10x[i]^3*x[j]^2+2x[j]^2 for j in jset]) 40 | global f += sum([x[j]*x[k]+2x[j]^2*x[k]+x[j]^2*x[k]^2 for j in jset for k in jset]) 41 | end 42 | 43 | function Broydenbanded(n::Int) 44 | supp = [UInt16[]] 45 | coe = Float64[n] 46 | for i = 1:n 47 | jset = max(1,i-5):min(n,i+1) 48 | jset = setdiff(jset,i) 49 | push!(supp, [i], [i;i], [i;i;i], [i;i;i;i], [i;i;i;i;i;i]) 50 | push!(coe, 4, 4, 10, 20, 25) 51 | for j in jset 52 | push!(supp, [j], [j;j], sort([i;j]), sort([i;j;j]), sort([i;i;i;j]), sort([i;i;i;j;j])) 53 | push!(coe, -2, -2, -4, -4, -10, -10) 54 | for k in jset 55 | push!(supp, sort([j;k]), sort([j;j;k]), sort([j;k;k]), sort([j;j;k;k])) 56 | push!(coe, 1, 1, 1, 1) 57 | end 58 | end 59 | end 60 | return resort(supp, coe) 61 | end 62 | 63 | function genRosenbrock(n::Int) 64 | supp = [UInt16[]] 65 | coe = Float64[n] 66 | for i = 2:n 67 | push!(supp, [i-1;i-1;i-1;i-1], [i-1;i-1;i], [i], [i;i]) 68 | push!(coe, 100, -200, -2, 101) 69 | end 70 | return resort(supp, coe) 71 | end 72 | 73 | function chainedWood(n::Int) 74 | supp = [UInt16[]] 75 | coe = Float64[21*n-41] 76 | for i = 1:2:n-3 77 | push!(supp, [i], [i;i], [i;i;i;i], [i;i;i+1], [i+1], [i+1;i+1], [i+1;i+3], [i+2], [i+2;i+2], [i+2;i+2;i+2;i+2], [i+2;i+2;i+3], [i+3], [i+3;i+3]) 78 | push!(coe, -2, 1, 100, -200, -40, 110.1, 19.8, -2, 1, 90, -180, -40, 100.1) 79 | end 80 | return resort(supp, coe) 81 | end 82 | 83 | function Broydentridiagonal(n::Int) 84 | supp = [UInt16[]] 85 | coe = Float64[n] 86 | push!(supp, [1;1], [1;1;1;1], [2;2], [1;1;1], [1;2], [1], [1;1;2], [2]) 87 | push!(coe, 5, 4, 4, -12, -12, 6, 8, -4) 88 | for i = 2:n-1 89 | push!(supp, [i;i], [i;i;i;i], [i-1;i-1], [i+1;i+1], [i;i;i], [i-1;i], [i;i+1], [i], [i-1;i;i], [i;i;i+1], [i-1;i+1], [i-1], [i+1]) 90 | push!(coe, 5, 4, 1, 4, -12, -6, -12, 6, 4, 8, 4, -2, -4) 91 | end 92 | push!(supp, [n;n], [n;n;n;n], [n-1;n-1], [n;n;n], [n-1;n], [n], [n-1;n;n], [n-1]) 93 | push!(coe, 5, 4, 1, -12, -6, 6, 4, -2) 94 | return resort(supp, coe) 95 | end 96 | 97 | # Chained singular polynomial 98 | n = 20 99 | @ncpolyvar x[1:n] 100 | for i = 1:2:n-3 101 | global f += (x[i]^2+10x[i]*x[i+1]+10x[i+1]*x[i]+100x[i+1]^2)+5*(x[i+2]^2-x[i+2]*x[i+3]-x[i+3]*x[i+2]+x[i+3]^2)+(x[i+1]^4-4x[i+1]*x[i+2]*x[i+1]^2+4x[i+2]^2*x[i+1]^2-4x[i+1]^2*x[i+2]*x[i+1]+16x[i+1]*x[i+2]^2*x[i+1]-16x[i+2]^3*x[i+1]+4x[i+1]^2*x[i+2]^2-16x[i+1]*x[i+2]^3+16x[i+2]^4)+10*(x[i]^4-20x[i]*x[i+3]*x[i]^2+100x[i+3]^2*x[i]^2-20x[i]^2*x[i+3]*x[i]+400x[i]*x[i+3]^2*x[i]-2000x[i+3]^3*x[i]+100x[i]^2*x[i+3]^2-2000x[i]*x[i+3]^3+10000x[i+3]^4) 102 | end 103 | 104 | # Chained singular polynomial 105 | function Chainedsingular(n::Int) 106 | supp = Vector{UInt16}[] 107 | coe = Float64[] 108 | for i = 1:2:n-3 109 | push!(supp, [i;i], [i;i+1], [i+1;i+1], [i+2;i+2], [i+3;i+3], [i+2;i+3], [i+1;i+1;i+1;i+1], [i+1;i+1;i+2;i+2], [i+2;i+2;i+2;i+2], [i+1;i+1;i+1;i+2], [i+1;i+1;i+2;i+2], [i+1;i+2;i+2;i+2], [i;i;i;i], [i;i;i+3;i+3], [i+3;i+3;i+3;i+3], [i;i;i;i+3], [i;i;i+3;i+3], [i;i+3;i+3;i+3]) 110 | push!(coe, 1, 20 ,100, 5, 5, -10, 1, 16, 16, -8, 8, -32, 10, 4000, 100000, -400, 2000, -40000) 111 | end 112 | return resort(supp, coe) 113 | end 114 | 115 | push!(coe, 1, 20 ,100, 5, 5, -10, 1, 16, 16, -8, 8, -32, 10, 40, 10, -40, 20, -40) 116 | 117 | # randomly generated examples 118 | l = 2 119 | b = 15 120 | n = (b-5)*l+5 121 | supp = Vector{Vector{Vector{UInt16}}}(undef, l+1) 122 | coe = Vector{Vector{Float64}}(undef, l+1) 123 | supp[1] = Vector{Vector{UInt16}}[] 124 | for i = 1:l, j = 1:b 125 | push!(supp[1], ceil.(UInt16, ((b-5)*i-(b-5)).+rand(4).*b)) 126 | end 127 | coe[1] = 2*rand(b*l).-1 128 | for i = 1:l 129 | supp[i+1] = [[[]]; [[j;j] for j=(b-5)*i-(b-6):(b-5)*i+5]] 130 | coe[i+1] = [1; -ones(b)] 131 | end 132 | -------------------------------------------------------------------------------- /example/polynomials.jl: -------------------------------------------------------------------------------- 1 | # Rosenbrock-Lerner polynomial 2 | N = 60 3 | b = 15 4 | @polyvar x[1:N] 5 | f_R = 10*sum((x[3:N-1].+x[2:N-2].-x[1:N-3].^2).^2)+sum((ntuple(i->1,N-3).-x[1:N-3].-x[4:N]).^2) 6 | f_Q = sum([x[i]*i/j*x[j] for i=1:b,j=1:b]) 7 | f = f_R + f_Q 8 | 9 | # Broyden tridiagonal polynomial 10 | l = 5 11 | p = 20 12 | n = l*p 13 | @polyvar x[1:n] 14 | f = ((3-2*x[1])*x[1]-2*x[2]+1)^2 15 | for i = 2:n-1 16 | f += ((3-2*x[i])*x[i]-x[i-1]-2*x[i+1]+1)^2 17 | end 18 | f += ((3-2*x[n])*x[n]-x[n-1]+1)^2 19 | pop = [f] 20 | for i = 1:l 21 | push!(pop,1-sum(x[(i-1)*p+1:i*p].^2)) 22 | end 23 | 24 | # Chained singular polynomial 25 | l = 2 26 | p = 15 27 | n = l*p 28 | @polyvar x[1:n] 29 | f = (x[1]+10*x[2])^2+5*(x[3]-x[4])^2+(x[2]-2*x[3])^4+10*(x[1]-10*x[4])^4 30 | for i = 3:2:n-3 31 | f += (x[i]+10*x[i+1])^2+5*(x[i+2]-x[i+3])^2+(x[i+1]-2*x[i+2])^4+10*(x[i]-10*x[i+3])^4 32 | end 33 | pop = [f] 34 | for i = 1:l 35 | push!(pop,1-sum(x[(i-1)*p+1:i*p].^2)) 36 | end 37 | 38 | # Broyden banded polynomial 39 | n = 400 40 | @polyvar x[1:n] 41 | f = x[1] 42 | for i = 1:n 43 | jset = max(1,i-5):min(n,i+1) 44 | jset = setdiff(jset,i) 45 | f0 = sum([(1+x[jset[j]])*x[jset[j]] for j=1:length(jset)]) 46 | f += (x[i]*(2+5*x[i]^2)+1-f0)^2 47 | end 48 | f -= x[1] 49 | 50 | # chained Wood polynomial 51 | l = 50 52 | p = 20 53 | n = l*p 54 | @polyvar x[1:n] 55 | f = x[1] + 1 56 | for i = 1:2:n-3 57 | f += 100*(x[i+1]-x[i]^2)^2+(1-x[i])^2+90*(x[i+3]-x[i+2]^2)^2+(1-x[i+2])^2+10*(x[i+1]+x[i+3]-2)^2+0.1*(x[i+1]-x[i+3])^2 58 | end 59 | f -= x[1] 60 | pop = [f] 61 | for i = 1:l 62 | push!(pop,1-sum(x[(i-1)*p+1:i*p].^2)) 63 | end 64 | 65 | # generalized Rosenbrock polynomial 66 | l = 50 67 | p = 20 68 | n = l*p 69 | @polyvar x[1:n] 70 | f = x[1] + 1 71 | for i = 2:n 72 | f += 100*(x[i]-x[i-1]^2)^2+(1-x[i])^2 73 | end 74 | f -= x[1] 75 | pop = [f] 76 | for i = 1:l 77 | push!(pop,1-sum(x[(i-1)*p+1:i*p].^2)) 78 | end 79 | -------------------------------------------------------------------------------- /example/psatz_linear.jl: -------------------------------------------------------------------------------- 1 | using JuMP 2 | using MosekTools 3 | using DynamicPolynomials 4 | using MultivariatePolynomials 5 | using TSSOS 6 | 7 | function basis(x) 8 | basis = Monomial{true}[1] 9 | push!(basis, x...) 10 | for i = 1:length(x), j = i:length(x) 11 | push!(basis, x[i]*x[j]) 12 | end 13 | return basis 14 | end 15 | 16 | n = 4 17 | @polyvar x[1:n] 18 | @polyvar y[1:3] 19 | b = basis(x[1:n]) 20 | f = rand(length(b))'*b*y[1] + rand(length(b))'*b*y[2] + rand(length(b))'*b*y[3] + rand(length(b))'*b 21 | g1 = rand(length(b))'*b*y[1] + rand(length(b))'*b*y[2] + rand(length(b))'*b*y[3] + rand(length(b))'*b 22 | g2 = 1 - sum(x.^2) 23 | g3 = rand(length(b))'*b - y[1] 24 | g4 = y[1] + rand(length(b))'*b 25 | g5 = rand(length(b))'*b - y[2] 26 | g6 = y[2] + rand(length(b))'*b 27 | g7 = rand(length(b))'*b - y[3] 28 | g8 = y[3] + rand(length(b))'*b 29 | 30 | opt,sol,data = tssos_first([f;g1;g2;g3;g4;g5;g6;g7;g8], [x;y], 3, TS=false, QUIET=true) 31 | 32 | d = 3 33 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 34 | set_optimizer_attribute(model, MOI.Silent(), true) 35 | s0 = add_SOS!(model, x, d) 36 | s1 = add_SOS!(model, x, d-1) 37 | s2 = add_SOS!(model, x, d-1) 38 | s3 = add_SOS!(model, x, d-1) 39 | s4 = add_SOS!(model, x, d-1) 40 | s5 = add_SOS!(model, x, d-1) 41 | s6 = add_SOS!(model, x, d-1) 42 | s7 = add_SOS!(model, x, d-1) 43 | s8 = add_SOS!(model, x, d-1) 44 | @variable(model, lower) 45 | @objective(model, Max, lower) 46 | @constraint(model, coefficients(f - lower - s0 - s1*g1 - s2*g2 - s3*g3 - s4*g4 - s5*g5 - s6*g6 - s7*g7 - s8*g8) .== 0) 47 | optimize!(model) 48 | status = termination_status(model) 49 | if status != MOI.OPTIMAL 50 | println("termination status: $status") 51 | status = primal_status(model) 52 | println("solution status: $status") 53 | end 54 | objv = objective_value(model) 55 | @show objv 56 | -------------------------------------------------------------------------------- /example/qpm.jl: -------------------------------------------------------------------------------- 1 | using DynamicPolynomials 2 | using TSSOS 3 | using JuMP 4 | using MosekTools 5 | using MultivariatePolynomials 6 | 7 | @polyvar x[1:2] 8 | @polyvar y 9 | f = ((x[1] - x[2])^2 - 2)^2 10 | s = 10 11 | t = 10 12 | 13 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 14 | ω = add_poly!(model, y, 2s)[1] 15 | q1 = add_poly!(model, x[1], 2t)[1] 16 | q2 = add_poly!(model, x[1], 2t)[1] 17 | add_psatz!(model, ω, [y], [1-y^2], [], s, TS=false) 18 | add_psatz!(model, q1, [x[1]], [1-x[1]^2], [], t, TS=false) 19 | add_psatz!(model, q2, [x[1]], [1-x[1]^2], [], t, TS=false) 20 | p = ω*(((x[1] - y)^2 - 2)^2 - 1) 21 | H1 = sum(MultivariatePolynomials.coefficient(p, y^i, [y])*(2/(i+1)) for i = 0:2:2s+4) + 1 + q1 - q2 22 | H2 = subs(H1, x[1]=>x[2]) 23 | @variable(model, τ) 24 | add_psatz!(model, [τ 0.5*(H1 + H2); 0.5*(H1 + H2) f], x, 1 .- x.^2, [], t, TS=false) 25 | @objective(model, Min, 0.5*τ + coefficients(sum(MultivariatePolynomials.coefficient(q2 - 0.1*q1, x[1]^i, [x[1]])*(2/(i+1)) for i = 0:2:2t))[1]) 26 | optimize!(model) 27 | optimum = objective_value(model) 28 | @show optimum 29 | 30 | 31 | @polyvar z[1:2] 32 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 33 | ω = add_poly!(model, y, 2s)[1] 34 | q1 = add_poly!(model, x[1], 2t)[1] 35 | q2 = add_poly!(model, x[1], 2t)[1] 36 | add_psatz!(model, ω, [y], [1-y^2], [], s, TS=false) 37 | add_psatz!(model, q1, [x[1]], [1-x[1]^2], [], t, TS=false) 38 | add_psatz!(model, q2, [x[1]], [1-x[1]^2], [], t, TS=false) 39 | p = ω*(((x[1] - y)^2 - 2)^2 - 1) 40 | H = -sum(MultivariatePolynomials.coefficient(p, y^i, [y])*(2/(i+1)) for i = 0:2:2s+4) + 1 + q1 - q2 41 | H1 = subs(H, x[1]=>z[1]+z[2]) 42 | H2 = subs(H, x[1]=>z[1]-z[2]) 43 | @variable(model, τ) 44 | # add_psatz!(model, [τ 0.5*(H1 + H2); 0.5*(H1 + H2) f(x[1]=>z[1]+z[2], x[2]=>z[1]-z[2])], z, [1-(z[1]+z[2])^2, 1-(z[1]-z[2])^2], [], t, TS="block") 45 | add_psatz!(model, [τ 0.5*(H1 + H2); 0.5*(H1 + H2) f(x[1]=>z[1]+z[2], x[2]=>z[1]-z[2])], z, [2-(z[1]+z[2])^2-(z[1]-z[2])^2, (1-(z[1]+z[2])^2)*(1-(z[1]-z[2])^2)], [], t, TS="block") 46 | @objective(model, Min, 0.5*τ + coefficients(sum(MultivariatePolynomials.coefficient(q2 - 0.1*q1, x[1]^i, [x[1]])*(2/(i+1)) for i = 0:2:2t))[1]) 47 | optimize!(model) 48 | optimum = objective_value(model) 49 | @show optimum 50 | 51 | 52 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 53 | sos1 = add_SOS!(model, y, s) 54 | sos2 = add_SOS!(model, y, s-1) 55 | sos3 = add_SOS!(model, x[1], t) 56 | sos4 = add_SOS!(model, x[1], t-1) 57 | sos5 = add_SOS!(model, x[1], t) 58 | sos6 = add_SOS!(model, x[1], t-1) 59 | p = (sos1 + sos2*(1 - y^2))*(((x[1] - y)^2 - 2)^2 + ((x[2] - y)^2 - 2)^2 - 2) 60 | q1 = sos3 + sos4*(1 - x[1]^2) 61 | q2 = subs(q1, x[1]=>x[2]) 62 | q3 = sos5 + sos6*(1 - x[1]^2) 63 | q4 = subs(q3, x[1]=>x[2]) 64 | msos1 = add_SOSMatrix!(model, x, 2, t)[1] 65 | msos2 = add_SOSMatrix!(model, x, 2, t-1)[1] 66 | msos3 = add_SOSMatrix!(model, x, 2, t-1)[1] 67 | @variable(model, τ) 68 | @constraint(model, coefficients(-0.5*sum(MultivariatePolynomials.coefficient(p, y^i, [y])*(2/(i+1)) for i = 0:2:2s+4) + 1 + 0.5*(q1 + q2 - q3 - q4) - msos1[1,2] - msos2[1,2]*(1-x[1]^2) - msos3[1,2]*(1-x[2]^2)) .== 0) 69 | @constraint(model, coefficients(τ - msos1[1,1] - msos2[1,1]*(1-x[1]^2) - msos3[1,1]*(1-x[2]^2)) .== 0) 70 | @constraint(model, coefficients(f - msos1[2,2] - msos2[2,2]*(1-x[1]^2) - msos3[2,2]*(1-x[2]^2)) .== 0) 71 | @objective(model, Min, 0.5*τ + coefficients(sum(MultivariatePolynomials.coefficient(q3 - 0.1*q1, x[1]^i, [x[1]])*(2/(i+1)) for i = 0:2:2t))[1]) 72 | optimize!(model) 73 | optimum = objective_value(model) 74 | @show optimum 75 | 76 | using SumOfSquares 77 | s = 10 78 | t = 10 79 | model = SOSModel(optimizer_with_attributes(Mosek.Optimizer)) 80 | X1 = monomials(x[1], 0:t) 81 | X2 = monomials(x[1], 0:t-1) 82 | Y1 = monomials(x[1], 0:s) 83 | Y2 = monomials(x[1], 0:s-1) 84 | τ1 = @variable(model, [1:2], SOSPoly(X1)) 85 | τ2 = @variable(model, [1:2], SOSPoly(X2)) 86 | τ3 = @variable(model, [1:1], SOSPoly(Y1)) 87 | τ4 = @variable(model, [1:1], SOSPoly(Y2)) 88 | q1 = τ1[1] + τ2[1]*(1-x[1]^2) 89 | q2 = τ1[2] + τ2[2]*(1-x[1]^2) 90 | ω = τ3[1] + τ4[1]*(1-y^2) 91 | p = ω*(((x[1] - y)^2 - 2)^2 - 1) 92 | H1 = sum(MultivariatePolynomials.coefficient(p, y^i, [y])*(2/(i+1)) for i = 0:2:2s+4) + 1 + q1 - q2 93 | H2 = subs(H1, x[1]=>x[2]) 94 | X3 = monomials(x, 0:t) 95 | r1 = @variable(model, [1:3], Poly(X3)) 96 | @constraint(model, [r1[1] r1[2]; r1[2] r1[3]] in PSDCone()) 97 | X4 = monomials(x, 0:t-1) 98 | r2 = @variable(model, [1:3], Poly(X4)) 99 | r3 = @variable(model, [1:3], Poly(X4)) 100 | @constraint(model, [r2[1] r2[2]; r2[2] r2[3]] in PSDCone()) 101 | @constraint(model, [r3[1] r3[2]; r3[2] r3[3]] in PSDCone()) 102 | @variable(model, τ) 103 | @constraint(model, 0.5*(H1 + H2) - r1[2] - r2[2]*(1-x[1]^2) - r3[2]*(1-x[2]^2) == 0) 104 | @constraint(model, τ - r1[1] - r2[1]*(1-x[1]^2) - r3[1]*(1-x[2]^2) == 0) 105 | @constraint(model, f - r1[3] - r2[3]*(1-x[1]^2) - r3[3]*(1-x[2]^2) == 0) 106 | @objective(model, Min, 0.5*τ + coefficients(sum(MultivariatePolynomials.coefficient(q2 - 0.1*q1, x[1]^i, [x[1]])*(2/(i+1)) for i = 0:2:2t))[1]) 107 | optimize!(model) 108 | optimum = objective_value(model) 109 | @show optimum 110 | termination_status(model) 111 | -------------------------------------------------------------------------------- /example/rhsos.jl: -------------------------------------------------------------------------------- 1 | using TSSOS 2 | using DynamicPolynomials 3 | using MultivariatePolynomials 4 | using Random 5 | 6 | function cbasis(z) 7 | basis = Poly{Int}[1] 8 | for i = 1:length(z) 9 | push!(basis, z[i]) 10 | end 11 | for i = 1:length(z), j = i:length(z) 12 | push!(basis, z[i]*z[j]) 13 | end 14 | return basis 15 | end 16 | 17 | # minimizing a random complex quadratic polynomial over the unit sphere 18 | Random.seed!(1) 19 | n = 50 20 | @complex_polyvar z[1:n] 21 | Q = rand(n+1, n+1) 22 | Q = (Q+Q')/2 23 | f = [1; z]'*Q*[1; z] 24 | h = z'*z - 1 25 | @time begin 26 | opt,sol,data = complex_tssos_first([f; h], z, 1, numeq=1, QUIET=true, TS=false) 27 | end 28 | 29 | @polyvar x[1:2n] 30 | rf = f(z=>x[1:n]+im*x[n+1:2n]) 31 | rpop = [real.(coefficients(rf))'*monomials(rf), 1-sum(x.^2)] 32 | @time begin 33 | opt,sol,data = tssos_first(rpop, x, 1, numeq=1, GroebnerBasis=false, QUIET=true, TS="block") 34 | end 35 | 36 | opt,sol = local_solution(2n, 1, data.supp, data.coe, numeq=1, startpoint=rand(2n), QUIET=true) 37 | println(opt) 38 | 39 | # minimizing a random complex quartic polynomial over the unit sphere 40 | Random.seed!(1) 41 | n = 20 42 | @complex_polyvar z[1:n] 43 | basis = cbasis(z) 44 | P = rand(length(basis), length(basis)) 45 | f = basis'*((P+P')/2)*basis 46 | h = z'*z - 1 47 | 48 | @time begin 49 | opt,sol,data = complex_tssos_first([f; h], z, 2, numeq=1, QUIET=true, TS=false) 50 | end 51 | 52 | @polyvar x[1:2n] 53 | rf = f(z=>x[1:n]+im*x[n+1:2n]) 54 | rpop = [real.(coefficients(rf))'*monomials(rf), 1-sum(x.^2)] 55 | @time begin 56 | opt,sol,data = tssos_first(rpop, x, 2, numeq=1, GroebnerBasis=false, QUIET=true, TS="block") 57 | end 58 | 59 | opt,sol = local_solution(2n, 1, data.supp, data.coe, numeq=1, startpoint=rand(2n), QUIET=true) 60 | println(opt) 61 | -------------------------------------------------------------------------------- /example/runopf.jl: -------------------------------------------------------------------------------- 1 | using TSSOS 2 | # Need to add the package PowerModels. 3 | include("D:/Programs/TSSOS/example/modelopf.jl") 4 | 5 | # Need to download the problem data from PGLiB (https://github.com/power-grid-lib/pglib-opf). 6 | cd("D:/Programs/PolyOPF/pglib") 7 | silence() 8 | 9 | case = "pglib_opf_case30_ieee" 10 | AC = 8208.5 11 | opfdata = parse_file(case * ".m") 12 | 13 | # first order relaxation 14 | model = pop_opf_real(opfdata, normal=true, AngleCons=true, LineLimit="relax") 15 | n = model.n 16 | m = model.m 17 | numeq = model.numeq 18 | supp = model.supp 19 | coe = model.coe 20 | mc = maximum(abs.(coe[1])) 21 | coe[1] = coe[1]./mc 22 | 23 | t = @elapsed begin 24 | opt,_,popd = cs_tssos_first(supp, coe, n, 1, numeq=numeq, CS=false, TS="MF", MomentOne=false) 25 | end 26 | opt *= mc 27 | mb = maximum(maximum.([maximum.(popd.blocksize[i]) for i = 1:popd.cql])) # maximal block size 28 | gap = (AC-opt)*100/AC # optimality gap 29 | println("n = $n, m = $m") 30 | println("opt = $opt, time = $t, mb = $mb, gap = $gap%") 31 | 32 | # minimum order relaxation 33 | model = pop_opf_real(opfdata, normal=true, AngleCons=true, LineLimit=true) 34 | n = model.n 35 | m = model.m 36 | numeq = model.numeq 37 | supp = model.supp 38 | coe = model.coe 39 | mc = maximum(abs.(coe[1])) 40 | coe[1] = coe[1]./mc 41 | 42 | t = @elapsed begin 43 | opt,_,popd = cs_tssos_first(supp, coe, n, "min", numeq=numeq, CS="MF", TS="block", MomentOne=false) 44 | end 45 | opt *= mc 46 | maxc = maximum(popd.cliquesize) # maximal clique size 47 | mb = maximum(maximum.([maximum.(popd.blocksize[i]) for i = 1:popd.cql])) # maximal block size 48 | gap = 100*(AC-opt)/AC # optimality gap 49 | println("n = $n, m = $m") 50 | println("mc = $maxc, opt = $opt, time = $t, mb = $mb, gap = $gap%") 51 | -------------------------------------------------------------------------------- /example/sosprogram.jl: -------------------------------------------------------------------------------- 1 | using JuMP 2 | using MosekTools 3 | using DynamicPolynomials 4 | using MultivariatePolynomials 5 | using TSSOS 6 | 7 | n = 3 8 | @polyvar x[1:n] 9 | f = [(x[1]^2+x[2]^2-1/4)*x[1], (x[2]^2+x[3]^2-1/4)*x[2], (x[2]^2+x[3]^2-1/4)*x[3]] 10 | g = [1-x[1]^2, 1-x[2]^2, 1-x[3]^2] 11 | 12 | d = 3 13 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 14 | set_optimizer_attribute(model, MOI.Silent(), true) 15 | v, vc, vb = add_poly!(model, x, 2d-2) 16 | w, wc, wb = add_poly!(model, x, 2d) 17 | Lv = v - sum(f .* differentiate(v, x)) 18 | info1 = add_psatz!(model, Lv, x, g, [], d, TS=false, SO=1, constrs="con1") 19 | info2 = add_psatz!(model, w, x, g, [], d, TS=false, SO=1) 20 | info3 = add_psatz!(model, w-v-1, x, g, [], d, TS=false, SO=1) 21 | moment = get_moment(wb, -ones(n), ones(n)) 22 | @objective(model, Min, sum(moment.*wc)) 23 | optimize!(model) 24 | objv = objective_value(model) 25 | @show objv 26 | # objv = 3.437648 27 | 28 | # retrieve Gram matrices 29 | GramMat = Vector{Vector{Vector{Union{Float64,Matrix{Float64}}}}}(undef, info1.cql) 30 | for i = 1:info1.cql 31 | GramMat[i] = Vector{Vector{Union{Float64,Matrix{Float64}}}}(undef, 1+length(info1.I[i])) 32 | for j = 1:1+length(info1.I[i]) 33 | GramMat[i][j] = [value.(info1.GramMat[i][j][l]) for l = 1:length(info1.GramMat[i][j])] 34 | end 35 | end 36 | 37 | # retrieve moment matrices 38 | MomMat = get_moment_matrix(-dual(constraint_by_name(model, "con1")), info1) 39 | -------------------------------------------------------------------------------- /example/strengthen.jl: -------------------------------------------------------------------------------- 1 | using TSSOS 2 | using DynamicPolynomials 3 | using Random 4 | using LinearAlgebra 5 | 6 | # Minimizing a random complex quadratic polynomial with unit-norm variables 7 | Random.seed!(1) 8 | n = 10 9 | @complex_polyvar z[1:n] 10 | P = rand(n+1, n+1) 11 | Q = rand(n+1, n+1) 12 | pop = [[1; z]'*((P+P')/2+im*(Q-Q')/2)*[1; z]] 13 | @time begin 14 | opt,sol,data = complex_tssos_first(pop, z, 1, nb=n, QUIET=true, TS=false, normality=0) 15 | end 16 | @time begin 17 | opt,sol,data = complex_tssos_first(pop, z, 2, nb=n, QUIET=true, TS=false, normality=0) 18 | end 19 | @time begin 20 | opt,sol,data = complex_tssos_first(pop, z, 1, nb=n, QUIET=true, TS=false, normality=1) 21 | end 22 | # println(sum(eigvals(convert.(ComplexF64, data.moment[1][1])) .> 1e-4)) 23 | 24 | @polyvar x[1:2n] 25 | rf = pop[1](z=>x[1:n]+im*x[n+1:2n]) 26 | rpop = [real.(coefficients(rf))'*monomials(rf)] 27 | for i = 1:n 28 | push!(rpop, 1 - x[i]^2 - x[i+n]^2) 29 | end 30 | @time begin 31 | opt,sol,data = tssos_first(rpop, x, 2, numeq=n, GroebnerBasis=true, QUIET=true, TS=false) 32 | end 33 | 34 | function basis(x) 35 | basis = Poly{Int}[1] 36 | push!(basis, x...) 37 | for i = 1:length(x), j = i:length(x) 38 | push!(basis, x[i]*x[j]) 39 | end 40 | return basis 41 | end 42 | 43 | # Minimizing a random complex quartic polynomial on a unit sphere 44 | Random.seed!(1) 45 | n = 10 46 | @complex_polyvar z[1:n] 47 | cb = basis(z) 48 | lcb = length(cb) 49 | P = rand(lcb, lcb) 50 | Q = rand(lcb, lcb) 51 | pop = [cb'*((P+P')/2+im*(Q-Q')/2)*cb] 52 | push!(pop, 1 - z'*z) 53 | @time begin 54 | opt,sol,data = complex_tssos_first(pop, z, 2, numeq=1, QUIET=true, TS=false, normality=0) 55 | end 56 | @time begin 57 | opt,sol,data = complex_tssos_first(pop, z, 3, numeq=1, QUIET=true, TS=false, normality=0) 58 | end 59 | @time begin 60 | opt,sol,data = complex_tssos_first(pop, z, 2, numeq=1, QUIET=true, TS=false, normality=1) 61 | end 62 | 63 | @polyvar x[1:2n] 64 | rf = pop[1](z=>x[1:n]+im*x[n+1:2n]) 65 | rpop = [real.(coefficients(rf))'*monomials(rf), 1 - sum(x.^2)] 66 | @time begin 67 | opt,sol,data = tssos_first(rpop, x, 2, numeq=1, GroebnerBasis=false, QUIET=true, TS=false) 68 | end 69 | println(sum(eigvals(data.moment[1]) .> 1e-4)) 70 | 71 | # Minimizing a random complex quartic polynomial with CS on multi-spheres 72 | Random.seed!(1) 73 | l = 5 74 | n = 4l + 2 75 | @complex_polyvar z[1:n] 76 | f = 0 77 | for i = 1:l 78 | cb = basis(z[4i-3:4i+2]) 79 | lcb = length(cb) 80 | P = rand(lcb, lcb) 81 | Q = rand(lcb, lcb) 82 | f += cb'*((P+P')/2+im*(Q-Q')/2)*cb 83 | end 84 | pop = [f] 85 | for i = 1:l 86 | push!(pop, 1 - sum(z[4i-3:4i+2]'*z[4i-3:4i+2])) 87 | end 88 | @time begin 89 | opt,sol,data = complex_tssos_first(pop, z, 2, numeq=l, QUIET=true, TS=false, normality=0) 90 | end 91 | @time begin 92 | opt,sol,data = complex_tssos_first(pop, z, 3, numeq=l, QUIET=true, TS=false, normality=0) 93 | end 94 | @time begin 95 | opt,sol,data = complex_tssos_first(pop, z, 2, numeq=l, QUIET=true, TS=false, normality=1) 96 | end 97 | 98 | @polyvar x[1:2n] 99 | rf = pop[1](z=>x[1:n]+im*x[n+1:2n]) 100 | rpop = [real.(coefficients(rf))'*monomials(rf)] 101 | for i = 1:l 102 | push!(rpop, 1 - sum(x[4i-3:4i+2].^2) - sum(x[n+4i-3:n+4i+2].^2)) 103 | end 104 | @time begin 105 | opt,sol,data = cs_tssos_first(rpop, x, 2, numeq=l, QUIET=true, TS=false, solution=false) 106 | end 107 | # println(maximum([sum(eigvals(data.moment[i][1]) .> 1e-4) for i = 1:l])) 108 | 109 | # The AC-OPF problem 110 | include("D:/Programs/TSSOS/example/modelopf.jl") 111 | cd("D:/Programs/PolyOPF/pglib") 112 | silence() 113 | 114 | case = "pglib_opf_case30_as" 115 | AC = 803.13 116 | opfdata = parse_file(case * ".m") 117 | model = pop_opf_com_vol(opfdata, normal=true, AngleCons=true, LineLimit=true) 118 | n = model.n 119 | m = model.m 120 | numeq = model.numeq 121 | supp = model.supp 122 | coe = model.coe 123 | mc = maximum(abs.(coe[1])) 124 | coe[1] = coe[1]./mc 125 | 126 | t = @elapsed begin 127 | opt,_,popd = complex_cs_tssos_first(supp, coe, n, "min", numeq=numeq, QUIET=true, normality=0, CS="MF", TS="block") 128 | end 129 | opt *= mc 130 | mb = maximum(maximum.([maximum.(popd.blocksize[i]) for i = 1:popd.cql])) # maximal block size 131 | gap = (AC-opt)*100/AC # optimality gap 132 | println("n = $n, m = $m") 133 | println("opt = $opt, time = $t, mb = $mb, gap = $gap%") 134 | 135 | t = @elapsed begin 136 | opt,_,popd = complex_cs_tssos_first(supp, coe, n, "min", numeq=numeq, QUIET=true, normality=1, CS="MF", TS="block") 137 | end 138 | opt *= mc 139 | mb = maximum(maximum.([maximum.(popd.blocksize[i]) for i = 1:popd.cql])) # maximal block size 140 | gap = (AC-opt)*100/AC # optimality gap 141 | println("n = $n, m = $m") 142 | println("opt = $opt, time = $t, mb = $mb, gap = $gap%") 143 | -------------------------------------------------------------------------------- /example/symmetry.jl: -------------------------------------------------------------------------------- 1 | using PermutationGroups 2 | using DynamicPolynomials 3 | using TSSOS 4 | using JuMP 5 | using MosekTools 6 | 7 | @polyvar x[1:4] 8 | f = sum(x) + sum(x.^2) 9 | G = PermGroup([perm"(1,2,3,4)"]) # define the symmetry group 10 | opt,data = tssos_symmetry([f], x, 1, G) 11 | # optimum = -1 12 | 13 | @polyvar x[1:3] 14 | f = sum(x) + sum(x.^4) 15 | G = PermGroup([perm"(1,2,3)", perm"(1,2)"]) 16 | opt,data = tssos_symmetry([f], x, 2, G) 17 | # optimum = -1.4174111 18 | 19 | @polyvar x[1:3] 20 | f = sum(x) + sum(x.^4) - 4*x[1]*x[2]*x[3] 21 | G = PermGroup([perm"(1,2,3)", perm"(1,2)"]) 22 | opt,data = tssos_symmetry([f], x, 2, G) 23 | # optimum = -2.1129138 24 | 25 | @polyvar x[1:3] 26 | f = sum(x) + sum(x.^4) 27 | pop = [f, 1 - sum(x.^2)] 28 | G = PermGroup([perm"(1,2,3)", perm"(1,2)"]) 29 | opt,data = tssos_symmetry(pop, x, 2, G) 30 | # optimum = -1.3987174 31 | 32 | @polyvar x[1:3] 33 | f = sum(x) + sum(x.^4) 34 | pop = [f, 1 - sum(x.^2)] 35 | opt,sol,data = tssos_first(pop, x, 2, TS="block") 36 | G = PermGroup([perm"(1,2,3)", perm"(1,2)"]) 37 | opt,data = tssos_symmetry_first(pop, x, 2, G, SymmetricConstraint=true) 38 | # optimum = -1.3987174 39 | 40 | d = 2 41 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 42 | set_optimizer_attribute(model, MOI.Silent(), true) 43 | lambda = @variable(model) 44 | info = add_psatz_symmetry!(model, f - lambda, x, [1 - sum(x.^2)], [], d, G, SymmetricConstraint=true, TS="block", SO=1) 45 | @objective(model, Max, lambda) 46 | optimize!(model) 47 | objv = objective_value(model) 48 | @show objv 49 | # optimum = -1.3987174 50 | 51 | @polyvar x[1:3] 52 | f = sum(x) + sum(x.^4) 53 | pop = [f, 1 - sum(x.^2)] 54 | G = PermGroup([perm"(1,2,3)", perm"(1,2)"]) 55 | opt,data = tssos_symmetry(pop, x, 2, G, numeq=1) 56 | # optimum = -1.3987174 57 | 58 | d = 2 59 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 60 | set_optimizer_attribute(model, MOI.Silent(), true) 61 | lambda = @variable(model) 62 | info = add_psatz_symmetry!(model, f - lambda, x, [], [1 - sum(x.^2)], d, G, TS="block", SO=1) 63 | @objective(model, Max, lambda) 64 | optimize!(model) 65 | objv = objective_value(model) 66 | @show objv 67 | # optimum = -1.3987174 68 | 69 | @polyvar x[1:3] 70 | f = sum(x.^2) + sum(x.^4) 71 | pop = [f, 1 - sum(x.^2)] 72 | G = PermGroup([perm"(1,2,3)", perm"(1,2)"]) 73 | opt,data = tssos_symmetry_first(pop, x, 2, G, numeq=0, TS="block") 74 | # optimum = 0 75 | opt,data = tssos_symmetry_higher!(data, TS="block") 76 | # optimum = 0 77 | -------------------------------------------------------------------------------- /src/Chebyshev_basis.jl: -------------------------------------------------------------------------------- 1 | using MultivariateBases 2 | 3 | mutable struct poly_basis 4 | pop # polynomial optimization problem 5 | numeq # number of equality constraints 6 | group 7 | action 8 | basis # polynomial bases 9 | ebasis # polynomial bases for equality constraints 10 | ksupp # extended support at the k-th step 11 | blocksize # size of blocks 12 | blocks # block structrue 13 | eblocks # block structrue for equality constraints 14 | GramMat # Gram matrices 15 | multiplier # multipliers for equality constraints 16 | SDP_status 17 | end 18 | 19 | """ 20 | info = add_psatz_cheby!(model, nonneg, vars, ineq_cons, eq_cons, order; TS="block", SO=1, QUIET=false) 21 | 22 | Add a Putinar's style SOS representation of the polynomial `nonneg` in the Chebyshev basis to the JuMP `model`. 23 | 24 | # Input arguments 25 | - `model`: a JuMP optimization model 26 | - `nonneg`: a nonnegative polynomial constrained to be a Putinar's style SOS on a semialgebraic set 27 | - `vars`: the set of POP variables 28 | - `ineq_cons`: inequality constraints 29 | - `eq_cons`: equality constraints 30 | - `order`: relaxation order 31 | - `TS`: type of term sparsity (`"block"`, `"MD"`, `"MF"`, `false`) 32 | - `SO`: sparse order 33 | - `QUIET`: run in the quiet mode (`true`, `false`) 34 | 35 | # Output arguments 36 | - `info`: auxiliary data 37 | """ 38 | function add_psatz_cheby!(model, nonneg::DP.Polynomial{V, M, T}, vars, ineq_cons, eq_cons, order; TS="block", SO=1, merge=false, md=3, QUIET=false) where {V, M, T<:Union{Number,AffExpr}} 39 | m = length(ineq_cons) 40 | l = length(eq_cons) 41 | basis = Vector{ChebyshevBasisFirstKind{DP.Polynomial{V, M, Float64}}}(undef, m+l+1) 42 | basis[1] = basis_covering_monomials(ChebyshevBasis, MP.monomials(vars, 0:order)) 43 | basis[2:m+1] = [basis_covering_monomials(ChebyshevBasis, MP.monomials(vars, 0:order-ceil(Int, maxdegree(g)/2))) for g in ineq_cons] 44 | basis[m+2:m+1+l] = [basis_covering_monomials(ChebyshevBasis, MP.monomials(vars, 0:2*order-maxdegree(h))) for h in eq_cons] 45 | tsupp = basis_covering_monomials(ChebyshevBasis, unique([MP.monomials(nonneg); MP.monomials.(ineq_cons)...; MP.monomials.(eq_cons)...])) 46 | tsupp = [item for item in tsupp] 47 | sort!(tsupp) 48 | blocks,cl,blocksize,eblocks = get_blocks(m, l, tsupp, ineq_cons, eq_cons, basis, TS=TS, SO=SO, merge=merge, md=md, QUIET=QUIET) 49 | poly = nonneg 50 | pos = Vector{Vector{Union{VariableRef,Symmetric{VariableRef}}}}(undef, 1+m) 51 | pos[1] = Vector{Union{VariableRef,Symmetric{VariableRef}}}(undef, cl[1]) 52 | for i = 1:cl[1] 53 | bs = blocksize[1][i] 54 | if bs == 1 55 | pos[1][i] = @variable(model, lower_bound=0) 56 | poly -= basis[1][blocks[1][i][1]]^2 * pos[1][i] 57 | else 58 | pos[1][i] = @variable(model, [1:bs, 1:bs], PSD) 59 | poly -= sum(basis[1][blocks[1][i][j]] * pos[1][i][j,k] * basis[1][blocks[1][i][k]] for j = 1:bs, k = 1:bs) 60 | end 61 | end 62 | for k = 1:m 63 | pos[k+1] = Vector{Union{VariableRef,Symmetric{VariableRef}}}(undef, cl[k+1]) 64 | for i = 1:cl[k+1] 65 | bs = blocksize[k+1][i] 66 | if bs == 1 67 | pos[k+1][i] = @variable(model, lower_bound=0) 68 | poly -= basis[k+1][blocks[k+1][i][1]]^2 * pos[k+1][i] * ineq_cons[k] 69 | else 70 | pos[k+1][i] = @variable(model, [1:bs, 1:bs], PSD) 71 | poly -= sum(basis[k+1][blocks[k+1][i][j]] * pos[k+1][i][j,r] * basis[k+1][blocks[k+1][i][r]] for j = 1:bs, r = 1:bs) * ineq_cons[k] 72 | end 73 | end 74 | end 75 | mul = nothing 76 | if l > 0 77 | mul = Vector{Vector{VariableRef}}(undef, l) 78 | for k = 1:l 79 | mul[k] = @variable(model, [1:length(eblocks[k])]) 80 | poly -= sum(basis[k+m+1][eblocks[k][j]] * mul[k][j] for j = 1:length(eblocks[k])) * eq_cons[k] 81 | end 82 | end 83 | coefs = MP.coefficients(poly, basis_covering_monomials(ChebyshevBasis, MP.monomials(poly))) 84 | remove_nearly_zero_terms!(model, coefs) 85 | drop_zeros!.(coefs) 86 | @constraint(model, coefs .== 0) 87 | info = poly_basis(nothing, nothing, nothing, nothing, basis, nothing, nothing, blocksize, blocks, eblocks, pos, mul, nothing) 88 | return info 89 | end 90 | 91 | function get_blocks(m::Int, l::Int, tsupp, ineq_cons, eq_cons, basis::Vector{ChebyshevBasisFirstKind{DP.Polynomial{V, M, Float64}}}; TS="block", SO=1, merge=false, md=3, QUIET=false) where {V, M} 92 | blocks = Vector{Vector{Vector{Int}}}(undef, m+1) 93 | eblocks = Vector{Vector{Int}}(undef, l) 94 | blocksize = Vector{Vector{Int}}(undef, m+1) 95 | cl = Vector{Int}(undef, m+1) 96 | if TS == false 97 | for k = 1:m+1 98 | blocks[k],blocksize[k],cl[k] = [Vector(1:length(basis[k]))],[length(basis[k])],1 99 | end 100 | for k = 1:l 101 | eblocks[k] = Vector(1:length(basis[k+m+1])) 102 | end 103 | else 104 | for i = 1:SO 105 | if i > 1 106 | oblocksize = deepcopy(blocksize) 107 | oeblocks = deepcopy(eblocks) 108 | end 109 | for k = 1:m+1 110 | if k == 1 111 | G = get_graph(tsupp, basis[1]) 112 | else 113 | G = get_graph(tsupp, basis[k], g=ineq_cons[k-1]) 114 | end 115 | if TS == "block" 116 | blocks[k] = connected_components(G) 117 | blocksize[k] = length.(blocks[k]) 118 | cl[k] = length(blocksize[k]) 119 | else 120 | blocks[k],cl[k],blocksize[k] = chordal_cliques!(G, method=TS) 121 | if merge == true 122 | blocks[k],cl[k],blocksize[k] = clique_merge!(blocks[k], d=md, QUIET=true) 123 | end 124 | end 125 | end 126 | for k = 1:l 127 | eblocks[k] = get_eblock(tsupp, eq_cons[k], basis[k+m+1]) 128 | end 129 | if i > 1 && blocksize == oblocksize && eblocks == oeblocks 130 | println("No higher TS step of the TSSOS hierarchy!") 131 | break 132 | end 133 | if i < SO 134 | tsupp = DP.Polynomial{V, M, Float64}[] 135 | for t = 1:length(blocks[1]), j = 1:blocksize[1][t], r = j:blocksize[1][t] 136 | append!(tsupp, basis_covering_monomials(ChebyshevBasis, MP.monomials(basis[1][blocks[1][t][j]] * basis[1][blocks[1][t][r]]))) 137 | end 138 | unique!(tsupp) 139 | sort!(tsupp) 140 | end 141 | end 142 | end 143 | return blocks,cl,blocksize,eblocks 144 | end 145 | 146 | function get_graph(tsupp, basis::ChebyshevBasisFirstKind{DP.Polynomial{V, M, Float64}}; g=1) where {V, M} 147 | lb = length(basis) 148 | G = SimpleGraph(lb) 149 | ltsupp = length(tsupp) 150 | for i = 1:lb, j = i+1:lb 151 | flag = 0 152 | for item in basis_covering_monomials(ChebyshevBasis, MP.monomials(basis[i] * basis[j] * g)) 153 | if lbfind(tsupp, ltsupp, item) !== nothing 154 | flag = 1 155 | break 156 | end 157 | end 158 | if flag == 1 159 | add_edge!(G, i, j) 160 | end 161 | end 162 | return G 163 | end 164 | 165 | function get_eblock(tsupp, h, basis::ChebyshevBasisFirstKind{DP.Polynomial{V, M, Float64}}) where {V, M} 166 | ltsupp = length(tsupp) 167 | eblock = Int[] 168 | for (i, ba) in enumerate(basis) 169 | flag = 0 170 | for item in basis_covering_monomials(ChebyshevBasis, MP.monomials(ba * h)) 171 | if lbfind(tsupp, ltsupp, item) !== nothing 172 | flag = 1 173 | break 174 | end 175 | end 176 | if flag == 1 177 | push!(eblock, i) 178 | end 179 | end 180 | return eblock 181 | end 182 | 183 | function Base.isless(P::T, Q::T) where {T<:AbstractPolynomial} 184 | return MP.monomials(P) < MP.monomials(Q) 185 | end 186 | 187 | function remove_nearly_zero_terms!(model, ps; tol=1e-8) 188 | vars = all_variables(model) 189 | for (i, p) in enumerate(ps) 190 | np = AffExpr(0) 191 | for x in vars 192 | c = JuMP.coefficient(p, x) 193 | add_to_expression!(p, -c, x) 194 | if abs(c) > tol 195 | add_to_expression!(np, c, x) 196 | end 197 | end 198 | ps[i] = np + p 199 | end 200 | return ps 201 | end 202 | -------------------------------------------------------------------------------- /src/TSSOS.jl: -------------------------------------------------------------------------------- 1 | module TSSOS 2 | 3 | using MosekTools 4 | using JuMP 5 | using Graphs 6 | using DynamicPolynomials 7 | using MultivariatePolynomials 8 | using Ipopt 9 | using LinearAlgebra 10 | using MetaGraphs 11 | using SemialgebraicSets 12 | using Groebner 13 | using COSMO 14 | using Dualization 15 | using Printf 16 | using AbstractAlgebra 17 | using Random 18 | using SymbolicWedderburn 19 | using AbstractPermutations 20 | import DynamicPolynomials as DP 21 | import MultivariatePolynomials as MP 22 | import CliqueTrees 23 | 24 | export tssos_first, tssos_higher!, cs_tssos_first, cs_tssos_higher!, complex_tssos_first, complex_tssos_higher!, complex_cs_tssos_first, 25 | complex_cs_tssos_higher!, LinearPMI_first, LinearPMI_higher!, sparseobj 26 | export cosmo_para, mosek_para 27 | export local_solution, refine_sol, extract_solutions, extract_solutions_robust, extract_solutions_pmo, extract_solutions_pmo_robust, extract_weight_matrix 28 | export add_SOS!, add_SOSMatrix!, add_poly!, add_psatz!, add_psatz_cheby!, add_poly_cheby! 29 | export tssos_symmetry, get_signsymmetry, tssos_symmetry_first, tssos_symmetry_higher!, add_psatz_symmetry! 30 | export homogenize, solve_hpop, SumOfRatios, SparseSumOfRatios, get_dynamic_sparsity 31 | export show_blocks, complex_to_real, get_mmoment, get_basis, get_moment, get_moment_matrix, get_cmoment 32 | export run_H1, run_H1CS, run_H2, run_H2CS, construct_CDK, construct_marginal_CDK, construct_CDK_cs, construct_marginal_CDK_cs 33 | 34 | mutable struct cosmo_para 35 | eps_abs::Float64 36 | eps_rel::Float64 37 | max_iter::Int64 38 | time_limit::Float64 39 | end 40 | 41 | cosmo_para() = cosmo_para(1e-5, 1e-5, 1e4, 0) 42 | 43 | mutable struct mosek_para 44 | tol_pfeas::Float64 45 | tol_dfeas::Float64 46 | tol_relgap::Float64 47 | time_limit::Int64 48 | num_threads::Int64 49 | end 50 | 51 | mosek_para() = mosek_para(1e-8, 1e-8, 1e-8, -1, 0) 52 | 53 | const Mono = DP.Monomial{DP.Commutative{DP.CreationOrder}, Graded{LexOrder}} 54 | const Poly{T} = DP.Polynomial{DP.Commutative{DP.CreationOrder}, Graded{LexOrder}, T} 55 | const PolyLike = Union{Mono,Term,Poly} 56 | export Mono,Poly 57 | 58 | include("chordal_extension.jl") 59 | include("clique_merge.jl") 60 | include("blockpop.jl") 61 | include("nblockmix.jl") 62 | include("complex.jl") 63 | include("utils.jl") 64 | include("local_solution.jl") 65 | include("extract_solutions.jl") 66 | include("add_psatz.jl") 67 | include("homogenize.jl") 68 | include("matrixsos.jl") 69 | include("sum_of_ratios.jl") 70 | include("CDK.jl") 71 | include("dynamic_system.jl") 72 | include("Chebyshev_basis.jl") 73 | include("symmetry.jl") 74 | 75 | end 76 | -------------------------------------------------------------------------------- /src/chordal_extension.jl: -------------------------------------------------------------------------------- 1 | function chordal_cliques!(G; method="MF", minimize=false) 2 | # choose algorithm 3 | alg = method == "MF" && minimize ? CliqueTrees.MinimalChordal(CliqueTrees.MF()) : 4 | method == "MD" && minimize ? CliqueTrees.MinimalChordal(CliqueTrees.MMD()) : 5 | method == "MF" && !minimize ? CliqueTrees.MF() : 6 | method == "MD" && !minimize ? CliqueTrees.MMD() : 7 | error() 8 | 9 | # compute maximal cliques 10 | label, tree = CliqueTrees.cliquetree(G; alg) 11 | 12 | # triangulate graph 13 | F = CliqueTrees.FilledGraph(tree) 14 | 15 | for edge in edges(F) 16 | add_edge!(G, label[src(edge)], label[dst(edge)]) 17 | end 18 | 19 | # return maximal cliques 20 | maximal_cliques = Vector{Vector{UInt16}}(undef, length(tree)) 21 | 22 | for (i, clique) in enumerate(tree) 23 | maximal_cliques[i] = sort!(label[clique]) 24 | end 25 | 26 | cliquesize = length.(maximal_cliques) 27 | cql = length(cliquesize) 28 | return maximal_cliques, cql, cliquesize 29 | end 30 | 31 | function add_clique!(G, nodes) 32 | for i in 1:length(nodes)-1, j in i+1:length(nodes) 33 | add_edge!(G, nodes[i], nodes[j]) 34 | end 35 | end 36 | 37 | function max_cliques(G) 38 | cliques = convert(Vector{Vector{UInt16}}, maximal_cliques(G)) 39 | sort!.(cliques) 40 | cliquesize = length.(cliques) 41 | cql = length(cliquesize) 42 | return cliques,cql,cliquesize 43 | end 44 | -------------------------------------------------------------------------------- /src/clique_merge.jl: -------------------------------------------------------------------------------- 1 | function fweight(a, b; d=3) 2 | return length(a)^d + length(b)^d - length(union(a, b))^d 3 | end 4 | 5 | function mergeclique!(cliques, cliqueG, i, j; d=3) 6 | cliques[i] = unique(sort([cliques[i]; cliques[j]])) 7 | cliques[j] = cliques[end] 8 | cliques = cliques[1:end-1] 9 | for neighbor in neighbors(cliqueG, j) 10 | if neighbor != i 11 | add_edge!(cliqueG, i, neighbor) 12 | end 13 | end 14 | rem_vertex!(cliqueG, j) 15 | for neighbor in neighbors(cliqueG, i) 16 | weight = fweight(cliques[i], cliques[neighbor], d=d) 17 | set_prop!(cliqueG, i, neighbor, :weight, weight) 18 | end 19 | return cliques,cliqueG 20 | end 21 | 22 | function clique_merge!(cliques; d=3, QUIET=true) 23 | cql = length(cliques) 24 | cliqueG = MetaGraph(cql) 25 | for i = 1:cql, j = i+1:cql 26 | if intersect(cliques[i], cliques[j]) != [] 27 | add_edge!(cliqueG, i, j) 28 | weight = fweight(cliques[i], cliques[j], d=d) 29 | set_prop!(cliqueG, i, j, :weight, weight) 30 | end 31 | end 32 | merge = true 33 | while merge == true 34 | mweight = 0 35 | medge = 0 36 | for edge in edges(cliqueG) 37 | weight = get_prop(cliqueG, edge, :weight) 38 | if weight > mweight 39 | mweight = weight 40 | medge = edge 41 | end 42 | end 43 | if mweight > 0 44 | cliques,cliqueG = mergeclique!(cliques, cliqueG, src(medge), dst(medge), d=d) 45 | else 46 | break 47 | end 48 | end 49 | cliquesize = length.(cliques) 50 | cql = length(cliquesize) 51 | if QUIET == false 52 | uc = sort(unique(cliquesize), rev=true) 53 | sizes = [sum(cliquesize.== i) for i in uc] 54 | println("-------------------------------------------") 55 | println("The size of blocks after merging:\n$uc\n$sizes") 56 | println("-------------------------------------------") 57 | end 58 | return cliques,cql,cliquesize 59 | end 60 | -------------------------------------------------------------------------------- /src/dynamic_system.jl: -------------------------------------------------------------------------------- 1 | function get_dynamic_sparsity(f, g, x, d; TS=["block","block"], SO=[1,1], merge=false, md=3, QUIET=false) 2 | n = length(x) 3 | m = length(g) 4 | fsupp = npolys_info(f, x)[1] 5 | flt = size.(fsupp, 2) 6 | df = maxdegree.(f) 7 | gsupp = npolys_info(g, x)[1] 8 | glt = size.(gsupp, 2) 9 | dg = maxdegree.(g) 10 | basis = Vector{Array{UInt8,2}}(undef, m+1) 11 | basis[1] = get_basis(n, d) 12 | for i = 1:m 13 | basis[i+1] = get_basis(n, d-Int(ceil(dg[i]/2))) 14 | end 15 | dv = 2d + 1 - maximum(df) 16 | if TS[1] != false 17 | tsupp = hcat(gsupp...) 18 | tsupp = [tsupp get_Lsupp(n, tsupp, fsupp, flt)] 19 | tsupp = sortslices(tsupp, dims=2) 20 | tsupp = unique(tsupp, dims=2) 21 | vsupp = tsupp[:, [sum(item) <= dv for item in eachcol(tsupp)]] 22 | tsupp1 = [vsupp get_Lsupp(n, vsupp, fsupp, flt)] 23 | tsupp1 = sortslices(tsupp1, dims=2) 24 | tsupp1 = unique(tsupp1, dims=2) 25 | else 26 | vsupp = get_basis(n, dv) 27 | tsupp1 = tsupp = nothing 28 | end 29 | vblocks,vsupp,tsupp,status = get_vblocks(m, dv, tsupp1, tsupp, vsupp, fsupp, flt, gsupp, glt, basis, TS=TS[1], SO=SO[1], merge=merge, md=md, QUIET=QUIET) 30 | wsupp = wblocks = nothing 31 | if status == 1 32 | if TS[1] != false 33 | tsupp = sortslices(tsupp, dims=2) 34 | tsupp = unique(tsupp, dims=2) 35 | end 36 | wblocks,status = get_blocks(m, tsupp, gsupp, glt, basis, TS=TS[2], SO=SO[2], merge=merge, md=md, QUIET=QUIET) 37 | if status == 1 38 | wsupp = get_tsupp(n, m, gsupp, glt, basis, wblocks) 39 | end 40 | end 41 | return vsupp,vblocks,wsupp,wblocks,status 42 | end 43 | 44 | function get_Lsupp(n, vsupp, fsupp, flt) 45 | Lsupp = zeros(UInt8, n, 1) 46 | for i = 1:length(flt) 47 | temp = zeros(UInt8, n) 48 | temp[i] = 1 49 | for j = 1:size(vsupp, 2) 50 | if vsupp[i, j] > 0 51 | for k = 1:flt[i] 52 | Lsupp = [Lsupp vsupp[:,j]-temp+fsupp[i][:,k]] 53 | end 54 | end 55 | end 56 | end 57 | Lsupp = sortslices(Lsupp, dims=2) 58 | Lsupp = unique(Lsupp, dims=2) 59 | return Lsupp 60 | end 61 | 62 | function get_tsupp(n, m, gsupp, glt, basis, blocks) 63 | blocksize = [length.(blocks[i]) for i = 1:m+1] 64 | cl = length.(blocksize) 65 | supp1 = zeros(UInt8, n, Int(sum(Int.(blocksize[1]).^2+blocksize[1])/2)) 66 | k = 1 67 | for i = 1:cl[1], j = 1:blocksize[1][i], r = j:blocksize[1][i] 68 | supp1[:,k] = basis[1][:,blocks[1][i][j]] + basis[1][:,blocks[1][i][r]] 69 | k += 1 70 | end 71 | supp2 = zeros(UInt8, n, sum(glt[i]*Int(sum(Int.(blocksize[i+1]).^2+blocksize[i+1])/2) for i=1:m)) 72 | l = 1 73 | for k = 1:m, i = 1:cl[k+1], j = 1:blocksize[k+1][i], r = j:blocksize[k+1][i], s = 1:glt[k] 74 | supp2[:,l] = basis[k+1][:,blocks[k+1][i][j]] + basis[k+1][:,blocks[k+1][i][r]] + gsupp[k][:,s] 75 | l += 1 76 | end 77 | tsupp = [supp1 supp2] 78 | tsupp = sortslices(tsupp,dims=2) 79 | tsupp = unique(tsupp,dims=2) 80 | return tsupp 81 | end 82 | 83 | function get_blocks(m::Int, tsupp, gsupp::Vector{Array{UInt8, 2}}, glt, basis::Vector{Array{UInt8, 2}}; TS="block", SO=1, merge=false, md=3, QUIET=false) 84 | blocks = Vector{Vector{Vector{Int}}}(undef, m+1) 85 | if TS == false 86 | blocks = [[Vector(1:size(basis[k],2))] for k = 1:m+1] 87 | status = 1 88 | else 89 | status = 1 90 | for i = 1:SO 91 | if i > 1 92 | oblocks = deepcopy(blocks) 93 | end 94 | for k = 1:m+1 95 | if k == 1 96 | G = get_graph(tsupp, basis[1]) 97 | else 98 | G = get_graph(tsupp, gsupp[k-1], basis[k]) 99 | end 100 | if TS == "block" 101 | blocks[k] = connected_components(G) 102 | else 103 | blocks[k] = chordal_cliques!(G, method=TS)[1] 104 | if merge == true 105 | blocks[k] = clique_merge!(blocks[k], QUIET=true, d=md)[1] 106 | end 107 | end 108 | end 109 | if i == 1 || oblocks != blocks 110 | if i < SO 111 | blocksize = length.(blocks[1]) 112 | tsupp = zeros(UInt8, size(gsupp[1], 1), numele(blocksize)) 113 | s = 1 114 | for t = 1:length(blocks[1]), j = 1:blocksize[t], r = j:blocksize[t] 115 | tsupp[:,s] = basis[1][:,blocks[1][t][j]] + basis[1][:,blocks[1][t][r]] 116 | s += 1 117 | end 118 | tsupp = sortslices(tsupp, dims=2) 119 | tsupp = unique(tsupp, dims=2) 120 | end 121 | else 122 | println("No higher TS step of the TSSOS hierarchy!") 123 | status = 0 124 | break 125 | end 126 | end 127 | end 128 | return blocks,status 129 | end 130 | 131 | function get_vblocks(m::Int, dv, tsupp1, tsupp, vsupp::Array{UInt8, 2}, fsupp, flt, gsupp::Vector{Array{UInt8, 2}}, glt, basis::Vector{Array{UInt8, 2}}; TS="block", SO=1, merge=false, md=3, QUIET=false) 132 | blocks = Vector{Vector{Vector{Int}}}(undef, m+1) 133 | if TS == false 134 | blocks = [[Vector(1:size(basis[k],2))] for k = 1:m+1] 135 | status = 1 136 | else 137 | status = 1 138 | qvsupp = vsupp 139 | for i = 1:SO 140 | if i > 1 141 | oblocks = deepcopy(blocks) 142 | end 143 | for k = 1:m+1 144 | if k == 1 145 | G = get_graph(tsupp1, basis[1]) 146 | else 147 | G = get_graph(tsupp1, gsupp[k-1], basis[k]) 148 | end 149 | if TS == "block" 150 | blocks[k] = connected_components(G) 151 | else 152 | blocks[k] = chordal_cliques!(G, method=TS)[1] 153 | if merge == true 154 | blocks[k] = clique_merge!(blocks[k], QUIET=true, d=md)[1] 155 | end 156 | end 157 | end 158 | if i == 1 || oblocks != blocks || size(vsupp, 2) != size(qvsupp, 2) 159 | vsupp = qvsupp 160 | if i < SO 161 | blocksize = length.(blocks[1]) 162 | tsupp = zeros(UInt8, size(gsupp[1], 1), Int(sum(Int.(blocksize).^2+blocksize)/2)) 163 | s = 1 164 | for t = 1:length(blocks[1]), j = 1:blocksize[t], r = j:blocksize[t] 165 | tsupp[:,s] = basis[1][:,blocks[1][t][j]] + basis[1][:,blocks[1][t][r]] 166 | s += 1 167 | end 168 | tsupp = sortslices(tsupp, dims=2) 169 | tsupp = unique(tsupp, dims=2) 170 | qvsupp = tsupp[:, [sum(item) <= dv for item in eachcol(tsupp)]] 171 | tsupp1 = [tsupp get_Lsupp(size(gsupp[1], 1), qvsupp, fsupp, flt)] 172 | tsupp1 = sortslices(tsupp1, dims=2) 173 | tsupp1 = unique(tsupp1, dims=2) 174 | end 175 | else 176 | println("No higher TS step of the TSSOS hierarchy!") 177 | status = 0 178 | break 179 | end 180 | end 181 | end 182 | return blocks,vsupp,tsupp,status 183 | end 184 | -------------------------------------------------------------------------------- /src/homogenize.jl: -------------------------------------------------------------------------------- 1 | # Homogenize the polynomial f with the homogenization variable z 2 | function homogenize(f, z) 3 | d = maxdegree(f) 4 | ts = [term*z^(d-maxdegree(term)) for term in MP.terms(f)] 5 | return sum(ts) 6 | end 7 | 8 | function solve_hpop(cost, vars, ineq_cons, eq_cons, order; QUIET=false, CS="MF", type=2, ε=0, TS="block", SO=1, nnhomovar=false, GroebnerBasis=false, Mommat=false) 9 | println("*********************************** TSSOS ***********************************") 10 | println("TSSOS is launching...") 11 | if CS != false 12 | fsupp = poly_info(cost, vars)[1] 13 | if ineq_cons != [] 14 | gsupp = npolys_info(ineq_cons, vars)[1] 15 | else 16 | gsupp = Matrix{UInt8}[] 17 | end 18 | if eq_cons != [] 19 | hsupp = npolys_info(eq_cons, vars)[1] 20 | else 21 | hsupp = Matrix{UInt8}[] 22 | end 23 | cliques,cql,_ = clique_decomp(length(vars), length(ineq_cons), length(eq_cons), fsupp, gsupp, hsupp, alg="NC", QUIET=QUIET) 24 | end 25 | @polyvar z 26 | if ineq_cons != [] 27 | ineq_cons = homogenize.(ineq_cons, z) 28 | dg = maxdegree.(ineq_cons) 29 | else 30 | dg = [0] 31 | end 32 | if eq_cons != [] 33 | eq_cons = homogenize.(eq_cons, z) 34 | end 35 | cost = homogenize(cost, z) 36 | d = maxdegree(cost) 37 | if nnhomovar == true || isodd(d) || any(isodd.(dg)) 38 | push!(ineq_cons, z) 39 | end 40 | if CS != false && cql > 1 41 | if type == 1 42 | @polyvar y[1:cql] 43 | for i = 1:cql 44 | push!(eq_cons, sum(vars[cliques[i]].^2) + z^2 + y[i]^2 - 1) 45 | end 46 | else 47 | freq = zeros(length(vars)) 48 | for clique in cliques 49 | freq[clique] .+= 1 50 | end 51 | if type == 2 52 | @polyvar y[1:cql-1] 53 | push!(ineq_cons, 2 - sum(vars[cliques[1]].^2) - z^2 - y[1]^2) 54 | push!(eq_cons, sum(1 ./ freq[cliques[1]] .* vars[cliques[1]].^2) + 1/cql*z^2 - y[1]^2) 55 | for i = 2:cql-1 56 | push!(ineq_cons, 3 - sum(vars[cliques[i]].^2) - z^2 - y[i-1]^2 - y[i]^2) 57 | push!(eq_cons, sum(1 ./ freq[cliques[i]] .* vars[cliques[i]].^2) + 1/cql*z^2 + y[i-1]^2 - y[i]^2) 58 | end 59 | push!(ineq_cons, 2 - sum(vars[cliques[end]].^2) - z^2 - y[end]^2) 60 | push!(eq_cons, sum(1 ./ freq[cliques[end]] .* vars[cliques[end]].^2) + 1/cql*z^2 + y[end]^2 - 1) 61 | else 62 | @polyvar y[1:cql] 63 | for i = 1:cql 64 | push!(eq_cons, sum(1 ./ freq[cliques[i]] .* vars[cliques[i]].^2) + 1/cql*z^2 + y[i]^2 - 1) 65 | end 66 | push!(eq_cons, sum(y.^2) - cql + 1) 67 | end 68 | # append!(ineq_cons, 1 .- vars.^2) 69 | # push!(ineq_cons, 1 - z^2) 70 | # append!(ineq_cons, 1 .- y.^2) 71 | end 72 | nvars = [vars; z; y] 73 | else 74 | push!(eq_cons, sum(vars.^2) + z^2 - 1) 75 | nvars = [vars; z] 76 | end 77 | if ε > 0 78 | d0 = iseven(d) ? d : d+1 79 | cost += ε*sum(nvars.^d0) 80 | end 81 | time = @elapsed begin 82 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 83 | set_optimizer_attribute(model, MOI.Silent(), QUIET) 84 | @variable(model, λ) 85 | info = add_psatz!(model, cost-λ*z^d, nvars, ineq_cons, eq_cons, order, QUIET=QUIET, CS=CS, TS=TS, SO=SO, GroebnerBasis=GroebnerBasis, constrs="con") 86 | @objective(model, Max, λ) 87 | optimize!(model) 88 | status = termination_status(model) 89 | if status != MOI.OPTIMAL 90 | println("termination status: $status") 91 | status = primal_status(model) 92 | println("solution status: $status") 93 | end 94 | optimum = objective_value(model) 95 | @show optimum 96 | end 97 | println("POP solving time: $time seconds.") 98 | moment = -dual(constraint_by_name(model, "con")) 99 | MomMat = get_moment_matrix(moment, info) 100 | return optimum,MomMat,info 101 | end -------------------------------------------------------------------------------- /src/local_solution.jl: -------------------------------------------------------------------------------- 1 | """ 2 | obj,sol,status = local_solution(n, m, supp::Vector{Union{Vector{Vector{UInt16}}, Array{UInt8, 2}}}, coe; nb=0, numeq=0, 3 | startpoint=[], QUIET=false) 4 | 5 | Compute a local solution by a local solver. 6 | # Input arguments 7 | - `n`: number of POP variables 8 | - `m`: number of POP constraints 9 | - `supp`: supports of the POP 10 | - `coe`: coefficients of the POP 11 | - `nb`: number of binary variables 12 | - `numeq`: number of equality constraints 13 | - `startpoint`: provide a start point 14 | - `QUIET`: run in the quiet mode or not (`true`, `false`) 15 | 16 | # Output arguments 17 | - `obj`: local optimum 18 | - `sol`: local solution 19 | - `status`: solver termination status 20 | """ 21 | function local_solution(n, m, supp::Vector{Vector{Vector{UInt16}}}, coe; nb=0, numeq=0, startpoint=[], QUIET=false) 22 | model = Model(optimizer_with_attributes(Ipopt.Optimizer)) 23 | set_optimizer_attribute(model, MOI.Silent(), QUIET) 24 | if QUIET == true 25 | set_optimizer_attribute(model, "print_level", 0) 26 | end 27 | if isempty(startpoint) 28 | @variable(model, x[1:n], start = 0) 29 | else 30 | @variable(model, x[i=1:n], start = startpoint[i]) 31 | end 32 | @NLobjective(model, Min, sum(coe[1][j]*prod(x[supp[1][j][k]] for k=1:length(supp[1][j])) for j=1:length(supp[1]))) 33 | for i = 1:nb 34 | @NLconstraint(model, x[i]^2-1==0) 35 | end 36 | for i in 1:m-numeq 37 | @NLconstraint(model, sum(coe[i+1][j]*prod(x[supp[i+1][j][k]] for k=1:length(supp[i+1][j])) for j=1:length(supp[i+1]))>=0) 38 | end 39 | for i in m-numeq+1:m 40 | @NLconstraint(model, sum(coe[i+1][j]*prod(x[supp[i+1][j][k]] for k=1:length(supp[i+1][j])) for j=1:length(supp[i+1]))==0) 41 | end 42 | optimize!(model) 43 | status = termination_status(model) 44 | objv = objective_value(model) 45 | if QUIET == false 46 | println("optimum = $objv") 47 | end 48 | return objv,value.(x),status 49 | end 50 | 51 | function local_solution(n, m, supp::Vector{Array{UInt8, 2}}, coe; nb=0, numeq=0, startpoint=[], QUIET=false) 52 | model = Model(optimizer_with_attributes(Ipopt.Optimizer)) 53 | set_optimizer_attribute(model, MOI.Silent(), QUIET) 54 | if QUIET == true 55 | set_optimizer_attribute(model, "print_level", 0) 56 | end 57 | if isempty(startpoint) 58 | @variable(model, x[1:n], start = 0) 59 | else 60 | @variable(model, x[i=1:n], start = startpoint[i]) 61 | end 62 | @NLobjective(model, Min, sum(coe[1][j]*prod(x[k]^supp[1][k,j] for k=1:n) for j=1:size(supp[1], 2))) 63 | for i = 1:nb 64 | @NLconstraint(model, x[i]^2-1==0) 65 | end 66 | for i in 1:m-numeq 67 | @NLconstraint(model, sum(coe[i+1][j]*prod(x[k]^supp[i+1][k,j] for k=1:n) for j=1:size(supp[i+1], 2))>=0) 68 | end 69 | for i in m-numeq+1:m 70 | @NLconstraint(model, sum(coe[i+1][j]*prod(x[k]^supp[i+1][k,j] for k=1:n) for j=1:size(supp[i+1], 2))==0) 71 | end 72 | optimize!(model) 73 | status = termination_status(model) 74 | objv = objective_value(model) 75 | if QUIET == false 76 | println("optimum = $objv") 77 | end 78 | return objv,value.(x),status 79 | end 80 | 81 | """ 82 | ref_sol,flag = refine_sol(opt, sol, data, QUIET=false, tol=1e-2) 83 | 84 | Refine the obtained solution by a local solver. 85 | Return the refined solution, and `flag=0` if global optimality is certified, `flag=1` otherwise. 86 | """ 87 | function refine_sol(opt, sol, data::Union{cpop_data,mcpop_data}; QUIET=false, gtol=1e-2) 88 | n = data.n 89 | nb = data.nb 90 | numeq = data.numeq 91 | if typeof(data) == cpop_data && !isempty(data.gb) 92 | m = length(data.pop) - 1 93 | supp = Vector{Array{UInt8,2}}(undef, m+1) 94 | coe = Vector{Vector{Float64}}(undef, m+1) 95 | supp[2:m+1-numeq] = data.supp[2:end] 96 | coe[2:m+1-numeq] = data.coe[2:end] 97 | for k in [1; [k for k=m+2-numeq:m+1]] 98 | mons = MP.monomials(data.pop[k]) 99 | coe[k] = MP.coefficients(data.pop[k]) 100 | supp[k] = zeros(UInt8, n, length(mons)) 101 | for i in eachindex(mons), j = 1:n 102 | @inbounds supp[k][j,i] = MP.degree(mons[i], data.x[j]) 103 | end 104 | end 105 | else 106 | m = data.m 107 | supp = data.supp 108 | coe = data.coe 109 | end 110 | for i = 1:n 111 | if abs(sol[i]) < 1e-10 112 | sol[i] = 1e-10 113 | end 114 | end 115 | ub,rsol,status = local_solution(n, m, supp, coe, nb=nb, numeq=numeq, startpoint=sol, QUIET=QUIET) 116 | if status == MOI.LOCALLY_SOLVED 117 | gap = abs(opt-ub)/max(1, abs(ub)) 118 | if gap < gtol 119 | println("------------------------------------------------") 120 | @printf "Global optimality certified with relative optimality gap %.6f%%!\n" 100*gap 121 | println("Successfully extracted one globally optimal solution.") 122 | println("------------------------------------------------") 123 | return rsol,0 124 | else 125 | @printf "Found a locally optimal solution by Ipopt, giving an upper bound: %.8f.\nThe relative optimality gap is: %.6f%%.\n" ub 100*gap 126 | return rsol,1 127 | end 128 | else 129 | println("The local solver failed refining the solution!") 130 | return sol,1 131 | end 132 | end 133 | -------------------------------------------------------------------------------- /src/sum_of_ratios.jl: -------------------------------------------------------------------------------- 1 | """ 2 | optimum = SumOfRatios(p, q, g, h, x, d; QUIET=false, SignSymmetry=true, GroebnerBasis=false) 3 | 4 | Minimizing the sum of ratios p1/q1 + ... + pN/qN on the set defined by g >= 0 and h == 0. 5 | 6 | # Input arguments 7 | - `p`: vector of denominators 8 | - `q`: vector of numerator 9 | - `g`: inequality constraints 10 | - `h`: equality constraints 11 | - `x`: vector of variables 12 | - `d`: relaxation order 13 | 14 | # Output arguments 15 | - `SignSymmetry`: exploit sign symmetries or not (`true`, `false`) 16 | - `GroebnerBasis`: exploit the quotient ring structure or not (`true`, `false`) 17 | """ 18 | function SumOfRatios(p, q, g, h, x, d; QUIET=false, dualize=false, SignSymmetry=true, mosek_setting=mosek_para(), GroebnerBasis=false) 19 | println("*********************************** TSSOS ***********************************") 20 | println("TSSOS is launching...") 21 | N = length(p) 22 | if SignSymmetry == true 23 | polys = [p; q] 24 | if !isempty(g) 25 | polys = [polys; g] 26 | end 27 | if !isempty(h) 28 | polys = [polys; h] 29 | end 30 | ss = get_signsymmetry(polys, x) 31 | TS = "block" 32 | else 33 | ss = TS = false 34 | end 35 | dq = maxdegree.(q) 36 | time = @elapsed begin 37 | if dualize == false 38 | model = Model(optimizer_with_attributes(Mosek.Optimizer, "MSK_DPAR_INTPNT_CO_TOL_PFEAS" => mosek_setting.tol_pfeas, "MSK_DPAR_INTPNT_CO_TOL_DFEAS" => mosek_setting.tol_dfeas, 39 | "MSK_DPAR_INTPNT_CO_TOL_REL_GAP" => mosek_setting.tol_relgap, "MSK_DPAR_OPTIMIZER_MAX_TIME" => mosek_setting.time_limit, "MSK_IPAR_NUM_THREADS" => mosek_setting.num_threads)) 40 | else 41 | model = Model(dual_optimizer(Mosek.Optimizer)) 42 | end 43 | set_optimizer_attribute(model, MOI.Silent(), QUIET) 44 | hh = Vector{Polynomial{true, AffExpr}}(undef, N-1) 45 | for i = 1:N-1 46 | hh[i] = add_poly!(model, x, 2d-max(dq[i], dq[N]), signsymmetry=ss)[1] 47 | add_psatz!(model, p[i]-hh[i]*q[i], x, g, h, d, QUIET=QUIET, CS=false, TS=TS, GroebnerBasis=GroebnerBasis) 48 | end 49 | c = @variable(model) 50 | add_psatz!(model, p[N]+(sum(hh)-c)*q[N], x, g, h, d, QUIET=QUIET, CS=false, TS=TS, GroebnerBasis=GroebnerBasis) 51 | @objective(model, Max, c) 52 | optimize!(model) 53 | status = termination_status(model) 54 | if status != MOI.OPTIMAL 55 | println("termination status: $status") 56 | status = primal_status(model) 57 | println("solution status: $status") 58 | end 59 | optimum = objective_value(model) 60 | end 61 | @show optimum 62 | println("solving time: $time seconds.") 63 | return optimum 64 | end 65 | 66 | """ 67 | optimum = SparseSumOfRatios(p, q, g, h, x, d; QUIET=false, SignSymmetry=true, GroebnerBasis=false) 68 | 69 | Minimizing the sum of sparse ratios p1/q1 + ... + pN/qN on the set defined by g >= 0 and h == 0. 70 | 71 | # Input arguments 72 | - `p`: vector of denominators 73 | - `q`: vector of numerator 74 | - `g`: inequality constraints 75 | - `h`: equality constraints 76 | - `x`: vector of variables 77 | - `d`: relaxation order 78 | 79 | # Output arguments 80 | - `SignSymmetry`: exploit sign symmetries or not (`true`, `false`) 81 | - `GroebnerBasis`: exploit the quotient ring structure or not (`true`, `false`) 82 | """ 83 | function SparseSumOfRatios(p, q, g, h, x, d; QUIET=false, dualize=false, SignSymmetry=true, mosek_setting=mosek_para(), GroebnerBasis=false) 84 | println("*********************************** TSSOS ***********************************") 85 | println("TSSOS is launching...") 86 | N = length(p) 87 | if SignSymmetry == true 88 | polys = [p; q] 89 | if !isempty(g) 90 | polys = [polys; g] 91 | end 92 | if !isempty(h) 93 | polys = [polys; h] 94 | end 95 | ss = get_signsymmetry(polys, x) 96 | end 97 | TS = SignSymmetry == true ? "block" : false 98 | dq = maxdegree.(q) 99 | vp = Vector{Vector{PolyVar{true}}}(undef, N) 100 | for i = 1:N 101 | if typeof(p[i]) == Polynomial 102 | vp[i] = variables(p[i]) 103 | else 104 | vp[i] = PolyVar{true}[] 105 | end 106 | end 107 | I = [unique([vp[i]; variables(q[i])]) for i=1:N] 108 | vg = variables.(g) 109 | J = [findall(j->issubset(vg[j], I[i]), 1:length(g)) for i=1:N] 110 | vh = variables.(h) 111 | K = [findall(j->issubset(vh[j], I[i]), 1:length(h)) for i=1:N] 112 | U = [findall(j->!isempty(intersect(I[i], I[j])), i+1:N) .+ i for i=1:N-1] 113 | V = [findall(j->!isempty(intersect(I[i], I[j])), 1:i-1) for i=2:N] 114 | time = @elapsed begin 115 | if dualize == false 116 | model = Model(optimizer_with_attributes(Mosek.Optimizer, "MSK_DPAR_INTPNT_CO_TOL_PFEAS" => mosek_setting.tol_pfeas, "MSK_DPAR_INTPNT_CO_TOL_DFEAS" => mosek_setting.tol_dfeas, 117 | "MSK_DPAR_INTPNT_CO_TOL_REL_GAP" => mosek_setting.tol_relgap, "MSK_DPAR_OPTIMIZER_MAX_TIME" => mosek_setting.time_limit, "MSK_IPAR_NUM_THREADS" => mosek_setting.num_threads)) 118 | else 119 | model = Model(dual_optimizer(Mosek.Optimizer)) 120 | end 121 | set_optimizer_attribute(model, MOI.Silent(), QUIET) 122 | hh = Vector{Vector{Polynomial{true, AffExpr}}}(undef, N) 123 | for i = 1:N-1 124 | hh[i] = Vector{Polynomial{true, AffExpr}}(undef, length(U[i])) 125 | for (ind, j) in enumerate(U[i]) 126 | Iij = intersect(I[i], I[j]) 127 | if SignSymmetry == true 128 | temp = [ncbfind(x, length(x), item) for item in Iij] 129 | hh[i][ind] = add_poly!(model, Iij, 2d-max(dq[i], dq[j]), signsymmetry=ss[temp, :])[1] 130 | else 131 | hh[i][ind] = add_poly!(model, Iij, 2d-max(dq[i], dq[j]))[1] 132 | end 133 | end 134 | end 135 | hh[N] = Polynomial{true, AffExpr}[] 136 | c = @variable(model, [1:N]) 137 | for i = 1:N 138 | if i == 1 139 | temp = 0 140 | else 141 | ind = [bfind(U[j], length(U[j]), i) for j in V[i-1]] 142 | temp = sum(hh[V[i-1][j]][ind[j]] for j=1:length(V[i-1])) 143 | end 144 | add_psatz!(model, p[i]-(c[i]+sum(hh[i])-temp)*q[i], I[i], g[J[i]], h[K[i]], d, QUIET=QUIET, CS=false, TS=TS, GroebnerBasis=GroebnerBasis) 145 | end 146 | @objective(model, Max, sum(c)) 147 | end 148 | println("SDP assembling time: $time seconds.") 149 | println("Solving the SDP...") 150 | time = @elapsed begin 151 | optimize!(model) 152 | end 153 | println("SDP solving time: $time seconds.") 154 | status = termination_status(model) 155 | if status != MOI.OPTIMAL 156 | println("termination status: $status") 157 | status = primal_status(model) 158 | println("solution status: $status") 159 | end 160 | optimum = objective_value(model) 161 | @show optimum 162 | return optimum 163 | end -------------------------------------------------------------------------------- /src/utils.jl: -------------------------------------------------------------------------------- 1 | # find the location of an entry a in a sorted sequence A 2 | function bfind(A, l, a) 3 | low = 1 4 | high = l 5 | while low <= high 6 | mid = Int(ceil(1/2*(low+high))) 7 | if ndims(A) == 2 8 | temp = A[:, mid] 9 | else 10 | temp = A[mid] 11 | end 12 | if temp == a 13 | return mid 14 | elseif temp < a 15 | low = mid + 1 16 | else 17 | high = mid - 1 18 | end 19 | end 20 | return nothing 21 | end 22 | 23 | function lbfind(A, l, a) 24 | low = 1 25 | high = l 26 | while low <= high 27 | mid = Int(ceil(1/2*(low+high))) 28 | temp = A[mid] 29 | if temp == a 30 | return mid 31 | elseif temp < a 32 | low = mid + 1 33 | else 34 | high = mid - 1 35 | end 36 | end 37 | return nothing 38 | end 39 | 40 | function ncbfind(A, l, a) 41 | low = 1 42 | high = l 43 | while low <= high 44 | mid = Int(ceil(1/2*(low+high))) 45 | if A[mid] == a 46 | return mid 47 | elseif A[mid] < a 48 | high = mid - 1 49 | else 50 | low = mid + 1 51 | end 52 | end 53 | return nothing 54 | end 55 | 56 | function get_signsymmetry(polys::Vector{DP.Polynomial{V, M, T}}, x) where {V, M, T<:Number} 57 | n = length(x) 58 | supp = zeros(UInt8, 1, n) 59 | for k = 1:length(polys) 60 | mons = MP.monomials(polys[k]) 61 | temp = zeros(UInt8, length(mons), n) 62 | for i in eachindex(mons), j = 1:n 63 | @inbounds temp[i, j] = MP.degree(mons[i], x[j]) 64 | end 65 | supp = [supp; temp] 66 | end 67 | supp = unique(supp, dims=1) 68 | supp = matrix(GF(2), supp) 69 | return nullspace(supp)[2] 70 | end 71 | 72 | function get_signsymmetry(supp::Vector{Vector{Vector{UInt16}}}, n) 73 | nsupp = zeros(UInt8, sum(length.(supp)), n) 74 | l = 1 75 | for item in supp, bi in item 76 | for i in bi 77 | nsupp[l, i] += 1 78 | end 79 | l += 1 80 | end 81 | nsupp = unique(nsupp, dims=1) 82 | nsupp = matrix(GF(2), nsupp) 83 | return nullspace(nsupp)[2] 84 | end 85 | 86 | function get_signsymmetry(supp::Matrix{UInt8}) 87 | supp = unique(supp, dims=1) 88 | supp = matrix(GF(2), supp) 89 | return nullspace(supp)[2] 90 | end 91 | 92 | function bin_add(bi, bj, nb) 93 | bs = bi + bj 94 | if nb > 0 95 | bs[1:nb,:] = isodd.(bs[1:nb,:]) 96 | end 97 | return bs 98 | end 99 | 100 | function sadd(a, b; nb=0) 101 | c = [a; b] 102 | sort!(c) 103 | if nb > 0 104 | i = 1 105 | while i < length(c) 106 | if c[i] <= nb 107 | if c[i] == c[i+1] 108 | deleteat!(c, i:i+1) 109 | else 110 | i += 1 111 | end 112 | else 113 | break 114 | end 115 | end 116 | end 117 | return c 118 | end 119 | 120 | # generate the standard monomial basis 121 | function get_basis(n::Int, d::Int; nb=0, lead=[], var=[]) 122 | if isempty(var) 123 | lb = binomial(n+d, d) 124 | basis = zeros(UInt8, n, lb) 125 | i = 0 126 | t = 1 127 | while i < d+1 128 | t += 1 129 | if basis[n,t-1] == i 130 | if i < d 131 | basis[1,t] = i+1 132 | end 133 | i += 1 134 | else 135 | j = findfirst(x->basis[x,t-1]!=0, 1:n) 136 | basis[:,t] = basis[:,t-1] 137 | if j == 1 138 | basis[1,t] -= 1 139 | basis[2,t] += 1 140 | else 141 | basis[1,t] = basis[j,t] - 1 142 | basis[j,t] = 0 143 | basis[j+1,t] += 1 144 | end 145 | end 146 | end 147 | if nb > 0 148 | basis_bin = basis[1:nb,:] 149 | basis_valid = all.(x->x<=1, eachcol(basis_bin)) 150 | basis = basis[:, basis_valid] 151 | end 152 | if !isempty(lead) 153 | basis_valid = map(a->!divide(a, lead, n, size(lead,2)), eachcol(basis)) 154 | basis = basis[:, basis_valid] 155 | end 156 | else 157 | lb = binomial(length(var)+d, d) 158 | basis = zeros(UInt8, n, lb) 159 | i = 0 160 | t = 1 161 | while i < d+1 162 | t += 1 163 | if basis[var[end], t-1] == i 164 | if i < d 165 | basis[var[1], t] = i + 1 166 | end 167 | i += 1 168 | else 169 | j = findfirst(x->basis[var[x], t-1] != 0, 1:n) 170 | basis[:, t] = basis[:, t-1] 171 | if j == 1 172 | basis[var[1], t] -= 1 173 | basis[var[2], t] += 1 174 | else 175 | basis[var[1], t] = basis[var[j], t] - 1 176 | basis[var[j], t] = 0 177 | basis[var[j+1], t] += 1 178 | end 179 | end 180 | end 181 | end 182 | return basis 183 | end 184 | 185 | # generate the standard monomial basis in the sparse form 186 | function get_basis(var::Vector{T}, d::Int; nb=0) where T <: Union{UInt16, Int} 187 | n = length(var) 188 | lb = binomial(n+d, d) 189 | basis = Vector{Vector{UInt16}}(undef, lb) 190 | basis[1] = UInt16[] 191 | i = 0 192 | t = 1 193 | while i < d + 1 194 | t += 1 195 | if sum(basis[t-1]) == var[n]*i 196 | if i < d 197 | basis[t] = var[1]*ones(UInt16, i+1) 198 | end 199 | i += 1 200 | else 201 | j = bfind(var, n, basis[t-1][1]) 202 | basis[t] = copy(basis[t-1]) 203 | ind = findfirst(x->basis[t][x]!=var[j], 1:length(basis[t])) 204 | if ind === nothing 205 | ind = length(basis[t])+1 206 | end 207 | if j != 1 208 | basis[t][1:ind-2] = var[1]*ones(UInt16, ind-2) 209 | end 210 | basis[t][ind-1] = var[j+1] 211 | end 212 | end 213 | if nb > 0 214 | ind = [!any([basis[i][j] == basis[i][j+1] && basis[i][j] <= nb for j = 1:length(basis[i])-1]) for i = 1:lb] 215 | basis = basis[ind] 216 | end 217 | return basis 218 | end 219 | 220 | function get_conjugate_basis(var::Vector{UInt16}, d::Int; nb=0) 221 | temp = get_basis(var, d) 222 | basis = vec([[item1, item2] for item1 in temp, item2 in temp]) 223 | basis = basis[[length(item[1]) + length(item[2]) <= d for item in basis]] 224 | if nb > 0 225 | basis = reduce_unitnorm.(basis, nb=nb) 226 | unique!(basis) 227 | end 228 | sort!(basis) 229 | return basis 230 | end 231 | 232 | function newton_basis(n, d, supp; e=1e-5, solver="Mosek") 233 | lsupp = size(supp, 2) 234 | basis = get_basis(n, d) 235 | lb = size(basis, 2) 236 | A0 = [-1/2*supp' ones(lsupp,1)] 237 | t = 1 238 | indexb = [i for i=1:lb] 239 | temp = sortslices(supp, dims=2) 240 | while t <= lb 241 | i = indexb[t] 242 | if bfind(temp, lsupp, UInt8(2)*basis[:,i]) !== nothing 243 | t += 1 244 | else 245 | if solver == "Mosek" 246 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 247 | elseif solver == "SDPT3" 248 | model = Model(optimizer_with_attributes(SDPT3.Optimizer)) 249 | elseif solver == "SDPNAL" 250 | model = Model(optimizer_with_attributes(SDPNAL.Optimizer)) 251 | elseif solver == "COSMO" 252 | model = Model(optimizer_with_attributes(COSMO.Optimizer)) 253 | else 254 | @error "The solver is currently not supported!" 255 | return nothing 256 | end 257 | set_optimizer_attribute(model, MOI.Silent(), true) 258 | @variable(model, x[1:n+1], lower_bound=-10, upper_bound=10) 259 | @constraint(model, [A0; [basis[:,i]' -1]]*x .<= zeros(lsupp+1)) 260 | @objective(model, Min, [basis[:,i]' -1]*x) 261 | optimize!(model) 262 | vx = value.(x) 263 | if abs(objective_value(model)) <= e && sum(abs.(vx)) <= e 264 | t += 1 265 | else 266 | if abs(objective_value(model)) <= e && sum(abs.(vx)) > e 267 | t += 1 268 | else 269 | lb -= 1 270 | indexb = deleteat!(indexb, t) 271 | end 272 | r = t 273 | while lb >= r 274 | j = indexb[r] 275 | if [basis[:,j]' -1]*vx <= -e 276 | lb -= 1 277 | indexb = deleteat!(indexb, r) 278 | else 279 | r += 1 280 | end 281 | end 282 | end 283 | end 284 | end 285 | return basis[:,indexb] 286 | end 287 | 288 | function generate_basis!(supp, basis) 289 | supp = sortslices(supp, dims=2) 290 | supp = unique(supp, dims=2) 291 | lsupp = size(supp, 2) 292 | lb = size(basis, 2) 293 | indexb = Int[] 294 | for i = 1:lb, j = i:lb 295 | bi = basis[:,i] + basis[:,j] 296 | if bfind(supp, lsupp, bi) !== nothing 297 | push!(indexb, i, j) 298 | end 299 | end 300 | sort!(indexb) 301 | unique!(indexb) 302 | return basis[:,indexb] 303 | end 304 | 305 | function eval(supp::Vector{Vector{UInt16}}, coe, x) 306 | return coe'*[prod(x[item]) for item in supp] 307 | end 308 | 309 | function eval(supp::Vector{Vector{Vector{UInt16}}}, coe, z) 310 | return real(transpose(coe)*[prod(z[item[1]])*conj(prod(z[item[2]])) for item in supp]) 311 | end 312 | 313 | function npolys_info(pop, x; nb=0) 314 | if nb > 0 315 | pop = Groebner.normalform(x[1:nb].^2 .- 1, pop) 316 | end 317 | coe = Vector{Vector{Union{Number, AffExpr}}}(undef, length(pop)) 318 | supp = Vector{Matrix{UInt8}}(undef, length(pop)) 319 | for (k, p) in enumerate(pop) 320 | supp[k],coe[k] = poly_info(p, x) 321 | end 322 | return supp,coe 323 | end 324 | 325 | function poly_info(p, x) 326 | mons = MP.monomials(p) 327 | coe = MP.coefficients(p) 328 | supp = zeros(UInt8, length(x), length(mons)) 329 | for (j, mon) in enumerate(mons) 330 | supp[:, j] = MP.degree.(mon, x) 331 | end 332 | return supp,coe 333 | end 334 | 335 | function polys_info(pop, x; nb=0) 336 | n = length(x) 337 | if nb > 0 338 | pop = Groebner.normalform(x[1:nb].^2 .- 1, pop) 339 | end 340 | coe = Vector{Vector{Union{Number, AffExpr}}}(undef, length(pop)) 341 | supp = Vector{Vector{Vector{UInt16}}}(undef, length(pop)) 342 | for (k, p) in enumerate(pop) 343 | mons = MP.monomials(p) 344 | coe[k] = MP.coefficients(p) 345 | supp[k] = [UInt16[] for i=1:length(mons)] 346 | for (i,mon) in enumerate(mons) 347 | ind = mon.z .> 0 348 | vars = mon.vars[ind] 349 | exp = mon.z[ind] 350 | for j in eachindex(vars) 351 | append!(supp[k][i], ncbfind(x, n, vars[j])*ones(UInt16, exp[j])) 352 | end 353 | end 354 | end 355 | return supp,coe 356 | end 357 | 358 | function cpolys_info(pop, x; ctype=ComplexF64) 359 | n = length(x) 360 | cx = conj.(x) 361 | coe = Vector{Vector{ctype}}(undef, length(pop)) 362 | supp = Vector{Vector{Vector{Vector{UInt16}}}}(undef, length(pop)) 363 | for k in eachindex(pop) 364 | mons = MP.monomials(pop[k]) 365 | coe[k] = MP.coefficients(pop[k]) 366 | supp[k] = [[[], []] for i=1:length(mons)] 367 | for (i,mon) in enumerate(mons) 368 | ind = mon.z .> 0 369 | vars = mon.vars[ind] 370 | exp = mon.z[ind] 371 | for j in eachindex(vars) 372 | if isconj(vars[j]) 373 | append!(supp[k][i][2], ncbfind(cx, n, vars[j])*ones(UInt16, exp[j])) 374 | else 375 | append!(supp[k][i][1], ncbfind(x, n, vars[j])*ones(UInt16, exp[j])) 376 | end 377 | end 378 | end 379 | end 380 | return supp,coe 381 | end 382 | 383 | function resort(supp, coe; nb=0) 384 | if nb > 0 385 | supp = reduce_unitnorm.(supp, nb=nb) 386 | end 387 | nsupp = copy(supp) 388 | sort!(nsupp) 389 | unique!(nsupp) 390 | l = length(nsupp) 391 | ncoe = zeros(typeof(coe[1]), l) 392 | for i in eachindex(supp) 393 | locb = bfind(nsupp, l, supp[i]) 394 | ncoe[locb] += coe[i] 395 | end 396 | return nsupp,ncoe 397 | end 398 | 399 | function divide(a, lead, n, llead) 400 | return any(j->all(i->lead[i,j]<=a[i], 1:n), 1:llead) 401 | end 402 | 403 | function reminder(a, x, gb, n) 404 | rem = Groebner.normalform(gb, prod(x.^a), ordering=DegRevLex()) 405 | mon = MP.monomials(rem) 406 | coe = MP.coefficients(rem) 407 | lm = length(mon) 408 | supp = zeros(UInt8, n, lm) 409 | for i = 1:lm, j = 1:n 410 | @inbounds supp[j,i] = MP.degree(mon[i], x[j]) 411 | end 412 | return lm,supp,coe 413 | end 414 | 415 | function sign_type(a::Vector{UInt16}) 416 | st = UInt16[] 417 | if length(a) == 1 418 | push!(st, a[1]) 419 | elseif length(a) > 1 420 | r = 1 421 | for i = 2:length(a) 422 | if a[i] == a[i-1] 423 | r += 1 424 | else 425 | if isodd(r) 426 | push!(st, a[i-1]) 427 | end 428 | r = 1 429 | end 430 | end 431 | if isodd(r) 432 | push!(st, a[end]) 433 | end 434 | end 435 | return st 436 | end 437 | 438 | """ 439 | p,coe,mon = add_poly!(model, vars, degree) 440 | 441 | Generate an unknown polynomial of given degree whose coefficients are from the JuMP `model`. 442 | 443 | # Input arguments 444 | - `model`: a JuMP optimization model 445 | - `vars`: set of variables 446 | - `degree`: degree of the polynomial 447 | 448 | # Output arguments 449 | - `p`: the polynomial 450 | - `coe`: coefficients of the polynomial 451 | - `mon`: monomials of the polynomial 452 | """ 453 | function add_poly!(model, vars, degree::Int; signsymmetry=false) 454 | mon = vcat([MP.monomials(vars, i) for i = 0:degree]...) 455 | if signsymmetry != false 456 | ind = [all(transpose(signsymmetry)*exponents(item) .== 0) for item in mon] 457 | mon = mon[ind] 458 | end 459 | coe = @variable(model, [1:length(mon)]) 460 | p = coe'*mon 461 | return p,coe,mon 462 | end 463 | 464 | """ 465 | p,coe,basis = add_poly_cheby!(model, vars, degree) 466 | 467 | Generate an unknown polynomial of given degree in the Chebyshev basis whose coefficients are from the JuMP `model`. 468 | 469 | # Input arguments 470 | - `model`: a JuMP optimization model 471 | - `vars`: set of variables 472 | - `degree`: degree of the polynomial 473 | 474 | # Output arguments 475 | - `p`: the polynomial 476 | - `coe`: coefficients of the polynomial 477 | - `basis`: Chebyshev basis 478 | """ 479 | function add_poly_cheby!(model, vars, degree::Int) 480 | basis = basis_covering_monomials(ChebyshevBasis, MP.monomials(vars, 0:degree)) 481 | coe = @variable(model, [1:length(basis)]) 482 | p = coe'*basis 483 | return p,coe,basis 484 | end 485 | 486 | function add_poly!(model, vars, supp::Array{UInt8,2}) 487 | mon = [prod(vars.^supp[:,i]) for i = 1:size(supp,2)] 488 | coe = @variable(model, [1:length(mon)]) 489 | p = coe'*mon 490 | return p,coe,mon 491 | end 492 | 493 | function numele(a) 494 | return Int(sum(Int.(a).^2+a)/2) 495 | end 496 | 497 | """ 498 | show_blocks(data) 499 | 500 | Display the block structure 501 | """ 502 | function show_blocks(data::cpop_data) 503 | for j = 1:length(data.blocks[1]) 504 | print("block $j: ") 505 | println([prod(data.x.^data.basis[1][:, data.blocks[1][j][k]]) for k = 1:data.blocksize[1][j]]) 506 | end 507 | end 508 | 509 | function show_blocks(data::mcpop_data) 510 | for l = 1:data.cql, j = 1:length(data.blocks[l][1]) 511 | print("clique $l, block $j: ") 512 | println([prod(data.x[data.basis[l][1][data.blocks[l][1][j][k]]]) for k = 1:data.blocksize[l][1][j]]) 513 | end 514 | end 515 | 516 | function complex_to_real(cpop, z) 517 | n = length(z) 518 | @polyvar x[1:2n] 519 | pop = Vector{DP.Polynomial}(undef, length(cpop)) 520 | for (i,cp) in enumerate(cpop) 521 | temp = cp(z => x[1:n]+im*x[n+1:2n]) 522 | pop[i] = real.(MP.coefficients(temp))'*MP.monomials(temp) 523 | end 524 | return pop,x 525 | end 526 | 527 | function cmod(a, m) 528 | s = mod(a, m) 529 | return s == 0 ? m : s 530 | end 531 | 532 | # generate an SOS polynomial with variables vars and degree 2d 533 | """ 534 | sos = add_SOS!(model, vars, d) 535 | 536 | Generate an SOS polynomial of degree 2d whose coefficients are from the JuMP `model`. 537 | 538 | # Input arguments 539 | - `model`: a JuMP optimization model 540 | - `vars`: set of variables 541 | - `d`: half degree of the SOS polynomial 542 | 543 | # Output arguments 544 | - `sos`: the sos polynomial 545 | """ 546 | function add_SOS!(model, vars, d) 547 | basis = vcat([MP.monomials(vars, i) for i = 0:d]...) 548 | sos = 0 549 | pos = @variable(model, [1:length(basis), 1:length(basis)], PSD) 550 | for j = 1:length(basis), k = j:length(basis) 551 | if j == k 552 | @inbounds sos += pos[j,k]*basis[j]*basis[k] 553 | else 554 | @inbounds sos += 2*pos[j,k]*basis[j]*basis[k] 555 | end 556 | end 557 | return sos 558 | end 559 | 560 | # generate an SOS polynomial with monomial `basis` 561 | """ 562 | sos = add_SOS!(model, basis) 563 | 564 | Generate an SOS polynomial with monomial `basis` whose coefficients are from the JuMP `model`. 565 | 566 | # Input arguments 567 | - `model`: a JuMP optimization model 568 | - `basis`: monomial basis 569 | 570 | # Output arguments 571 | - `sos`: the sos polynomial 572 | """ 573 | function add_SOS!(model, basis) 574 | sos = 0 575 | pos = @variable(model, [1:length(basis), 1:length(basis)], PSD) 576 | for j = 1:length(basis), k = j:length(basis) 577 | if j == k 578 | @inbounds sos += pos[j,k]*basis[j]*basis[k] 579 | else 580 | @inbounds sos += 2*pos[j,k]*basis[j]*basis[k] 581 | end 582 | end 583 | return sos 584 | end 585 | -------------------------------------------------------------------------------- /test/cpop_test.jl: -------------------------------------------------------------------------------- 1 | using TSSOS 2 | using DynamicPolynomials 3 | using Test 4 | 5 | @testset begin 6 | 7 | @complex_polyvar z[1:2] 8 | pop = [3-z[1]*conj(z[1])-0.5im*z[1]*conj(z[2])^2+0.5im*z[2]^2*conj(z[1]), z[2]+conj(z[2]), 9 | -1+z[1]*conj(z[1])-0.25*z[1]^2-0.25*conj(z[1])^2, -3+z[1]*conj(z[1])+z[2]*conj(z[2]), im*z[2]-im*conj(z[2])] 10 | opt,sol,data = complex_tssos_first(pop, z, 2, numeq=3, QUIET=true, TS="block", solution=true, Gram=true) 11 | @test opt ≈ -0.4165019 atol = 1e-6 12 | opt,sol,data = complex_tssos_higher!(data, QUIET=true, TS="block", solution=true, Gram=true) 13 | @test opt ≈ 0.4281746 atol = 1e-6 14 | 15 | @complex_polyvar z[1:3] 16 | pop = [z[1]^2*conj(z[2])+z[2]*conj(z[1])^2+z[1]*conj(z[2])+z[2]*conj(z[1])+z[2]*conj(z[3])+z[3]*conj(z[2]), 17 | 1-z[1]*conj(z[1])-z[2]*conj(z[2]), 1-z[2]*conj(z[2])-z[3]*conj(z[3]), 1+z[2]+conj(z[2])] 18 | opt,sol,data = complex_cs_tssos_first(pop, z, 2, numeq=1, QUIET=true, TS="block", solution=true, Gram=true) 19 | @test opt ≈ -2.682188 atol = 1e-6 20 | 21 | @complex_polyvar z[1:3] 22 | f = 0.5z[1]*conj(z[2])+0.5z[1]*conj(z[3])+0.5z[2]*conj(z[1])+0.25z[2]*conj(z[2])+0.25z[2]*conj(z[3])+0.5z[3]*conj(z[1])+ 23 | 0.25z[3]*conj(z[2])+z[1]+z[2]+z[3]+conj(z[1])+conj(z[2])+conj(z[3]) 24 | pop = [f, 1-z[1]*conj(z[1]), 1-z[2]*conj(z[2]), 1-z[3]*conj(z[3])] 25 | opt,sol,data = complex_cs_tssos_first(pop, z, 2, numeq=3, QUIET=true, TS=false, solution=true, Gram=true) 26 | @test opt ≈ -3.75 atol = 1e-6 27 | 28 | @complex_polyvar z[1:2] 29 | pop = [z[1]+z[2]+conj(z[1])+conj(z[2]), (1+im)*z[1]^2*conj(z[2])+(1-im)*z[2]*conj(z[1])^2, 1 - z'*z] 30 | opt,sol,data = complex_cs_tssos_first(pop, z, 2, numeq=1, QUIET=true, TS="block", ConjugateBasis=true, solution=true, Gram=true) 31 | @test opt ≈ -2.7423247 atol = 1e-6 32 | opt,sol,data = complex_cs_tssos_first(pop, z, 2, numeq=1, QUIET=true, TS="block", ConjugateBasis=true, normality=2, solution=true, Gram=true) 33 | @test opt ≈ -2.7423247 atol = 1e-6 34 | opt,sol,data = complex_cs_tssos_first(pop, z, 2, numeq=1, QUIET=true, TS="block", solution=true, Gram=true) 35 | @test opt ≈ -2.7423247 atol = 1e-6 36 | opt,sol,data = complex_cs_tssos_higher!(data, QUIET=true, TS="block", solution=true, Gram=true) 37 | @test opt ≈ -2.7423247 atol = 1e-6 38 | 39 | @complex_polyvar z[1:2] 40 | pop = [z[1]*z[2] + conj(z[1])*conj(z[2]), 1 - z'*z] 41 | opt,sol,data = complex_cs_tssos_first(pop, z, 2, numeq=1, QUIET=true, TS="block", solution=true, Gram=true) 42 | @test opt ≈ -1 atol = 1e-6 43 | 44 | @complex_polyvar x[1:3] 45 | pop = [1, x[1]^2-2x[1]*x[3]+conj(x[1]^2)-2conj(x[1]*x[3])+10, im*(x[1]^2-2x[1]*x[3])-im*(conj(x[1]^2)-2conj(x[1]*x[3])), 46 | x[1]*x[2]^2+x[2]*x[3]+conj(x[1]*x[2]^2+x[2]*x[3])+2, im*(x[1]*x[2]^2+x[2]*x[3])-im*conj(x[1]*x[2]^2+x[2]*x[3])+2, 47 | 3x[2]^2-8x[1]*x[3]+conj(3x[2]^2-8x[1]*x[3]), im*(3x[2]^2-8x[1]*x[3])-im*conj(3x[2]^2-8x[1]*x[3])] 48 | opt,sol,data = complex_tssos_first(pop, x, 3, numeq=6, TS="block", Gram=true, solution=true, QUIET=true) 49 | @test opt ≈ 1 atol = 1e-6 50 | 51 | @complex_polyvar z[1:3] 52 | pop = [1, z[1]^2+z[2]+z[3]+conj(z[1]^2+z[2]+z[3])+2, im*(z[1]^2+z[2]+z[3])-im*conj(z[1]^2+z[2]+z[3]), 53 | z[2]^2+z[1]+z[3]+conj(z[2]^2+z[1]+z[3])+2, im*(z[2]^2+z[1]+z[3])-im*conj(z[2]^2+z[1]+z[3]), 54 | z[3]^2+z[2]+z[1]+conj(z[3]^2+z[2]+z[1])+2, im*(z[3]^2+z[2]+z[1])-im*conj(z[3]^2+z[2]+z[1])] 55 | opt,sol,data = complex_tssos_first(pop, z, 3, numeq=6, TS="block", Gram=true, solution=true, QUIET=true) 56 | @test opt ≈ 1 atol = 1e-6 57 | 58 | @complex_polyvar z1 z2 z3 59 | z = tuple(z1,z2,z3) 60 | f = - z3*conj(z3) 61 | g1 = z1^2*conj(z1)^2 - z1^2 - conj(z1)^2 - 4*z3*conj(z3) + 1 62 | g2 = z2^2*conj(z2)^2 - z2^2 - conj(z2)^2 - 4*z3*conj(z3) + 1 63 | h1 = - z1*conj(z1) - z2*conj(z2) + 2/3 64 | h2 = 3*z1*z2 + 3*conj(z1)*conj(z2) - 2 65 | h3 = 9*z1*z2*conj(z1)*conj(z2) - 1 66 | cpop = [f; g1; g2; h1; h2; h3] 67 | opt,sol,data = complex_cs_tssos_first(cpop, z, 2, numeq=3, CS=false, TS="block", solution=true, QUIET=true, Gram=true) 68 | @test opt ≈ -0.4444444 atol = 1e-6 69 | 70 | n = 3 71 | @complex_polyvar z1 z2 z3 z4 72 | z = tuple(z1,z2,z3,z4) 73 | f = - z4*conj(z4) 74 | g1 = 9 - 6*z1^3 + 12*z1^2*z2 + 12*z1^2*z3 - 6*conj(z1)^3 + 4*z1^3*conj(z1)^3 - 75 | 8*z1^2*z2*conj(z1)^3 - 8*z1^2*z3*conj(z1)^3 + 12*conj(z1)^2*conj(z2) - 76 | 8*z1^3*conj(z1)^2*conj(z2) + 16*z1^2*z2*conj(z1)^2*conj(z2) + 16*z1^2*z3*conj(z1)^2*conj(z2) + 77 | 12*conj(z1)^2*conj(z3) - 8*z1^3*conj(z1)^2*conj(z3) + 16*z1^2*z2*conj(z1)^2*conj(z3) + 78 | 16*z1^2*z3*conj(z1)^2*conj(z3) - 36*z4*conj(z4) 79 | g2 = 9 + 12*z1*z2^2 - 6*z2^3 + 12*z2^2*z3 + 12*conj(z1)*conj(z2)^2 + 80 | 16*z1*z2^2*conj(z1)*conj(z2)^2 - 8*z2^3*conj(z1)*conj(z2)^2 + 16*z2^2*z3*conj(z1)*conj(z2)^2 - 81 | 6*conj(z2)^3 - 8*z1*z2^2*conj(z2)^3 + 4*z2^3*conj(z2)^3 - 8*z2^2*z3*conj(z2)^3 + 82 | 12*conj(z2)^2*conj(z3) + 16*z1*z2^2*conj(z2)^2*conj(z3) - 8*z2^3*conj(z2)^2*conj(z3) + 83 | 16*z2^2*z3*conj(z2)^2*conj(z3) - 36*z4*conj(z4) 84 | g3 = 9 + 12*z1*z3^2 + 12*z2*z3^2 - 6*z3^3 + 12*conj(z1)*conj(z3)^2 + 85 | 16*z1*z3^2*conj(z1)*conj(z3)^2 + 16*z2*z3^2*conj(z1)*conj(z3)^2 - 8*z3^3*conj(z1)*conj(z3)^2 + 86 | 12*conj(z2)*conj(z3)^2 + 16*z1*z3^2*conj(z2)*conj(z3)^2 + 16*z2*z3^2*conj(z2)*conj(z3)^2 - 87 | 8*z3^3*conj(z2)*conj(z3)^2 - 6*conj(z3)^3 - 8*z1*z3^2*conj(z3)^3 - 88 | 8*z2*z3^2*conj(z3)^3 + 4*z3^3*conj(z3)^3 - 36*z4*conj(z4) 89 | h1 = z1*conj(z1) + z2*conj(z2) + z3*conj(z3) - n*(1/(n+1))^(2/n) 90 | h2 = 2*z1*z2*z3 + 2*conj(z1)*conj(z2)*conj(z3) + 1 91 | h3 = 16*z1*z2*z3*conj(z1)*conj(z2)*conj(z3) - 1 92 | cpop = [f; g1; g2; g3; h1; h2; h3] 93 | opt,sol,data = complex_cs_tssos_first(cpop, z, 5, numeq=3, CS=false, TS="block", QUIET=true, solve=false) 94 | opt,sol,data = complex_cs_tssos_higher!(data, TS="block", QUIET=true, solve=false) 95 | opt,sol,data = complex_cs_tssos_higher!(data, TS="block", QUIET=true, Gram=true) 96 | @test opt ≈ -0.5625 atol = 1e-6 97 | 98 | N = 6 99 | @complex_polyvar z[1:N+1] 100 | f = z[N+1]^2 + conj(z[N+1])^2 101 | cons = Vector{typeof(f)}(undef, N-2) 102 | for k = 1:N-2 103 | cons[k] = z[N+1]^2 + conj(z[N+1])^2 - sum(z[i]*z[j+k]*conj(z[j])*conj(z[i+k]) for i = 1:N-k, j = 1:N-k) 104 | end 105 | opt,sol,data = complex_cs_tssos_first([f; cons], z, 3, nb=N+1, CS=false, TS="block", ConjugateBasis=true, QUIET=true, Gram=true) 106 | @test opt ≈ 1 atol = 1e-6 107 | 108 | end 109 | -------------------------------------------------------------------------------- /test/runtest.jl: -------------------------------------------------------------------------------- 1 | using DynamicPolynomials 2 | using TSSOS 3 | using JuMP 4 | using MosekTools 5 | using PermutationGroups 6 | using Test 7 | 8 | 9 | @testset begin 10 | 11 | # Unconstrained Polynomial Optimization 12 | @polyvar x[1:3] 13 | f = 1+x[1]^4+x[2]^4+x[3]^4+x[1]*x[2]*x[3]+x[2] 14 | opt,sol,data = tssos_first(f, x, newton=true, reducebasis=true, TS="block", solution=true, Gram=true, QUIET=true) 15 | @test opt ≈ 0.4752748 atol = 1e-6 16 | opt,sol,data = tssos_first(f, x, newton=false, reducebasis=false, TS="block", solution=true, Gram=true, QUIET=true) 17 | @test opt ≈ 0.4752748 atol = 1e-6 18 | opt,sol,data = tssos_higher!(data, TS="MD", solution=true, Gram=true, QUIET=true) 19 | @test opt ≈ 0.4752748 atol = 1e-6 20 | 21 | # Constrained Polynomial Optimization 22 | @polyvar x[1:3] 23 | f = 1+x[1]^4+x[2]^4+x[3]^4+x[1]*x[2]*x[3]+x[2] 24 | g = 0.5-x[1]^2-2*x[2]^2 25 | h = x[1]^2+x[2]^2+x[3]^2-1 26 | pop = [f, g, h] 27 | opt,sol,data = tssos_first(pop, x, 2, numeq=1, GroebnerBasis=false, TS="block", Gram=true, solution=true, QUIET=true) 28 | @test opt ≈ 0.9555474 atol = 1e-6 29 | opt,sol,data = tssos_first(pop, x, 2, numeq=1, GroebnerBasis=true, TS="block", Gram=true, solution=true, QUIET=true) 30 | @test opt ≈ 0.9555474 atol = 1e-6 31 | opt,sol,data = tssos_higher!(data, TS="block", solution=true, Gram=true, QUIET=true) 32 | @test opt ≈ 0.9555474 atol = 1e-6 33 | opt,sol,data = tssos_first(pop, x, 2, numeq=1, GroebnerBasis=true, TS="MD", Gram=true, solution=true, QUIET=true) 34 | @test opt ≈ 0.9555474 atol = 1e-6 35 | opt,sol,data = tssos_first(pop, x, 2, numeq=1, GroebnerBasis=false, TS=false, Gram=true, solution=true, QUIET=true) 36 | @test opt ≈ 0.9555474 atol = 1e-6 37 | opt,sol,data = tssos_first(pop, x, 2, numeq=1, GroebnerBasis=false, TS="signsymmetry", Gram=true, solution=true, QUIET=true) 38 | @test opt ≈ 0.9555474 atol = 1e-6 39 | 40 | @polyvar x[1:2] 41 | pop = [-x[1]-x[2], 2x[1]^4-8x[1]^3+8x[1]^2+2-x[2], 4x[1]^4-32x[1]^3+88x[1]^2-96x[1]+36-x[2], (3-x[1])*x[1], (4-x[2])*x[2]] 42 | opt,sol,data = tssos_first(pop, x, 3, TS="block", Gram=true, solution=true, QUIET=true) 43 | @test opt ≈ -5.508013 atol = 1e-6 44 | 45 | @polyvar x[1:3] 46 | pop = [x[1]^2*x[2]^2*(x[1]^2+x[2]^2-3x[3]^2)+x[3]^6, 1-x[1]^2-x[2]^2-x[3]^2] 47 | opt,sol,data = tssos_first(pop, x, 3, TS=false, Gram=true, solution=true, QUIET=true) 48 | @test opt ≈ -0.0045964 atol = 1e-6 49 | 50 | @polyvar x[1:4] 51 | pop = [3-x[1]^2-x[3]^2+x[1]*x[2]^2+2x[2]*x[3]*x[4]-x[1]*x[4]^2, x[2], x[1]^2+3x[3]^2-2, x[4], x[1]^2+x[2]^2+x[3]^2+x[4]^2-3] 52 | opt,sol,data = cs_tssos_first(pop, x, 2, numeq=3, TS="block", Gram=true, solution=true, QUIET=true) 53 | @test opt ≈ -0.4142135 atol = 1e-6 54 | opt,sol,data = cs_tssos_higher!(data, TS="block", Gram=true, solution=true, QUIET=true) 55 | @test opt ≈ -0.4142135 atol = 1e-6 56 | 57 | @polyvar x[1:6] 58 | f = -25*(x[1]-2)^2-(x[2]-2)^2-(x[3]-1)^2-(x[4]-4)^2-(x[5]-1)^2-(x[6]-4)^2 59 | pop = [f, (x[3]-3)^2+x[4]-4, (x[5]-3)^2+x[6]-4, 2-x[1]+3*x[2], 2+x[1]-x[2], 60 | 6-x[1]-x[2], x[1]+x[2]-2, (5-x[3])*(x[3]-1), (6-x[4])*x[4], (5-x[5])*(x[5]-1), 61 | (10-x[6])*x[6], x[1], x[2]] 62 | d = 2 63 | opt,sol,data = tssos_first(pop, x, d, TS="block", Gram=true, solution=true, QUIET=true) 64 | @test opt ≈ -310 atol = 1e-3 65 | opt,sol,data = cs_tssos_first(pop, x, d, TS="block", Gram=true, solution=true, QUIET=true) 66 | @test opt ≈ -310 atol = 1e-3 67 | 68 | @polyvar x[1:6] 69 | f = 1+sum(x.^4)+x[1]*x[2]*x[3]+x[3]*x[4]*x[5]+x[3]*x[4]*x[6]+x[3]*x[5]*x[6]+x[4]*x[5]*x[6] 70 | pop = [f, 1-sum(x[1:3].^2), 1-sum(x[3:6].^2)] 71 | d = 2 72 | opt,sol,data = cs_tssos_first(pop, x, d, numeq=1, TS="block", Gram=true, solution=true, QUIET=true) 73 | @test opt ≈ 0.71742533 atol = 1e-6 74 | opt,sol,data = cs_tssos_higher!(data, TS="MD", solution=true, Gram=true, QUIET=true) 75 | @test opt ≈ 0.71742533 atol = 1e-6 76 | opt,sol,data = cs_tssos_first(pop, x, d, numeq=1, TS="signsymmetry", Gram=true, solution=true, QUIET=true) 77 | @test opt ≈ 0.71742533 atol = 1e-6 78 | opt,sol,data = cs_tssos_first(pop, x, d, numeq=1, TS=false, Gram=true, solution=true, QUIET=true) 79 | @test opt ≈ 0.71742533 atol = 1e-6 80 | 81 | # Solving systems of polynomial equations 82 | @polyvar x[1:3] 83 | pop = [1, 5x[1]^9-6x[1]^5*x[2]+x[1]*x[2]^4+2x[1]*x[3], -2x[1]^6*x[2]+2x[1]^2*x[2]^3+2x[2]*x[3], x[1]^2+x[2]^2-0.265625] 84 | opt,sol,data = tssos_first(pop, x, 5, numeq=3, TS=false, GroebnerBasis=false, Gram=true, solution=true, QUIET=true) 85 | @test opt ≈ 1 atol = 1e-6 86 | 87 | @polyvar x[1:3] 88 | pop = [1, x[1]^2-2x[1]*x[3]+5, x[1]*x[2]^2+x[2]*x[3]+1, 3x[2]^2-8x[1]*x[3]] 89 | opt,sol,data = tssos_first(pop, x, 3, numeq=3, TS=false, Gram=true, solution=true, QUIET=true) 90 | @test opt ≈ 1 atol = 1e-6 91 | 92 | @polyvar x[1:6] 93 | h1 = 2*x[6]^2 + 2x[5]^2 + 2x[4]^2 + 2x[3]^2 + 2x[2]^2 + x[1]^2 - x[1] 94 | h2 = x[6]*x[5] + x[5]*x[4] + 2x[4]*x[3] + 2x[3]*x[2] + 2x[2]*x[1] - x[2] 95 | h3 = 2x[6]*x[4] + 2x[5]*x[3] + 2x[4]*x[2] + x[2]^2 + 2x[3]*x[1] - x[3] 96 | h4 = 2x[6]*x[3] + 2x[5]*x[2] + 2x[3]*x[2] + 2x[4]*x[1] - x[4] 97 | h5 = x[3]^2 + 2x[6]*x[1] + 2x[5]*x[1] + 2x[4]*x[1] - x[5] 98 | h6 = 2x[6] + 2x[5] + 2x[4] + 2x[3] + 2x[2] + x[1] - 1 99 | opt,sol,data = tssos_first([1;h1;h2;h3;h4;h5;h6], x, 3, numeq=6, TS=false, Gram=true, solution=true, QUIET=true, rtol=1e-6) 100 | @test opt ≈ 1 atol = 1e-6 101 | opt,sol,data = tssos_first([1;x[1]-0.5;h1;h2;h3;h4;h5;h6], x, 2, numeq=6, TS=false, Gram=true, solution=true, QUIET=true, rtol=1e-4) 102 | @test opt ≈ 1 atol = 1e-6 103 | 104 | # SOS Programming 105 | n = 3 106 | @polyvar x[1:3] 107 | f = [(x[1]^2+x[2]^2-1/4)*x[1], (x[2]^2+x[3]^2-1/4)*x[2], (x[2]^2+x[3]^2-1/4)*x[3]] 108 | g = [1-x[1]^2, 1-x[2]^2, 1-x[3]^2] 109 | d = 3 110 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 111 | set_optimizer_attribute(model, MOI.Silent(), true) 112 | v, vc, vb = add_poly!(model, x, 2d-2) 113 | w, wc, wb = add_poly!(model, x, 2d) 114 | Lv = v - sum(f .* differentiate(v, x)) 115 | info1 = add_psatz!(model, Lv, x, g, [], d, TS="block", SO=1, constrs="con1") 116 | info2 = add_psatz!(model, w, x, g, [], d, TS="block", SO=1) 117 | info3 = add_psatz!(model, w-v-1, x, g, [], d, TS="block", SO=1) 118 | moment = get_moment(wb, -ones(n), ones(n)) 119 | @objective(model, Min, sum(moment.*wc)) 120 | optimize!(model) 121 | objv = objective_value(model) 122 | @test objv ≈ 3.437648 atol = 1e-6 123 | 124 | # Sum-Of-Ratio Optimization 125 | @polyvar x y z 126 | p = [x^2+y^2-y*z, y^2+x^2*z, z^2-x+y] 127 | q = [1+2x^2+y^2+z^2, 1+x^2+2y^2+z^2, 1+x^2+y^2+2z^2] 128 | g = [1-x^2-y^2-z^2] 129 | d = 4 130 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 131 | set_optimizer_attribute(model, MOI.Silent(), true) 132 | h1 = add_poly!(model, [x;y;z], 2d-2, signsymmetry=get_signsymmetry([p[2]; q[2]; g], [x;y;z]))[1] 133 | h2 = add_poly!(model, [x;y;z], 2d-2, signsymmetry=get_signsymmetry([p[3]; q[3]; g], [x;y;z]))[1] 134 | c = @variable(model) 135 | add_psatz!(model, p[1]+(h1+h2-c)*q[1], [x;y;z], g, [], d, QUIET=true, TS="block", SO=1, GroebnerBasis=false) 136 | add_psatz!(model, p[2]-h1*q[2], [x;y;z], g, [], d, QUIET=true, TS="block", SO=1, GroebnerBasis=false) 137 | add_psatz!(model, p[3]-h2*q[3], [x;y;z], g, [], d, QUIET=true, TS="block", SO=1, GroebnerBasis=false) 138 | @objective(model, Max, c) 139 | optimize!(model) 140 | objv = objective_value(model) 141 | @test objv ≈ -0.346510 atol = 1e-6 142 | 143 | # Polynomial Matrix Optimization 144 | @polyvar x[1:2] 145 | Q = [1/sqrt(2) -1/sqrt(3) 1/sqrt(6); 0 1/sqrt(3) 2/sqrt(6); 1/sqrt(2) 1/sqrt(3) -1/sqrt(6)] 146 | F = Q*[-x[1]^2-x[2]^2 0 0; 0 -1/4*(x[1]+1)^2-1/4*(x[2]-1)^2 0; 0 0 -1/4*(x[1]-1)^2-1/4*(x[2]+1)^2]*Q' 147 | G = [1-4x[1]*x[2] x[1]; x[1] 4-x[1]^2-x[2]^2] 148 | opt,data = tssos_first(F, [G], x, 2, TS="block", QUIET=true, Gram=true, Moment=true) 149 | @test opt ≈ -4 atol = 1e-6 150 | opt,data = tssos_higher!(data, QUIET=true, Gram=true) 151 | @test opt ≈ -4 atol = 1e-6 152 | 153 | @polyvar x[1:3] 154 | f = x[1]^2 + x[1]*x[2] + x[2]^2 + x[2]*x[3] + x[3]^2 155 | d = 2 # set the relaxation order 156 | @polyvar y[1:2] 157 | h = [x[1]^2 + x[2]^2 + y[1]^2-1, x[2]^2 + x[3]^2 + y[2]^2 - 1] 158 | model = Model(optimizer_with_attributes(Mosek.Optimizer)) 159 | set_optimizer_attribute(model, MOI.Silent(), true) 160 | @variable(model, lower) 161 | nonneg = f - lower*sum(x.^2) 162 | add_psatz!(model, nonneg, [x; y], [], h, d, TS="block", GroebnerBasis=true) 163 | @objective(model, Max, lower) 164 | optimize!(model) 165 | opt = objective_value(model) 166 | @test opt ≈ 0.29289321 atol = 1e-6 167 | 168 | # Exploiting Symmetry 169 | @polyvar x[1:3] 170 | f = sum(x) + sum(x.^4) 171 | pop = [f, 1 - sum(x.^2)] 172 | G = PermGroup([perm"(1,2,3)", perm"(1,2)"]) 173 | opt,data = tssos_symmetry(pop, x, 2, G, QUIET=true) 174 | @test opt ≈ -1.3987174 atol = 1e-6 175 | 176 | @polyvar x[1:3] 177 | f = sum(x) + sum(x.^4) 178 | pop = [f, 1 - sum(x.^2)] 179 | G = PermGroup([perm"(1,2,3)", perm"(1,2)"]) 180 | opt,data = tssos_symmetry(pop, x, 2, G, QUIET=true) 181 | @test opt ≈ -1.3987174 atol = 1e-6 182 | 183 | @polyvar x[1:3] 184 | f = sum(x) + sum(x.^4) 185 | pop = [f, 1 - sum(x.^2)] 186 | G = PermGroup([perm"(1,2,3)", perm"(1,2)"]) 187 | opt,data = tssos_symmetry(pop, x, 2, G, numeq=1, QUIET=true) 188 | @test opt ≈ -1.3987174 atol = 1e-6 189 | 190 | end 191 | --------------------------------------------------------------------------------