Repository: sagemath/sage

Issue:
Implement check for Lorentzian polynomials
<div id="comment:0"></div>

Implement a check for Lorentzian polynomials, as defined in "Lorentzian Polynomials", https://arxiv.org/abs/1902.03719.

Part of the "Geometry and Combinatorics of Matroids" project at Sage Days 99 at the Institute for Mathematics and its Applications, at University of Minnesota Twin Cities.

CC:  @tscrim @kwankyu @slel @dcoudert

Component: **commutative algebra**

Keywords: **IMA Coding Sprints, days99, polynomials, discrete convex analysis**

Author: **Galen Dorpalen-Barry, Bryan Gillespie, Jacob P. Matherne, Thomas McConville**

Branch/Commit: **[public/28252](https://github.com/sagemath/sagetrac-mirror/tree/public/28252) @ [`5fa1a05`](https://github.com/sagemath/sagetrac-mirror/commit/5fa1a0534c9b4a51cdb6a9ad65c29c06a9e52798)**

Reviewer: **Aritra Bhattacharya, Samuel Lelièvre, Julian Rüth**

_Issue created by migration from https://trac.sagemath.org/ticket/28252_




Discussion:
Author: **Galen Dorpalen-Barry, Bryan Gillespie, Jacob P. Matherne, Thomas McConville**

Resolving patch:
diff --git a/src/sage/quadratic_forms/quadratic_form.py b/src/sage/quadratic_forms/quadratic_form.py
--- a/src/sage/quadratic_forms/quadratic_form.py
+++ b/src/sage/quadratic_forms/quadratic_form.py
@@ -30,13 +30,15 @@
 from sage.arith.all import GCD, LCM
 from sage.rings.all import Ideal, QQ
 from sage.rings.ring import is_Ring, PrincipalIdealDomain
-from sage.structure.sage_object import SageObject
 from sage.structure.element import is_Vector
 from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
+from sage.rings.polynomial.polynomial_element import is_Polynomial
+from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial
 from sage.modules.free_module_element import vector
 from sage.quadratic_forms.genera.genus import genera
 from sage.quadratic_forms.quadratic_form__evaluate import QFEvaluateVector, QFEvaluateMatrix
-
+from sage.structure.sage_object import SageObject
+from sage.combinat.integer_lists.invlex import IntegerListsLex
 
 def QuadraticForm__constructor(R, n=None, entries=None):
     """
@@ -206,6 +208,10 @@ class QuadraticForm(SageObject):
          in `R` (given lexicographically, or equivalently, by rows of the
          matrix)
 
+    #. ``QuadraticForm(p)``, where
+
+      - `p` -- a homogeneous polynomial of degree `2`
+
     #. ``QuadraticForm(R, n)``, where
 
        - `R` -- a ring
@@ -284,6 +290,16 @@ class QuadraticForm(SageObject):
         [ 1 5 ]
         [ * 4 ]
 
+    ::
+
+        sage: P.<x,y,z> = QQ[]
+        sage: p = x^2 + 2*x*y + x*z/2 + y^2 + y*z/3
+        sage: QuadraticForm(p)
+        Quadratic form in 3 variables over Rational Field with coefficients:
+        [ 1 2 1/2 ]
+        [ * 1 1/3 ]
+        [ * * 0 ]
+
     ::
 
         sage: QuadraticForm(ZZ, m + m.transpose())
@@ -499,6 +515,25 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_
             sage: s.dim()
             4
 
+            sage: P.<x,y,z> = QQ[]
+            sage: p = x^2 + y^2 + 2*x*z
+            sage: QuadraticForm(p)
+            Quadratic form in 3 variables over Rational Field with coefficients:
+            [ 1 0 2 ]
+            [ * 1 0 ]
+            [ * * 0 ]
+            sage: z = P.zero()
+            sage: QuadraticForm(z)
+            Quadratic form in 3 variables over Rational Field with coefficients:
+            [ 0 0 0 ]
+            [ * 0 0 ]
+            [ * * 0 ]
+            sage: q = x^2 + 3*y - z
+            sage: QuadraticForm(q)
+            Traceback (most recent call last):
+            ...
+            ValueError: polynomial is neither zero nor homogeneous of degree 2
+
         TESTS::
 
             sage: s == loads(dumps(s))
@@ -510,6 +545,10 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_
 
             sage: x = polygen(ZZ, 'x')
             sage: QuadraticForm(x**2)
+            Quadratic form in 1 variables over Integer Ring with coefficients:
+            [ 1 ]
+
+            sage: QuadraticForm(1)
             Traceback (most recent call last):
             ....
             TypeError: wrong input for QuadraticForm
@@ -527,20 +566,39 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_
                 M_ring = R
                 matrix_init_flag = True
 
-        elif not is_Matrix(R):
-            # first argument, if not a ring, must be a matrix
-            raise TypeError('wrong input for QuadraticForm')
-        else:
-            # Deal with:  QuadraticForm(matrix)
+        elif is_Matrix(R):
+            M = R
+
             # Test if R is symmetric and has even diagonal
-            if not self._is_even_symmetric_matrix_(R):
+            if not self._is_even_symmetric_matrix_(M):
                 raise TypeError("the matrix is not a symmetric with even diagonal")
 
-            # Rename the matrix and ring
-            M = R
-            M_ring = R.base_ring()
+            M_ring = M.base_ring()
             matrix_init_flag = True
 
+        elif is_Polynomial(R) or is_MPolynomial(R):
+            p = R
+            
+            if not p.is_zero() and not (p.is_homogeneous() and p.degree() == 2):
+                raise ValueError("polynomial is neither zero nor homogeneous of degree 2")
+
+            P = p.parent()
+            R, n = P.base_ring(), P.ngens()
+
+            # Extract quadratic form coefficients
+            entries = []
+            if n == 0:
+                exponents = []
+            elif n == 1:
+                exponents = [2]
+            else:
+                exponents = IntegerListsLex(2, length=n)
+            for alpha in exponents:
+                entries.append(p[alpha])
+
+        else:
+            raise TypeError('wrong input for QuadraticForm')
+
         # Perform the quadratic form initialization
         if matrix_init_flag:
             self.__n = ZZ(M.nrows())


Test patch: