{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# Sign symmetry"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "**Adapted from**: Example 4 of [L09]\n",
    "\n",
    "[L09] Lofberg, Johan.\n",
    "*Pre-and post-processing sum-of-squares programs in practice*.\n",
    "IEEE transactions on automatic control 54, no. 5 (2009): 1007-1011."
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "(DynamicPolynomials.Variable{DynamicPolynomials.Commutative{DynamicPolynomials.CreationOrder}, MultivariatePolynomials.Graded{MultivariatePolynomials.LexOrder}}[x₁, x₂, x₃],)"
     },
     "metadata": {},
     "execution_count": 1
    }
   ],
   "cell_type": "code",
   "source": [
    "using DynamicPolynomials\n",
    "@polyvar x[1:3]"
   ],
   "metadata": {},
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "source": [
    "We would like to determine whether the following polynomial is a sum-of-squares."
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "1 + x₃² + x₁x₂ + x₂⁴ + x₁⁴",
      "text/latex": "$$ 1 + x_{3}^{2} + x_{1}x_{2} + x_{2}^{4} + x_{1}^{4} $$"
     },
     "metadata": {},
     "execution_count": 2
    }
   ],
   "cell_type": "code",
   "source": [
    "poly = 1 + x[1]^4 + x[1] * x[2] + x[2]^4 + x[3]^2"
   ],
   "metadata": {},
   "execution_count": 2
  },
  {
   "cell_type": "markdown",
   "source": [
    "In order to do this, we can solve the following Sum-of-Squares program."
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Success: SDP solved\n",
      "Primal objective value: 0.0000000e+00 \n",
      "Dual objective value: 0.0000000e+00 \n",
      "Relative primal infeasibility: 5.23e-17 \n",
      "Relative dual infeasibility: 5.00e-11 \n",
      "Real Relative Gap: 0.00e+00 \n",
      "XZ Relative Gap: 1.00e-10 \n",
      "DIMACS error measures: 7.85e-17 0.00e+00 5.00e-11 0.00e+00 0.00e+00 1.00e-10\n",
      "CSDP 6.2.0\n",
      "This is a pure primal feasibility problem.\n",
      "Iter:  0 Ap: 0.00e+00 Pobj:  0.0000000e+00 Ad: 0.00e+00 Dobj:  0.0000000e+00 \n",
      "Iter:  1 Ap: 8.10e-01 Pobj:  0.0000000e+00 Ad: 1.00e+00 Dobj:  4.0878274e+01 \n",
      "Iter:  2 Ap: 1.00e+00 Pobj:  0.0000000e+00 Ad: 1.00e+00 Dobj:  2.7225538e+01 \n",
      "* Solver : CSDP\n",
      "\n",
      "* Status\n",
      "  Result count       : 1\n",
      "  Termination status : OPTIMAL\n",
      "  Message from the solver:\n",
      "  \"Problem solved to optimality.\"\n",
      "\n",
      "* Candidate solution (result #1)\n",
      "  Primal status      : FEASIBLE_POINT\n",
      "  Dual status        : FEASIBLE_POINT\n",
      "  Objective value    : 0.00000e+00\n",
      "  Dual objective value : 0.00000e+00\n",
      "\n",
      "* Work counters\n",
      "  Solve time (sec)   : 4.61102e-04\n",
      "\n"
     ]
    },
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "7-element DynamicPolynomials.MonomialVector{DynamicPolynomials.Commutative{DynamicPolynomials.CreationOrder}, MultivariatePolynomials.Graded{MultivariatePolynomials.LexOrder}}:\n 1\n x₃\n x₂\n x₁\n x₂²\n x₁x₂\n x₁²"
     },
     "metadata": {},
     "execution_count": 3
    }
   ],
   "cell_type": "code",
   "source": [
    "import CSDP\n",
    "solver = CSDP.Optimizer\n",
    "using SumOfSquares\n",
    "function sos_check(sparsity)\n",
    "    model = Model(solver)\n",
    "    con_ref = @constraint(model, poly in SOSCone(), sparsity = sparsity)\n",
    "    optimize!(model)\n",
    "    println(solution_summary(model))\n",
    "    return gram_matrix(con_ref)\n",
    "end\n",
    "\n",
    "g = sos_check(Sparsity.NoPattern())\n",
    "g.basis.monomials"
   ],
   "metadata": {},
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "source": [
    "As detailed in the Example 4 of [L09], we can exploit the *sign symmetry* of\n",
    "the polynomial to decompose the large positive semidefinite matrix into smaller ones."
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Success: SDP solved\n",
      "Primal objective value: 0.0000000e+00 \n",
      "Dual objective value: 0.0000000e+00 \n",
      "Relative primal infeasibility: 7.46e-17 \n",
      "Relative dual infeasibility: 5.00e-11 \n",
      "Real Relative Gap: 0.00e+00 \n",
      "XZ Relative Gap: 1.21e-10 \n",
      "DIMACS error measures: 1.21e-16 0.00e+00 5.00e-11 0.00e+00 0.00e+00 1.21e-10\n",
      "CSDP 6.2.0\n",
      "This is a pure primal feasibility problem.\n",
      "Iter:  0 Ap: 0.00e+00 Pobj:  0.0000000e+00 Ad: 0.00e+00 Dobj:  0.0000000e+00 \n",
      "Iter:  1 Ap: 7.15e-01 Pobj:  0.0000000e+00 Ad: 1.00e+00 Dobj:  4.7634216e+01 \n",
      "Iter:  2 Ap: 1.00e+00 Pobj:  0.0000000e+00 Ad: 1.00e+00 Dobj:  3.5035802e+01 \n",
      "* Solver : CSDP\n",
      "\n",
      "* Status\n",
      "  Result count       : 1\n",
      "  Termination status : OPTIMAL\n",
      "  Message from the solver:\n",
      "  \"Problem solved to optimality.\"\n",
      "\n",
      "* Candidate solution (result #1)\n",
      "  Primal status      : FEASIBLE_POINT\n",
      "  Dual status        : FEASIBLE_POINT\n",
      "  Objective value    : 0.00000e+00\n",
      "  Dual objective value : 0.00000e+00\n",
      "\n",
      "* Work counters\n",
      "  Solve time (sec)   : 6.58989e-04\n",
      "\n"
     ]
    },
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "3-element Vector{DynamicPolynomials.MonomialVector{DynamicPolynomials.Commutative{DynamicPolynomials.CreationOrder}, MultivariatePolynomials.Graded{MultivariatePolynomials.LexOrder}}}:\n [x₂, x₁]\n [x₃]\n [1, x₂², x₁x₂, x₁²]"
     },
     "metadata": {},
     "execution_count": 4
    }
   ],
   "cell_type": "code",
   "source": [
    "g = sos_check(Sparsity.SignSymmetry())\n",
    "monos = [sub.basis.monomials for sub in g.blocks]"
   ],
   "metadata": {},
   "execution_count": 4
  },
  {
   "cell_type": "markdown",
   "source": [
    "---\n",
    "\n",
    "*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*"
   ],
   "metadata": {}
  }
 ],
 "nbformat_minor": 3,
 "metadata": {
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "1.11.3"
  },
  "kernelspec": {
   "name": "julia-1.11",
   "display_name": "Julia 1.11.3",
   "language": "julia"
  }
 },
 "nbformat": 4
}