]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_utils.py
eja: add a WIP gram-schmidt for EJA elements.
[sage.d.git] / mjo / eja / eja_utils.py
index b6b0a0327c19842ce654023b00bf6e0b9af539a1..8f2d8f32b0dd2e2cf6e693166688d6be1f3ea999 100644 (file)
@@ -1,4 +1,95 @@
 from sage.modules.free_module_element import vector
+from sage.rings.number_field.number_field import NumberField
+from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
+from sage.rings.real_lazy import RLF
 
 def _mat2vec(m):
         return vector(m.base_ring(), m.list())
+
+def gram_schmidt(v):
+    """
+    Perform Gram-Schmidt on the list ``v`` which are assumed to be
+    vectors over the same base ring. Returns a list of orthonormalized
+    vectors over the smallest extention ring containing the necessary
+    roots.
+
+    SETUP::
+
+        sage: from mjo.eja.eja_utils import gram_schmidt
+
+    EXAMPLES::
+
+        sage: v1 = vector(QQ,(1,2,3))
+        sage: v2 = vector(QQ,(1,-1,6))
+        sage: v3 = vector(QQ,(2,1,-1))
+        sage: v = [v1,v2,v3]
+        sage: u = gram_schmidt(v)
+        sage: [ u_i.inner_product(u_i).sqrt() == 1 for u_i in u ]
+        True
+        sage: u[0].inner_product(u[1]) == 0
+        True
+        sage: u[0].inner_product(u[2]) == 0
+        True
+        sage: u[1].inner_product(u[2]) == 0
+        True
+
+    TESTS:
+
+    Ensure that zero vectors don't get in the way::
+
+        sage: v1 = vector(QQ,(1,2,3))
+        sage: v2 = vector(QQ,(1,-1,6))
+        sage: v3 = vector(QQ,(0,0,0))
+        sage: v = [v1,v2,v3]
+        sage: len(gram_schmidt(v)) == 2
+        True
+
+    """
+    def proj(x,y):
+        return (y.inner_product(x)/x.inner_product(x))*x
+
+    v = list(v) # make a copy, don't clobber the input
+
+    # Drop all zero vectors before we start.
+    v = [ v_i for v_i in v if not v_i.is_zero() ]
+
+    if len(v) == 0:
+        # cool
+        return v
+
+    R = v[0].base_ring()
+
+    # First orthogonalize...
+    for i in xrange(1,len(v)):
+        # Earlier vectors can be made into zero so we have to ignore them.
+        v[i] -= sum( proj(v[j],v[i]) for j in range(i) if not v[j].is_zero() )
+
+    # And now drop all zero vectors again if they were "orthogonalized out."
+    v = [ v_i for v_i in v if not v_i.is_zero() ]
+
+    # Now pretend to normalize, building a new ring R that contains
+    # all of the necessary square roots.
+    norms_squared = [0]*len(v)
+
+    for i in xrange(len(v)):
+        norms_squared[i] = v[i].inner_product(v[i])
+        ns = [norms_squared[i].numerator(), norms_squared[i].denominator()]
+
+        # Do the numerator and denominator separately so that we
+        # adjoin e.g. sqrt(2) and sqrt(3) instead of sqrt(2/3).
+        for j in xrange(len(ns)):
+            PR = PolynomialRing(R, 'z')
+            z = PR.gen()
+            p = z**2 - ns[j]
+            if p.is_irreducible():
+                R = NumberField(p,
+                                'sqrt' + str(ns[j]),
+                                embedding=RLF(ns[j]).sqrt())
+
+    # When we're done, we have to change every element's ring to the
+    # extension that we wound up with, and then normalize it (which
+    # should work, since "R" contains its norm now).
+    for i in xrange(len(v)):
+        v[i] = v[i].change_ring(R) / R(norms_squared[i]).sqrt()
+
+    return v