def compatibility_degree(self, alpha, beta):
        if self.is_finite():
            tube_contribution = -1
        elif self.is_affine():
            gck = self.gamma().associated_coroot()
            if any([gck.scalar(alpha) != 0, gck.scalar(beta) != 0]):
                tube_contribution = -1
            else:
                sup_a = self._tube_support(alpha)
                sup_b = self._tube_support(beta)
                if all([x in sup_b for x in sup_a]) or all([x in sup_a for x in sup_b]):
                    tube_contribution = -1
                else:
                    nbh_a = self._tube_nbh(alpha)
                    tube_contribution = len([ x for x in nbh_a if x in sup_b ])
        else:
            raise ValueError("compatibility degree is implemented only for finite and affine types")
        
        initial = self.initial_cluster()
        if alpha in initial:
            return max(beta[initial.index(alpha)],0)

        alphacheck = alpha.associated_coroot()

        if beta in initial:
            return max(alphacheck[initial.index(beta)],0)

        Ap = -matrix(self.rk, map(lambda x: max(x,0), self.b_matrix().list() ) )
        Am =  matrix(self.rk, map(lambda x: min(x,0), self.b_matrix().list() ) )

        a = vector(alphacheck)
        b = vector(beta)

        return max( -a*b-a*Am*b, -a*b-a*Ap*b, tube_contribution )
Exemplo n.º 2
0
def semi_norm_v(M, v,  p=2, verbose=False):
    r"""
    Return the semi norm on the hyperplane orthogonal to v.

    EXAMPLES::

        sage: from slabbe.matrix_cocycle import semi_norm_v
        sage: A1 = matrix(3, [1,-1,-1, 0,1,0, 0,0,1]).inverse()
        sage: semi_norm_v(A1, vector( (1,1,1)))      # tolerance 0.0001
        0.9999999999890247
        sage: semi_norm_v(A1, vector( (1,1,1)), p=1)   # tolerance 0.0001
        0.9999394820959548
        sage: semi_norm_v(A1, vector( (1,1,1)), p=oo)   # tolerance 0.0001
        1.0

    """
    from sage.modules.free_module_element import vector
    from sage.numerical.optimize import minimize_constrained
    def func(z):
        vz = vector(z)
        return - (M*vz).norm(p) / vz.norm(p)
    cons = [lambda z: v * vector(z),
            lambda z: - v * vector(z)]
    x0 = range(len(v))
    x0[0] = v[1]
    x0[1] = -v[0]
    rep = minimize_constrained(func, cons, x0)
    if verbose:
        print(rep, rep.norm(), rep*v)
    return -func(rep)
    def relative_field_representation(self, b):
        r"""
        Returns a vector representation of the field element ``b`` in the basis
        of the absolute field over the relative field.

        INPUT:

        - ``b`` -- an element of the absolute field

        EXAMPLES::

            sage: from sage.coding.relative_finite_field_extension import *
            sage: Fqm.<aa> = GF(16)
            sage: Fq.<a> = GF(4)
            sage: FE = RelativeFiniteFieldExtension(Fqm, Fq)
            sage: b = aa^3 + aa^2 + aa + 1
            sage: FE.relative_field_representation(b)
            (1, a + 1)
        """
        if not b in self.absolute_field():
            raise ValueError("The input has to be an element of the absolute field")
        s = self.relative_field_degree()
        if s == 1:
            return vector(b)
        else:
            Fq = self.relative_field()
            vect = self._flattened_relative_field_representation(b)
            sm = self.absolute_field_degree()
            list_elts = []
            for i in range(0, sm, s):
                list_elts.append(Fq(vect[i:i+s]))
            return vector(Fq, list_elts)
Exemplo n.º 4
0
    def __init__(self, v, omega, mu=0, prec=None):
        r"""
        EXAMPLES::

            sage: from slabbe import DiscreteHyperplane
            sage: p = DiscreteHyperplane([1,pi,7], 1+pi+7, mu=0)
            sage: p
            Set of points x in ZZ^3 satisfying: 0 <= (1, pi, 7) . x + 0 < pi + 8

        ::

            sage: p = DiscreteHyperplane([1,pi,7], 1+pi+7, mu=20)
            sage: vector((0,0,0)) in p
            False
            sage: p = DiscreteHyperplane([1,pi,7], 1+pi+7, mu=0)
            sage: vector((0,0,0)) in p
            True
        """
        if prec is None:
            self._v = vector(v)
            self._omega = omega
            self._mu = mu
        else:
            RF = RealField(prec=prec)
            self._v = vector(RF, v)
            self._omega = RF(omega)
            self._mu = RF(mu)
        def contain(p):
            #print("est-ce proche : ", self._v.dot_product(p) + self._mu)
            return  0 <= self._v.dot_product(p) + self._mu < self._omega
        DiscreteSubset.__init__(self, dimension=len(self._v), predicate=contain)
Exemplo n.º 5
0
    def parallelotope(self, generators):
        r"""
        Return the parallelotope spanned by the generators.

        INPUT:

        - ``generators`` -- an iterable of anything convertible to vector
          (for example, a list of vectors) such that the vectors all
          have the same dimension.

        OUTPUT:

        The parallelotope. This is the multi-dimensional
        generalization of a parallelogram (2 generators) and a
        parallelepiped (3 generators).

        EXAMPLES::

            sage: polytopes.parallelotope([ (1,0), (0,1) ])
            A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices
            sage: polytopes.parallelotope([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]])
            A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 16 vertices
        """
        try:
            generators = [ vector(QQ,v) for v in generators ]
            base_ring = QQ
        except TypeError:
            generators = [ vector(RDF,v) for v in generators ]
            base_ring = RDF

        from sage.combinat.combination import Combinations
        par =  [ 0*generators[0] ]
        par += [ sum(c) for c in Combinations(generators) if c!=[] ]
        return Polyhedron(vertices=par, base_ring=base_ring)
Exemplo n.º 6
0
    def first_coordinate_plane(self):
        """
        Restrict to the first coordinate plane.

        OUTPUT:

        A new double description pair with the constraint `x_0 = 0`
        added.

        EXAMPLES::

            sage: A = matrix([(1, 1), (-1, 1)])
            sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
            sage: DD, _ = StandardAlgorithm(A).initial_pair()
            sage: DD
            Double description pair (A, R) defined by
            A = [ 1  1],   R = [ 1/2 -1/2]
                [-1  1]        [ 1/2  1/2]
            sage: DD.first_coordinate_plane()
            Double description pair (A, R) defined by
                [ 1  1]
            A = [-1  1],   R = [  0]
                [-1  0]        [1/2]
                [ 1  0]
        """
        R = self.problem.base_ring()
        d = self.problem.dim()
        a_neg = vector(R, [-self.one] + [self.zero] * (d - 1))
        a_pos = vector(R, [+self.one] + [self.zero] * (d - 1))
        new = self._make_new(self.A, self.R)
        new.add_inequality(a_neg)
        new.add_inequality(a_pos)
        return new
Exemplo n.º 7
0
    def kernel_vector(self, way='LLL', verbose=False):
        r"""
        todo: clean this

        EXAMPLES::

            sage: from slabbe import ChristoffelGraph
            sage: C = ChristoffelGraph((2,5,7))
            sage: C.kernel_vector()
            [(-1, -1, 1), (3, -4, 0)]

        """
        from sage.arith.misc import gcd
        if way == 'vect_gcd':
            a,b,c = self._v
            gcd_ac = gcd(a,c)
            gcd_bc = gcd(b,c)
            U = ua,ub,uc = vector((c,0,-a)) / gcd(a,c)
            V = va,vb,vc = vector((0,c,-b)) / gcd(b,c)
            rows = U,V
        elif way == 'echelon':
            a,b,c = self._v
            m = matrix(ZZ, 4, [1,1,1,c,0,-a,0,c,-b,b,-a,0])
            me = m.echelon_form()
            if verbose:
                print(me)
            rows = me[1],me[2]
        elif way == 'LLL':
            dim = self.dimension()
            if dim == 3:
                a,b,c = self._v
                M = matrix(ZZ, 4, [1,1,1,c,0,-a,0,c,-b,b,-a,0])
            elif dim == 4:
                a,b,c,d = self._v
                M = matrix(ZZ, 7, (1,1,1,1,b,-a,0,0,c,0,-a,0,0,c,-b,0,d,0,0,-a,0,d,0,-b,0,0,d,-c))
            else:
                raise ValueError("dimension (=%s) must be 3 or 4" % dim)
            rows = M.LLL().rows()
            VS = rows[0].parent()
            zero = VS(0)
            un = VS((1,)*dim)
            assert zero in rows, "(0,0,0) not in LLL result"
            assert un in rows, "(1,1,1) not in LLL result"
            while zero in rows: rows.remove(zero)
            while un in rows: rows.remove(un)
        elif way == 'vect':
            a,b,c = self._v
            U = ua,ub,uc = vector((c,0,-a))
            V = va,vb,vc = vector((0,c,-b))
            rows = U,V
        else:
            raise ValueError("unknown way")
        R = matrix(rows)
        if sum(map(abs, R.minors(dim-1))) != sum(map(abs,self._v)):
            print(R)
            print(R.minors(dim-1))
            print(sum(map(abs, R.minors(dim))))
            print(sum(map(abs,self._v)))
            raise Exception("The result (=%s) is false " % rows)
        return rows
def plot_fan_stereographically(rays, walls, northsign=1, north=vector((-1,-1,-1)), right=vector((1,0,0)), colors=None, thickness=None):
    from sage.plot.graphics import Graphics
    from sage.plot.point import point
    from sage.misc.flatten import flatten
    from sage.plot.line import line
    from sage.misc.functional import norm
    
    if colors == None:
        colors = dict([('walls','black'),('rays','red')])

    if thickness == None:
        thickness = dict([('walls',0.5),('rays',20)])


    G = Graphics()
    
    for (u,v) in walls:
        G += _stereo_arc(vector(u),vector(v),vector(u+v),north=northsign*north,right=right,color=colors['walls'],thickness=thickness['walls'],zorder=len(G))
   
    for v in rays: 
        G += point(_stereo_coordinates(vector(v),north=northsign*north,right=right),color=colors['rays'],zorder=len(G),size=thickness['rays'])
    
    G.set_aspect_ratio(1)
    G._show_axes = False
    return G
Exemplo n.º 9
0
    def decode_to_code(self, y):
        r"""
        Corrects the errors in ``word`` and returns a codeword.

        EXAMPLES::

            sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'aa').list()[:13], 5)
            sage: Cs = codes.SubfieldSubcode(C, GF(4, 'a'))
            sage: D = codes.decoders.SubfieldSubcodeOriginalCodeDecoder(Cs)
            sage: Chan = channels.StaticErrorRateChannel(Cs.ambient_space(), D.decoding_radius())
            sage: c = Cs.random_element()
            sage: y = Chan(c)
            sage: c == D.decode_to_code(y)
            True
        """
        C = self.code()
        D = self.original_decoder()
        FE = C.embedding()
        phi = FE.embedding()
        y_or = vector([phi(i) for i in y])
        c_or = D.decode_to_code(y_or)
        if 'list-decoder' in self.decoder_type():
            result = []
            for c in c_or:
                if all(FE.is_in_relative_field(x) for x in c):
                    result.append(vector(map(FE.cast_into_relative_field, c)))
            return result
        else:
            if all(FE.is_in_relative_field(x) for x in c_or):
                return vector([FE.cast_into_relative_field(i, check=False)
                               for i in c_or])
            else:
                raise DecodingError("Original decoder does not output a "
                "subfield codeword. You may have exceeded the decoding radius.")
Exemplo n.º 10
0
    def __init__(self, v, start=(0,0,0)):
        r"""
        EXAMPLES::

            sage: from slabbe import BilliardCube
            sage: b = BilliardCube((1,pi,sqrt(2)))
            sage: b
            Cubic billiard of direction (1, pi, sqrt(2))

        TESTS::

            sage: vector((0,0,0)) in b
            True
            sage: vector((0,0,1)) in b
            False
            sage: vector((0,1,0)) in b
            True
            sage: vector((1,0,0)) in b
            False
            sage: vector((0,-1,0)) in b
            True

        """
        a,b,c = self._v = vector(v)
        sx,sy,sz = self._start = vector(start)
        px = DiscretePlane([0,c,-b], b+c, mu=(b+c)/2 - sy*c + sz*b)
        py = DiscretePlane([c,0,-a], a+c, mu=(a+c)/2 - sx*c + sz*a)
        pz = DiscretePlane([b,-a,0], a+b, mu=(a+b)/2 - sx*b + sy*a)
        Intersection.__init__(self, (px,py,pz))
Exemplo n.º 11
0
def platonic_dodecahedron():
    r"""Produce a triple consisting of a polyhedral version of the platonic dodecahedron,
    the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface
    to the polyhedron.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import platonic_dodecahedron
    sage: polyhedron,surface,surface_to_polyhedron = platonic_dodecahedron()
    sage: TestSuite(surface).run()
    r"""
    vertices=[]
    phi=AA(1+sqrt(5))/2
    F=NumberField(phi.minpoly(),"phi",embedding=phi)
    phi=F.gen()
    for x in xrange(-1,3,2):
        for y in xrange(-1,3,2):
            for z in xrange(-1,3,2):
                vertices.append(vector(F,(x,y,z)))
    for x in xrange(-1,3,2):
        for y in xrange(-1,3,2):
            vertices.append(vector(F,(0,x*phi,y/phi)))
            vertices.append(vector(F,(y/phi,0,x*phi)))
            vertices.append(vector(F,(x*phi,y/phi,0)))
    scale=AA(2/sqrt(1+(phi-1)**2+(1/phi-1)**2))
    p=Polyhedron(vertices=vertices)
    s,m = polyhedron_to_cone_surface(p,scaling_factor=scale)
    return p,s,m
Exemplo n.º 12
0
    def __init__(self, projection_direction, height = 1.1):
        """
        Initializes the projection.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.plot import ProjectionFuncSchlegel
            sage: proj = ProjectionFuncSchlegel([2,2,2])
            sage: proj.__init__([2,2,2])
            sage: proj(vector([1.1,1.1,1.11]))[0]
            0.0302...
            sage: TestSuite(proj).run(skip='_test_pickling')
        """
        self.projection_dir = vector(RDF, projection_direction)
        if norm(self.projection_dir).is_zero():
            raise ValueError, "projection direction must be a non-zero vector."
        self.dim = self.projection_dir.degree()
        spcenter = height * self.projection_dir/norm(self.projection_dir)
        self.height = height
        v = vector(RDF, [0.0]*(self.dim-1) + [self.height]) - spcenter
        polediff = matrix(RDF,v).transpose()
        denom = (polediff.transpose()*polediff)[0][0]
        if denom.is_zero():
            self.house = identity_matrix(RDF,self.dim)
        else:
            self.house = identity_matrix(RDF,self.dim) \
            - 2*polediff*polediff.transpose()/denom #Householder reflector
Exemplo n.º 13
0
    def __init__(self, projection_point):
        """
        Create a stereographic projection function.

        INPUT:

        - ``projection_point`` -- a list of coordinates in the
          appropriate dimension, which is the point projected from.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.plot import ProjectionFuncStereographic
            sage: proj = ProjectionFuncStereographic([1.0,1.0])
            sage: proj.__init__([1.0,1.0])
            sage: proj.house
            [-0.7071067811...  0.7071067811...]
            [ 0.7071067811...  0.7071067811...]
            sage: TestSuite(proj).run(skip='_test_pickling')
        """
        self.projection_point = vector(projection_point)
        self.dim = self.projection_point.degree()

        pproj = vector(RDF,self.projection_point)
        self.psize = norm(pproj)
        if (self.psize).is_zero():
            raise ValueError, "projection direction must be a non-zero vector."
        v = vector(RDF, [0.0]*(self.dim-1) + [self.psize]) - pproj
        polediff = matrix(RDF,v).transpose()
        denom = RDF((polediff.transpose()*polediff)[0][0])
        if denom.is_zero():
            self.house = identity_matrix(RDF,self.dim)
        else:
            self.house = identity_matrix(RDF,self.dim) \
            - 2*polediff*polediff.transpose()/denom   # Householder reflector
def _arc(p,q,s,**kwds):
    #rewrite this to use polar_plot and get points to do filled triangles
    from sage.misc.functional import det
    from sage.plot.line import line
    from sage.misc.functional import norm
    from sage.symbolic.all import pi
    from sage.plot.arc import arc
     
    p,q,s = map( lambda x: vector(x), [p,q,s])
     
    # to avoid running into division by 0 we set to be colinear vectors that are
    # almost colinear
    if abs(det(matrix([p-s,q-s])))<0.01:
        return line((p,q),**kwds)
     
    (cx,cy)=var('cx','cy')
    equations=[
            2*cx*(s[0]-p[0])+2*cy*(s[1]-p[1]) == s[0]**2+s[1]**2-p[0]**2-p[1]**2,
            2*cx*(s[0]-q[0])+2*cy*(s[1]-q[1]) == s[0]**2+s[1]**2-q[0]**2-q[1]**2
            ]
    c = vector( [solve( equations, (cx,cy), solution_dict=True )[0][i] for i in [cx,cy]] )
     
    r = norm(p-c)
     
    a_p,a_q,a_s = map( _to_angle, [p-c,q-c,s-c])
    angles = [a_p,a_q,a_s]
    angles.sort()
     
    if a_s == angles[0]:
        return arc( c, r, angle=angles[2], sector=(0,2*pi-angles[2]+angles[1]), **kwds)
    if a_s == angles[1]:
        return arc( c, r, angle=angles[0], sector=(0,angles[2]-angles[0]), **kwds)
    if a_s == angles[2]:
        return arc( c, r, angle=angles[1], sector=(0,2*pi-angles[1]+angles[0]), **kwds)
Exemplo n.º 15
0
 def space(self):
     r'''
     Calculates the homology space as a Z-module.
     '''
     verb = get_verbose()
     set_verbose(0)
     V = self.coefficient_module()
     R = V.base_ring()
     Vdim = V.dimension()
     G = self.group()
     gens = G.gens()
     ambient = R**(Vdim * len(gens))
     if self.trivial_action():
         cycles = ambient
     else:
         # Now find the subspace of cycles
         A = Matrix(R, Vdim, 0)
         for g in gens:
             for v in V.gens():
                 A = A.augment(matrix(R,Vdim,1,list(vector(g**-1 * v - v))))
         K = A.right_kernel_matrix()
         cycles = ambient.submodule([ambient(list(o)) for o in K.rows()])
     boundaries = []
     for r in G.get_relation_words():
         grad = self.twisted_fox_gradient(G(r).word_rep)
         for v in V.gens():
             boundaries.append(cycles(ambient(sum([list(a * vector(v)) for a in grad],[]))))
     boundaries = cycles.submodule(boundaries)
     ans = cycles.quotient(boundaries)
     set_verbose(verb)
     return ans
    def plot_cluster_fan_stereographically(self, northsign=1, north=None, right=None, colors=None):
        from sage.plot.graphics import Graphics
        from sage.plot.point import point
        from sage.misc.flatten import flatten
        from sage.plot.line import line
        from sage.misc.functional import norm

        if self.rk !=3:
            raise ValueError("Can only stereographically project fans in 3d.")
        if not self.is_finite() and self._depth == infinity:
            raise ValueError("For infinite algebras you must specify the depth.")

        if north == None:
            if self.is_affine():
                north = vector(self.delta())
            else:
                north = vector( (-1,-1,-1) )
        if right == None:
            if self.is_affine():
                right = vector(self.gamma())
            else:
                right = vector( (1,0,0) )
        if colors == None:
            colors = dict([(0,'red'),(1,'green'),(2,'blue'),(3,'cyan'),(4,'yellow')])
        G = Graphics()

        roots = list(self.g_vectors())
        compatible = []
        while roots:
            x = roots.pop()
            for y in roots:
                if self.compatibility_degree(x,y) == 0:
                    compatible.append((x,y))
        for (u,v) in compatible:
            G += _stereo_arc(vector(u),vector(v),vector(u+v),north=northsign*north,right=right,thickness=0.5,color='black')

        for i in range(3):
            orbit = self.ith_orbit(i)
            for j in orbit:
                G += point(_stereo_coordinates(vector(orbit[j]),north=northsign*north,right=right),color=colors[i],zorder=len(G))

        if self.is_affine():
            tube_vectors = map(vector,flatten(self.affine_tubes()))
            for v in tube_vectors:
                G += point(_stereo_coordinates(v,north=northsign*north,right=right),color=colors[3],zorder=len(G))
            if north != vector(self.delta()):
                G += _stereo_arc(tube_vectors[0],tube_vectors[1],vector(self.delta()),north=northsign*north,right=right,thickness=2,color=colors[4],zorder=0)
            else:
                # FIXME: refactor this before publishing
                tube_projections = [
                        _stereo_coordinates(v,north=northsign*north,right=right)
                        for v in tube_vectors ]
                t=min((G.get_minmax_data()['xmax'],G.get_minmax_data()['ymax']))
                G += line([tube_projections[0],tube_projections[0]+t*(_normalize(tube_projections[0]-tube_projections[1]))],thickness=2,color=colors[4],zorder=0)
                G += line([tube_projections[1],tube_projections[1]+t*(_normalize(tube_projections[1]-tube_projections[0]))],thickness=2,color=colors[4],zorder=0)
        G.set_aspect_ratio(1)
        G._show_axes = False
        return G
Exemplo n.º 17
0
    def closest_vector(self, t):
        """
        Compute the closest vector in the embedded lattice to a given vector.

        INPUT:

        - ``t`` -- the target vector to compute the closest vector to

        OUTPUT:

        The vector in the lattice closest to ``t``.

        EXAMPLES::

            sage: from sage.modules.free_module_integer import IntegerLattice
            sage: L = IntegerLattice([[1, 0], [0, 1]])
            sage: L.closest_vector((-6, 5/3))
            (-6, 2)

        ALGORITHM:

        Uses the algorithm from [Mic2010]_.

        REFERENCES:

        .. [Mic2010] D. Micciancio, P. Voulgaris. *A Deterministic Single
           Exponential Time Algorithm for Most Lattice Problems based on
           Voronoi Cell Computations*.
           Proceedings of the 42nd ACM Symposium Theory of Computation, 2010.
        """
        voronoi_cell = self.voronoi_cell()

        def projection(M, v):
            Mt = M.transpose()
            P = Mt * (M * Mt) ** (-1) * M
            return P * v

        t = projection(matrix(self.reduced_basis), vector(t))

        def CVPP_2V(t, V, voronoi_cell):
            t_new = t
            while not voronoi_cell.contains(t_new.list()):
                v = max(V, key=lambda v: t_new * v / v.norm() ** 2)
                t_new = t_new - v
            return t - t_new

        V = self.voronoi_relevant_vectors()
        t = vector(t)
        p = 0
        while not (ZZ(2 ** p) * voronoi_cell).contains(t):
            p += 1
        t_new = t
        i = p
        while i >= 1:
            V_scaled = [v * (2 ** (i - 1)) for v in V]
            t_new = t_new - CVPP_2V(t_new, V_scaled, ZZ(2 ** (i - 1)) * voronoi_cell)
            i -= 1
        return t - t_new
    def __init__(self, A, elt=None, check=True):
        """
        TESTS::

            sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])])
            sage: A(QQ(4))
            Traceback (most recent call last):
            ...
            TypeError: elt should be a vector, a matrix, or an element of the base field

            sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])])
            sage: elt = B(Matrix([[1,1], [-1,1]])); elt
            e0 + e1
            sage: TestSuite(elt).run()
            sage: B(Matrix([[0,1], [1,0]]))
            Traceback (most recent call last):
            ...
            ValueError: matrix does not define an element of the algebra
        """
        AlgebraElement.__init__(self, A)
        k = A.base_ring()
        n = A.degree()
        if elt is None:
            self._vector = vector(k, n)
            self._matrix = Matrix(k, n)
        else:
            if isinstance(elt, int):
                elt = Integer(elt)
            elif isinstance(elt, list):
                elt = vector(elt)
            if A == elt.parent():
                self._vector = elt._vector.base_extend(k)
                self._matrix = elt._matrix.base_extend(k)
            elif k.has_coerce_map_from(elt.parent()):
                e = k(elt)
                if e == 0:
                    self._vector = vector(k, n)
                    self._matrix = Matrix(k, n)
                elif A.is_unitary():
                    self._vector = A._one * e
                    self._matrix = Matrix.identity(k, n) * e
                else:
                    raise TypeError("algebra is not unitary")
            elif is_Vector(elt):
                self._vector = elt.base_extend(k)
                self._matrix = Matrix(k, sum([elt[i] * A.table()[i] for i in xrange(n)]))
            elif is_Matrix(elt):
                if not A.is_unitary():
                    raise TypeError("algebra is not unitary")
                self._vector = A._one * elt
                if not check or sum([self._vector[i]*A.table()[i] for i in xrange(n)]) == elt:
                    self._matrix = elt
                else:
                    raise ValueError("matrix does not define an element of the algebra")
            else:
                raise TypeError("elt should be a vector, a matrix, " +
                                "or an element of the base field")
Exemplo n.º 19
0
    def has_rational_point(self, point = False,
                           algorithm = 'default', read_cache = True):
        r"""
        Returns True if and only if the conic ``self``
        has a point over its base field `B`.

        If ``point`` is True, then returns a second output, which is
        a rational point if one exists.
        
        Points are cached whenever they are found. Cached information
        is used if and only if ``read_cache`` is True.
        
        EXAMPLES:

            sage: Conic(RR, [1, 1, 1]).has_rational_point()
            False
            sage: Conic(CC, [1, 1, 1]).has_rational_point()
            True
            
            sage: Conic(RR, [1, 2, -3]).has_rational_point(point = True)
            (True, (1.73205080756888 : 0.000000000000000 : 1.00000000000000))
        """
        if read_cache:
            if self._rational_point is not None:
                if point:
                    return True, self._rational_point
                else:
                    return True
        B = self.base_ring()
        if is_ComplexField(B):
            if point:
                [_,_,_,d,e,f] = self._coefficients
                if d == 0:
                    return True, self.point([0,1,0])
                return True, self.point([0, ((e**2-4*d*f).sqrt()-e)/(2*d), 1],
                                        check = False)
            return True
        if is_RealField(B):
            D, T = self.diagonal_matrix()
            [a, b, c] = [D[0,0], D[1,1], D[2,2]]
            if a == 0:
                ret = True, self.point(T*vector([1,0,0]), check = False)
            elif a*c <= 0:
                ret = True, self.point(T*vector([(-c/a).sqrt(),0,1]),
                                       check = False)
            elif b == 0:
                ret = True, self.point(T*vector([0,1,0]), check = False)
            elif b*c <= 0:
                ret = True, self.point(T*vector([0,(-c/b).sqrt(),0,1]),
                                       check = False)
            else:
                ret = False, None
            if point:
                return ret
            return ret[0]
        raise NotImplementedError, "has_rational_point not implemented for " \
                                   "conics over base field %s" % B 
def _normalize(x):
    r"""
    make x of length 1
    """
    from sage.misc.functional import norm
    x=vector(RR, x)
    if norm(x) == 0:
        return x
    return vector(x/norm(x))
def _stereo_arc(x,y, xy=None,  north=(1,0,0), right=(0,1,0), translation=-1, **kwds):
    from sage.misc.functional import n
    x=vector(x)
    y=vector(y)
    sx=n(_stereo_coordinates(x, north=north, right=right, translation=translation))
    sy=n(_stereo_coordinates(y, north=north, right=right, translation=translation))
    if xy == None:
        xy=x+y
    sxy=n(_stereo_coordinates(xy, north=north, right=right, translation=translation))
    return _arc(sx,sy,sxy,**kwds)                                                               
Exemplo n.º 22
0
    def decode_to_code(self, y, **kwargs):
        r"""
        Decodes ``y`` to an element in :meth:`sage.coding.decoder.Decoder.code`.

        EXAMPLES::

            sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'a').list()[:15], 7)
            sage: Ce = codes.ExtendedCode(C)
            sage: D = codes.decoders.ExtendedCodeOriginalCodeDecoder(Ce)
            sage: c = Ce.random_element()
            sage: Chan = channels.StaticErrorRateChannel(Ce.ambient_space(), D.decoding_radius())
            sage: y = Chan(c)
            sage: y in Ce
            False
            sage: D.decode_to_code(y) == c
            True

        Another example, with a list decoder::

            sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'a').list()[:15], 7)
            sage: Ce = codes.ExtendedCode(C)
            sage: Dgrs = C.decoder('GuruswamiSudan', tau = 4)
            sage: D = codes.decoders.ExtendedCodeOriginalCodeDecoder(Ce, original_decoder = Dgrs)
            sage: c = Ce.random_element()
            sage: Chan = channels.StaticErrorRateChannel(Ce.ambient_space(), D.decoding_radius())
            sage: y = Chan(c)
            sage: y in Ce
            False
            sage: c in D.decode_to_code(y)
            True
        """
        D = self.original_decoder()
        C = self.code()
        F = C.base_field()
        n = C.length()
        y_original = copy(y.list())
        y_original.pop(n - 1)
        decoded = D.decode_to_code(vector(y_original), **kwargs)
        if 'list-decoder' in self.decoder_type():
            l = []
            for word in decoded:
                last_pos = F.zero()
                for i in word:
                    last_pos += i
                word_list = list(word)
                word_list.append(last_pos)
                l.append(vector(F, word_list))
            return l
        else:
            last_pos = F.zero()
            for i in decoded:
                last_pos += i
            decoded_list = list(decoded)
            decoded_list.append(last_pos)
            return vector(F, decoded_list)
Exemplo n.º 23
0
    def encode(self, m, S):
        ''' encodes a vector m (in Zmod(q)^n) to index set S '''

        zinv = prod([self.zinv[i] for i in S])

        m = vector(Zmod(self.q),m)

        zero = vector(Zmod(self.q),self.D_sigmap_I()) # random encoding of 0
        c = self.Rq(list(zero + m))

        return c * zinv
Exemplo n.º 24
0
    def __call__(self,w, field = None):
        r"""
        Return the image of ``w`` under the similarity. Here ``w`` may be a ConvexPolygon or a vector
        (or something that can be indexed in the same way as a vector). If a field is provided,
        the objects returned will be defined over this field.

        TESTS::

            sage: from flatsurf.geometry.similarity import SimilarityGroup
            sage: S = SimilarityGroup(AA)
            sage: a = S((1,-1,AA(2).sqrt(),0))
            sage: a((1,2))
            (4.414213562373095?, 1)
            sage: a.matrix()*vector((1,2,1))
            (4.414213562373095?, 1, 1)

            sage: from flatsurf.geometry.similarity import SimilarityGroup
            sage: SG = SimilarityGroup(QQ)
            sage: from flatsurf.geometry.polygon import Polygons
            sage: P = Polygons(QQ)
            sage: p = P.an_element()
            sage: p
            Polygon: (0, 0), (1, 0), (1, 1), (0, 1)
            sage: g = SG.an_element()**2
            sage: g
            (x, y) |-> (25*x + 4, 25*y + 10)
            sage: g(p)
            Polygon: (4, 10), (29, 10), (29, 35), (4, 35)
            sage: g(p, field=AA).parent()
            polygons with coordinates in Algebraic Real Field
        """
        if isinstance(w,ConvexPolygon):
            if field is None:
                P = Polygons(field=self.parent().base_field())
            else:
                P = Polygons(field=field)
            try:
                return P(vertices=[self(v) for v in w.vertices()])
            except ValueError as e:
                if not self._sign.is_one():
                    raise ValueError("Similarity must be orientation preserving.")
                else:
                    # Not sure why this would happen:
                    raise e
        if field is None:
            if self._sign.is_one():
                return vector([self._a*w[0]-self._b*w[1]+self._s, self._b*w[0]+self._a*w[1]+self._t])
            else:
                return vector([self._a*w[0]+self._b*w[1]+self._s, self._b*w[0]-self._a*w[1]+self._t])
        else:
            if self._sign.is_one():
                return vector(field, [self._a*w[0]-self._b*w[1]+self._s, self._b*w[0]+self._a*w[1]+self._t])
            else:
                return vector(field, [self._a*w[0]+self._b*w[1]+self._s, self._b*w[0]-self._a*w[1]+self._t])
Exemplo n.º 25
0
def repr_pretty(coefficients, type, prefix='x', indices=None, latex=False):
    r"""
    Return a pretty representation of equation/inequality represented
    by the coefficients.

    INPUT:

    - ``coefficients`` -- a tuple or other iterable

    - ``type`` -- either ``0`` (``PolyhedronRepresentation.INEQUALITY``)
      or ``1`` (``PolyhedronRepresentation.EQUATION``)

    - ``prefix`` -- a string

    - ``indices`` -- a tuple or other iterable

    - ``latex`` -- a boolean

    OUTPUT:

    A string.

    EXAMPLES::

        sage: from sage.geometry.polyhedron.representation import repr_pretty
        sage: from sage.geometry.polyhedron.representation import PolyhedronRepresentation
        sage: print(repr_pretty((0, 1, 0, 0), PolyhedronRepresentation.INEQUALITY))
        x0 >= 0
        sage: print(repr_pretty((1, 2, 1, 0), PolyhedronRepresentation.INEQUALITY))
        2*x0 + x1 + 1 >= 0
        sage: print(repr_pretty((1, -1, -1, 1), PolyhedronRepresentation.EQUATION))
        x2 + 1 == x0 + x1
    """
    from sage.misc.latex import latex as latex_function
    from sage.modules.free_module_element import vector
    from sage.symbolic.ring import SR

    coeffs = vector(coefficients)
    if indices is None:
        indices = range(len(coeffs)-1)
    vars = vector([1] + list(SR(prefix + '{}'.format(i)) for i in indices))
    positive_part = vector([max(c, 0) for c in coeffs])
    negative_part = - (coeffs - positive_part)
    assert coeffs == positive_part - negative_part
    if type == PolyhedronRepresentation.EQUATION:
        rel = '=' if latex else '=='
    elif type == PolyhedronRepresentation.INEQUALITY:
        rel = r'\geq' if latex else '>='
    else:
        raise NotImplementedError(
            'no pretty printing available: wrong type {}'.format(type))
    f = latex_function if latex else repr
    return '{} {} {}'.format(f(positive_part*vars), rel, f(negative_part*vars))
Exemplo n.º 26
0
 def d_vector(self):
     n = self.parent().rk
     one = self.parent().ambient_field()(1)
     factors = self.lift_to_field().factor()
     initial = []
     non_initial = []
     [(initial if x[1] > 0 and len(x[0].monomials()) == 1 else non_initial).append(x[0]**x[1]) for x in factors]
     initial = prod(initial+[one]).numerator()
     non_initial = prod(non_initial+[one]).denominator()
     v1 = vector(non_initial.exponents()[0][:n])
     v2 = vector(initial.exponents()[0][:n])
     return tuple(v1-v2)
Exemplo n.º 27
0
    def __init__(self, params, asym=False):

        (self.n, self.q, sigma, self.sigma_prime, self.k) = params

        S, x = PolynomialRing(ZZ, 'x').objgen()
        self.R = S.quotient_ring(S.ideal(x**self.n + 1))

        Sq = PolynomialRing(Zmod(self.q), 'x')
        self.Rq = Sq.quotient_ring(Sq.ideal(x**self.n + 1))

        # draw z_is uniformly from Rq and compute its inverse in Rq
        if asym:
            z = [self.Rq.random_element() for i in range(self.k)]
            self.zinv = [z_i**(-1) for z_i in z]
        else: # or do symmetric version
            z = self.Rq.random_element()
            zinv = z**(-1)
            z, self.zinv = zip(*[(z,zinv) for i in range(self.k)])

        # set up some discrete Gaussians
        DGSL_sigma = DGSL(ZZ**self.n, sigma)
        self.D_sigma = lambda: self.Rq(list(DGSL_sigma()))

        # discrete Gaussian in ZZ^n with stddev sigma_prime, yields random level-0 encodings
        DGSL_sigmap_ZZ = DGSL(ZZ**self.n, self.sigma_prime)
        self.D_sigmap_ZZ = lambda: self.Rq(list(DGSL_sigmap_ZZ()))

        # draw g repeatedly from a Gaussian distribution of Z^n (with param sigma)
        # until g^(-1) in QQ[x]/<x^n + 1> is small (< n^2)
        Sk = PolynomialRing(QQ, 'x')
        K = Sk.quotient_ring(Sk.ideal(x**self.n + 1)) 
        while True:
            l = self.D_sigma()
            ginv_K = K(mod_near_poly(l, self.q))**(-1)
            ginv_size = vector(ginv_K).norm()

            if ginv_size < self.n**2:
                g = self.Rq(l)
                self.ginv = g**(-1)
                break

        # discrete Gaussian in I = <g>, yields random encodings of 0
        short_g = vector(ZZ, mod_near_poly(g,self.q))
        DGSL_sigmap_I = DGSL(short_g, self.sigma_prime)
        self.D_sigmap_I = lambda: self.Rq(list(DGSL_sigmap_I()))

        # compute zero-testing parameter p_zt
        # randomly draw h (in Rq) from a discrete Gaussian with param q^(1/2)
        self.h = self.Rq(list(DGSL(ZZ**self.n, round(sqrt(self.q)))()))

        # create p_zt
        self.p_zt = self.ginv * self.h * prod(z)
Exemplo n.º 28
0
    def closest_vector(self, t):
        """
        Compute the closest vector in the embedded lattice to a given vector.

        INPUT:

        - ``t`` -- the target vector to compute the closest vector to

        OUTPUT:

        The vector in the lattice closest to ``t``.

        EXAMPLES::

            sage: from sage.modules.free_module_integer import IntegerLattice
            sage: L = IntegerLattice([[1, 0], [0, 1]])
            sage: L.closest_vector((-6, 5/3))
            (-6, 2)

        ALGORITHM:

        Uses the algorithm from [MV2010]_.
        """
        voronoi_cell = self.voronoi_cell()

        def projection(M, v):
            Mt = M.transpose()
            P = Mt * (M * Mt) ** (-1) * M
            return P * v

        t = projection(matrix(self.reduced_basis), vector(t))

        def CVPP_2V(t, V, voronoi_cell):
            t_new = t
            while not voronoi_cell.contains(t_new.list()):
                v = max(V, key=lambda v: t_new * v / v.norm() ** 2)
                t_new = t_new - v
            return t - t_new

        V = self.voronoi_relevant_vectors()
        t = vector(t)
        p = 0
        while not (ZZ(2 ** p) * voronoi_cell).contains(t):
            p += 1
        t_new = t
        i = p
        while i >= 1:
            V_scaled = [v * (2 ** (i - 1)) for v in V]
            t_new = t_new - CVPP_2V(t_new, V_scaled, ZZ(2 ** (i - 1)) * voronoi_cell)
            i -= 1
        return t - t_new
def _stereo_coordinates(x, north=(1,0,0), right=(0,1,0), translation=-1):
    r"""
    Project stereographically points from a sphere
    """
    from sage.misc.functional import norm
    north=_normalize(north)
    right=vector(right)
    right=_normalize(right-(right*north)*north)
    if norm(right) == 0:
        raise ValueError ("Right must not be linearly dependent from north")
    top=north.cross_product(right)
    x=_normalize(x)
    p=(translation-north*x)/(1-north*x)*(north-x)+x
    return vector((right*p, top*p ))
Exemplo n.º 30
0
    def tangent_vector(self, lab, p, v, ring=None):
        r"""
        Return a tangent vector.

        INPUT:

        - ``lab`` -- label of a polygon

        - ``p`` -- coordinates of a point in the polygon

        - ``v`` -- coordinates of a vector in R^2
        
        EXAMPLES::

            sage: from flatsurf.geometry.chamanara import chamanara_surface
            sage: S = chamanara_surface(1/2)
            sage: S.tangent_vector(S.base_label(), (1/2,1/2), (1,1))
            SimilaritySurfaceTangentVector in polygon (1, [-1  0]
            [ 0 -1]) based at (1/2, -3/2) with vector (1, 1)
            sage: K.<sqrt2> = QuadraticField(2)
            sage: S.tangent_vector(S.base_label(), (1/2,1/2), (1,sqrt2))
            SimilaritySurfaceTangentVector in polygon (1, [-1  0]
            [ 0 -1]) based at (1/2, -3/2) with vector (1, sqrt2)
        """
        p = vector(p)
        v = vector(v)

        if p.parent().dimension() != 2 or v.parent().dimension() != 2:
            raise ValueError("p (={!r}) and v (={!v}) should have two coordinates")

        if ring is None:
            R = p.base_ring()
            if R != v.base_ring():
                from sage.structure.element import get_coercion_model
                cm = get_coercion_model()
                R = cm.common_parent(R, v.base_ring())
                p = p.change_ring(R)
                v = v.change_ring(R)
    
            R2 = self.base_ring()
            if R != R2:
                if R2.has_coerce_map_from(R):
                    p = p.change_ring(R2)
                    v = v.change_ring(R2)
                    R = R2
                elif not R.has_coerce_map_from(R2):
                    raise ValueError("not able to find a common ring for arguments")
            return self.tangent_bundle(R)(lab, p, v)
        else:
            return self.tangent_bundle(ring)(lab, p, v)
Exemplo n.º 31
0
    def __init__(self, n, q, D, secret_dist='uniform', m=None):
        """
        Construct an LWE oracle in dimension ``n`` over a ring of order
        ``q`` with noise distribution ``D``.

        INPUT:

        - ``n`` - dimension (integer > 0)
        - ``q`` - modulus typically > n (integer > 0)
        - ``D`` - an error distribution such as an instance of
          :class:`DiscreteGaussianSamplerRejection` or :class:`UniformSampler`
        - ``secret_dist`` - distribution of the secret; one of

          - "uniform" - secret follows the uniform distribution in `\Zmod{q}`
          - "noise" - secret follows the noise distrbution
          - ``(lb,ub)`` - the secret is chosen uniformly from ``[lb,...,ub]`` including both endpoints

        - ``m`` - number of allowed samples or ``None`` if no such limit exists
          (default: ``None``)

        EXAMPLE:

        First, we construct a noise distribution with standard deviation 3.0::

            sage: D = DiscreteGaussianSamplerRejection(3.0)

        Next, we construct our oracle::

            sage: lwe = LWE(n=20, q=next_prime(400), D=D); lwe
            LWE(20, 401, DiscreteGaussianSamplerRejection(3.000000, 53, 4), 'uniform', None)

        and sample 1000 samples::

            sage: L = [lwe() for _ in range(1000)]

        To test the oracle, we use the internal secret to evaluate the samples
        in the secret::

            sage: S = [ZZ(a.dot_product(lwe._LWE__s) - c) for (a,c) in L]

        However, while Sage represents finite field elements between 0 and q-1
        we rely on a balanced representation of those elements here. Hence, we
        fix the representation and recover the correct standard deviation of the
        noise::

            sage: sqrt(variance([e if e <= 200 else e-401 for e in S]).n())
            3.0...

        If ``m`` is not ``None`` the number of available samples is restricted::

            sage: lwe = LWE(n=20, q=next_prime(400), D=D, m=30)
            sage: _ = [lwe() for _ in range(30)]
            sage: lwe() # 31
            Traceback (most recent call last):
            ...
            IndexError: Number of available samples exhausted.
        """
        self.n = ZZ(n)
        self.m = m
        self.__i = 0
        self.K = IntegerModRing(q)
        self.FM = FreeModule(self.K, n)
        self.D = D

        self.secret_dist = secret_dist
        if secret_dist == 'uniform':
            self.__s = random_vector(self.K, self.n)
        elif secret_dist == 'noise':
            self.__s = vector(self.K, self.n, [self.D() for _ in range(n)])
        else:
            try:
                lb, ub = map(ZZ, secret_dist)
                self.__s = vector(self.K, self.n,
                                  [randint(lb, ub) for _ in range(n)])
            except (IndexError, TypeError):
                raise TypeError("Parameter secret_dist=%s not understood." %
                                (secret_dist))
Exemplo n.º 32
0
 def func(z):
     vz = vector(z)
     return - (M*vz).norm(p) / vz.norm(p)
Exemplo n.º 33
0
def solve(self, c=0):
    r"""
    Return a vector `x` such that ``self(x) == c``.

    INPUT:

    - ``c`` -- (default: 0) a rational number.

    OUTPUT:

    - A non-zero vector `x` satisfying ``self(x) == c``.

    ALGORITHM:

    Uses PARI's qfsolve(). Algorithm described by Jeroen Demeyer; see comments on :trac:`19112`

    EXAMPLES::

        sage: F = DiagonalQuadraticForm(QQ, [1, -1]); F
        Quadratic form in 2 variables over Rational Field with coefficients:
        [ 1 0 ]
        [ * -1 ]
        sage: F.solve()
        (1, 1)
        sage: F.solve(1)
        (1, 0)
        sage: F.solve(2)
        (3/2, -1/2)
        sage: F.solve(3)
        (2, -1)

    ::

        sage: F = DiagonalQuadraticForm(QQ, [1, 1, 1, 1])
        sage: F.solve(7)
        (1, 2, -1, -1)
        sage: F.solve()
        Traceback (most recent call last):
        ...
        ArithmeticError: no solution found (local obstruction at -1)

    ::

        sage: Q = QuadraticForm(QQ, 2, [17, 94, 130])
        sage: x = Q.solve(5); x
        (17, -6)
        sage: Q(x)
        5

        sage: Q.solve(6)
        Traceback (most recent call last):
        ...
        ArithmeticError: no solution found (local obstruction at 3)

        sage: G = DiagonalQuadraticForm(QQ, [5, -3, -2])
        sage: x = G.solve(10); x
        (3/2, -1/2, 1/2)
        sage: G(x)
        10

        sage: F = DiagonalQuadraticForm(QQ, [1, -4])
        sage: x = F.solve(); x
        (2, 1)
        sage: F(x)
        0

    ::

        sage: F = QuadraticForm(QQ, 4, [0, 0, 1, 0, 0, 0, 1, 0, 0, 0]); F
        Quadratic form in 4 variables over Rational Field with coefficients:
        [ 0 0 1 0 ]
        [ * 0 0 1 ]
        [ * * 0 0 ]
        [ * * * 0 ]
        sage: F.solve(23)
        (23, 0, 1, 0)

    Other fields besides the rationals are currently not supported::

        sage: F = DiagonalQuadraticForm(GF(11), [1, 1])
        sage: F.solve()
        Traceback (most recent call last):
        ...
        TypeError: solving quadratic forms is only implemented over QQ
    """
    if self.base_ring() is not QQ:
        raise TypeError("solving quadratic forms is only implemented over QQ")

    M = self.Gram_matrix()

    # If no argument passed for c, we just pass self into qfsolve().
    if not c:
        x = qfsolve(M)
        if isinstance(x, Integer):
            raise ArithmeticError(
                "no solution found (local obstruction at {})".format(x))
        return x

    # If c != 0, define a new quadratic form Q = self - c*z^2
    d = self.dim()
    N = Matrix(self.base_ring(), d + 1, d + 1)
    for i in range(d):
        for j in range(d):
            N[i, j] = M[i, j]
    N[d, d] = -c

    # Find a solution x to Q(x) = 0, using qfsolve()
    x = qfsolve(N)
    # Raise an error if qfsolve() doesn't find a solution
    if isinstance(x, Integer):
        raise ArithmeticError(
            "no solution found (local obstruction at {})".format(x))

    # Let z be the last term of x, and remove z from x
    z = x[-1]
    x = x[:-1]
    # If z != 0, then Q(x/z) = c
    if z:
        return x * (1 / z)

    # Case 2: We found a solution self(x) = 0. Let e be any vector such
    # that B(x,e) != 0, where B is the bilinear form corresponding to self.
    # To find e, just try all unit vectors (0,..0,1,0...0).
    # Let a = (c - self(e))/(2B(x,e)) and let y = e + a*x.
    # Then self(y) = B(e + a*x, e + a*x) = self(e) + 2B(e, a*x)
    #              = self(e) + 2([c - self(e)]/[2B(x,e)]) * B(x,e) = c.
    e = vector([1] + [0] * (d - 1))
    i = 0
    while self.bilinear_map(x, e) == 0:
        e[i] = 0
        i += 1
        e[i] = 1

    a = (c - self(e)) / (2 * self.bilinear_map(x, e))
    return e + a * x
Exemplo n.º 34
0
def series_sum_ordinary(Intervals, dop, bwrec, ini, pt, stop, stride):

    jet = pt.jet(Intervals)
    Jets = jet.parent()  # polynomial ring!
    ord = pt.jet_order
    jetpow = Jets.one()
    radpow = bounds.IR.one()

    ordrec = bwrec.order
    assert ini.expo.is_zero()
    last = collections.deque([Intervals.zero()] * (ordrec - dop.order() + 1))
    last.extend(
        Intervals(ini.shift[n][0]) for n in xrange(dop.order() - 1, -1, -1))
    assert len(last) == ordrec + 1  # not ordrec!
    psum = Jets.zero()

    tail_bound = bounds.IR(infinity)

    start = dop.order()
    # Evaluate the coefficients a bit in advance as we are going to need them to
    # compute the residuals. This is not ideal at high working precision, but
    # already saves a lot of time compared to doing the evaluations twice.
    bwrec_ev = bwrec.eval_method(Intervals)
    bwrec_nplus = collections.deque(
        (bwrec_ev(start + i) for i in xrange(ordrec)), maxlen=ordrec)

    def get_bound(maj):
        return maj.bound(pt.rad, rows=ord)

    def get_residuals():
        return [
            stop.maj.normalized_residual(n, [[c] for c in last][1:],
                                         [[[c] for c in l]
                                          for l in bwrec_nplus])
        ]

    def get_value():
        return psum

    for n in itertools.count():
        last.rotate(1)
        #last[0] = None
        # At this point last[0] should be considered undefined (it will hold
        # the coefficient of z^n later in the loop body) and last[1], ...
        # last[ordrec] are the coefficients of z^(n-1), ..., z^(n-ordrec)
        if n % stride == 0:
            radpowest = abs(
                jetpow[0] if pt.is_numeric else Intervals(pt.rad**n))
            est = sum(abs(a) for a in last) * radpowest
            done, tail_bound = stop.check(get_bound, get_residuals, get_value,
                                          (n <= start), n, tail_bound, est,
                                          stride)
            if done:
                break
        if n >= start:
            bwrec_n = (bwrec_nplus[0] if bwrec_nplus else bwrec_ev(n))
            comb = sum(bwrec_n[k] * last[k] for k in xrange(1, ordrec + 1))
            last[0] = -~bwrec_n[0] * comb
            bwrec_nplus.append(bwrec_ev(n + bwrec.order))
            # logger.debug("n = %s, [c(n), c(n-1), ...] = %s", n, list(last))
        term = Jets(last[0])._mul_trunc_(jetpow, ord)
        psum += term
        jetpow = jetpow._mul_trunc_(jet, ord)
        radpow *= pt.rad
    logger.info(
        "summed %d terms, tail <= %s (est = %s), coeffwise error <= %s", n,
        tail_bound, bounds.IR(est),
        max(psum[i].rad() for i in range(ord)) if pt.is_numeric else "n/a")
    # Account for the dropped high-order terms in the intervals we return
    # (tail_bound is actually a bound on the Frobenius norm of the error matrix,
    # so there is some overestimation). WARNING: For symbolic x, the resulting
    # polynomials have to be interpreted with some care: in particular, it would
    # be incorrect to evaluate a polynomial result with real coefficients at a
    # complex point. Our current mechanism to choose whether to add a real or
    # complex error bound in this case is pretty fragile.
    tail_bound = tail_bound.abs()
    res = vector(_add_error(psum[i], tail_bound) for i in xrange(ord))
    return res
Exemplo n.º 35
0
        def radical_basis(self):
            r"""
            Return a basis of the Jacobson radical of this algebra.

            .. NOTE::

               This implementation handles algebras over fields of
               characteristic zero (using Dixon's lemma) or fields of
               characteristic `p` in which we can compute `x^{1/p}`
               [FR1985]_, [Eb1989]_.

            OUTPUT:

            - a list of elements of ``self``.

            .. SEEALSO:: :meth:`radical`, :class:`Algebras.Semisimple`

            EXAMPLES::

                sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A
                An example of a finite dimensional algebra with basis:
                the path algebra of the Kronecker quiver
                (containing the arrows a:x->y and b:x->y) over Rational Field
                sage: A.radical_basis()
                (a, b)

            We construct the group algebra of the Klein Four-Group
            over the rationals::

                sage: A = KleinFourGroup().algebra(QQ)

            This algebra belongs to the category of finite dimensional
            algebras over the rationals::

                sage: A in Algebras(QQ).FiniteDimensional().WithBasis()
                True

            Since the field has characteristic `0`, Maschke's Theorem
            tells us that the group algebra is semisimple. So its
            radical is the zero ideal::

                sage: A in Algebras(QQ).Semisimple()
                True
                sage: A.radical_basis()
                ()

            Let's work instead over a field of characteristic `2`::

                sage: A = KleinFourGroup().algebra(GF(2))
                sage: A in Algebras(GF(2)).Semisimple()
                False
                sage: A.radical_basis()
                (() + (1,2)(3,4), (3,4) + (1,2)(3,4), (1,2) + (1,2)(3,4))

            We now implement the algebra `A = K[x] / (x^p-1)`, where `K`
            is a finite field of characteristic `p`, and check its
            radical; alas, we currently need to wrap `A` to make it a
            proper :class:`ModulesWithBasis`::

                sage: class AnAlgebra(CombinatorialFreeModule):
                ....:     def __init__(self, F):
                ....:         R.<x> = PolynomialRing(F)
                ....:         I = R.ideal(x**F.characteristic()-F.one())
                ....:         self._xbar = R.quotient(I).gen()
                ....:         basis_keys = [self._xbar**i for i in range(F.characteristic())]
                ....:         CombinatorialFreeModule.__init__(self, F, basis_keys,
                ....:                 category=Algebras(F).FiniteDimensional().WithBasis())
                ....:     def one(self):
                ....:         return self.basis()[self.base_ring().one()]
                ....:     def product_on_basis(self, w1, w2):
                ....:         return self.from_vector(vector(w1*w2))
                sage: AnAlgebra(GF(3)).radical_basis()
                (B[1] + 2*B[xbar^2], B[xbar] + 2*B[xbar^2])
                sage: AnAlgebra(GF(16,'a')).radical_basis()
                (B[1] + B[xbar],)
                sage: AnAlgebra(GF(49,'a')).radical_basis()
                (B[1] + 6*B[xbar^6], B[xbar] + 6*B[xbar^6], B[xbar^2] + 6*B[xbar^6],
                 B[xbar^3] + 6*B[xbar^6], B[xbar^4] + 6*B[xbar^6], B[xbar^5] + 6*B[xbar^6])

            TESTS::

                sage: A = KleinFourGroup().algebra(GF(2))
                sage: A.radical_basis()
                (() + (1,2)(3,4), (3,4) + (1,2)(3,4), (1,2) + (1,2)(3,4))

                sage: A = KleinFourGroup().algebra(QQ, category=Monoids())
                sage: A.radical_basis.__module__
                'sage.categories.finite_dimensional_algebras_with_basis'
                sage: A.radical_basis()
                ()
            """
            F = self.base_ring()
            if not F.is_field():
                raise NotImplementedError("the base ring must be a field")
            p = F.characteristic()
            from sage.matrix.constructor import matrix
            from sage.modules.free_module_element import vector

            product_on_basis = self.product_on_basis

            if p == 0:
                keys = list(self.basis().keys())
                cache = [{(i, j): c
                          for i in keys for j, c in product_on_basis(y, i)}
                         for y in keys]
                mat = [[
                    sum(x.get((j, i), 0) * c for (i, j), c in y.items())
                    for x in cache
                ] for y in cache]

                mat = matrix(self.base_ring(), mat)
                rad_basis = mat.kernel().basis()

            else:
                # TODO: some finite field elements in Sage have both an
                # ``nth_root`` method and a ``pth_root`` method (such as ``GF(9,'a')``),
                # some only have a ``nth_root`` element such as ``GF(2)``
                # I imagine that ``pth_root`` would be fastest, but it is not
                # always available....
                if hasattr(self.base_ring().one(), 'nth_root'):
                    root_fcn = lambda s, x: x.nth_root(s)
                else:
                    root_fcn = lambda s, x: x**(1 / s)

                s, n = 1, self.dimension()
                B = [b.on_left_matrix() for b in self.basis()]
                I = B[0].parent().one()
                while s <= n:
                    BB = B + [I]
                    G = matrix([[
                        (-1)**s * (b * bb).characteristic_polynomial()[n - s]
                        for bb in BB
                    ] for b in B])
                    C = G.left_kernel().basis()
                    if 1 < s < F.order():
                        C = [
                            vector(F, [root_fcn(s, ci) for ci in c]) for c in C
                        ]
                    B = [sum(ci * b for (ci, b) in zip(c, B)) for c in C]
                    s = p * s
                e = vector(self.one())
                rad_basis = [b * e for b in B]

            return tuple([self.from_vector(vec) for vec in rad_basis])
    def _discrete_log_pgroup(self, p, aa, b):
        r"""
        Attempt to express an element of p-power order in terms of
        generators of a p-subgroup of this group.

        Used as a subroutine in the _discrete_log() method.

        ALGORITHM:

        This implements a basic version of the recursive algorithm
        from [Suth2008]_.
        The base cases are handled using a variant of Shanks'
        baby-step giant-step algorithm for products of cyclic groups.

        EXAMPLES::

            sage: G = AdditiveAbelianGroup([5, 5**2, 5**4, 5**4])
            sage: (a, b, c, d) = gs = G.gens()
            sage: A = AdditiveAbelianGroupWrapper(a.parent(), gs, [g.order() for g in gs])
            sage: A._discrete_log_pgroup(5, gs, a + 17 * b + 123 * c + 456 * d)
            (1, 17, 123, 456)
        """
        from sage.arith.misc import valuation
        from sage.functions.other import ceil
        from sage.misc.functional import sqrt
        from itertools import product as iproduct

        vals = [valuation(a.order(), p) for a in aa]
        qq = lambda j, k: vector(p**(j + max(0, v - k))
                                 for a, v in zip(aa, vals))
        subbasis = lambda j, k: [q * a for q, a in zip(qq(j, k), aa)]
        dotprod = lambda xs, ys: sum(x * y for x, y in zip(xs, ys))

        def _base(j, k, c):

            assert k - j == 1
            aajk = subbasis(j, k)
            assert all(a.order() in (1, p) for a in aajk)
            idxs = [i for i, a in enumerate(aajk) if a.order() == p]

            rs = [([0], [0]) for i in range(len(aajk))]
            for i in range(len(idxs)):
                rs[idxs[i]] = (range(p), [0]) if i % 2 else ([0], range(p))
            if len(idxs) % 2:
                m = ceil(sqrt(p))
                rs[idxs[-1]] = range(0, p, m), range(m)

            tab = {}
            for x in iproduct(*(r for r, _ in rs)):
                key = dotprod(x, aajk)
                if hasattr(key, 'set_immutable'):
                    key.set_immutable()
                tab[key] = vector(x)
            for y in iproduct(*(r for _, r in rs)):
                key = c - dotprod(y, aajk)
                if hasattr(key, 'set_immutable'):
                    key.set_immutable()
                if key in tab:
                    return tab[key] + vector(y)

            raise TypeError('Not in group')

        def _rec(j, k, c):

            assert 0 <= j < k

            if k - j <= 1:  # base case
                return _base(j, k, c)

            w = 2
            js = list(range(j, k, (k - j + w - 1) // w)) + [k]
            assert len(js) == w + 1

            x = vector([0] * len(aa))
            for i in reversed(range(w)):

                gamma = p**(js[i] - j) * c - dotprod(x, subbasis(js[i], k))

                v = _rec(js[i], js[i + 1], gamma)

                assert not any(
                    q1 % q2
                    for q1, q2 in zip(qq(js[i], js[i + 1]), qq(js[i], k)))
                x += vector(
                    q1 // q2 * r
                    for q1, q2, r in zip(qq(js[i], js[i +
                                                      1]), qq(js[i], k), v))

            return x

        return _rec(0, max(vals), b)
Exemplo n.º 37
0
 def extract(cls, obj):
     """
     Takes an object extracted by the json parser and decodes the
     special-formating dictionaries used to store special types.
     """
     if isinstance(obj, dict) and "data" in obj:
         if len(obj) == 2 and "__ComplexList__" in obj:
             return [complex(*v) for v in obj["data"]]
         elif len(obj) == 2 and "__QQList__" in obj:
             assert SAGE_MODE
             return [QQ(tuple(v)) for v in obj["data"]]
         elif len(obj) == 3 and "__NFList__" in obj and "base" in obj:
             assert SAGE_MODE
             base = cls.extract(obj["base"])
             return [cls._extract(base, c) for c in obj["data"]]
         elif len(obj) == 2 and "__IntDict__" in obj:
             if SAGE_MODE:
                 return {Integer(k): cls.extract(v) for k, v in obj["data"]}
             else:
                 return {int(k): cls.extract(v) for k, v in obj["data"]}
         elif len(obj) == 3 and "__Vector__" in obj and "base" in obj:
             assert SAGE_MODE
             base = cls.extract(obj["base"])
             return vector([cls._extract(base, v) for v in obj["data"]])
         elif len(obj) == 2 and "__Rational__" in obj:
             assert SAGE_MODE
             return Rational(*obj["data"])
         elif len(obj) == 3 and "__RealLiteral__" in obj and "prec" in obj:
             assert SAGE_MODE
             return LmfdbRealLiteral(RealField(obj["prec"]), obj["data"])
         elif len(obj) == 2 and "__complex__" in obj:
             return complex(*obj["data"])
         elif len(obj) == 3 and "__Complex__" in obj and "prec" in obj:
             assert SAGE_MODE
             return ComplexNumber(ComplexField(obj["prec"]), *obj["data"])
         elif len(obj) == 3 and "__NFElt__" in obj and "parent" in obj:
             assert SAGE_MODE
             return cls._extract(cls.extract(obj["parent"]), obj["data"])
         elif (
             len(obj) == 3
             and ("__NFRelative__" in obj or "__NFAbsolute__" in obj)
             and "vname" in obj
         ):
             assert SAGE_MODE
             poly = cls.extract(obj["data"])
             return NumberField(poly, name=obj["vname"])
         elif len(obj) == 2 and "__NFCyclotomic__" in obj:
             assert SAGE_MODE
             return CyclotomicField(obj["data"])
         elif len(obj) == 2 and "__IntegerRing__" in obj:
             assert SAGE_MODE
             return ZZ
         elif len(obj) == 2 and "__RationalField__" in obj:
             assert SAGE_MODE
             return QQ
         elif len(obj) == 3 and "__RationalPoly__" in obj and "vname" in obj:
             assert SAGE_MODE
             return QQ[obj["vname"]]([QQ(tuple(v)) for v in obj["data"]])
         elif (len(obj) == 4 and "__Poly__" in obj and "vname" in obj and "base" in obj):
             assert SAGE_MODE
             base = cls.extract(obj["base"])
             return base[obj["vname"]]([cls._extract(base, c) for c in obj["data"]])
         elif (
             len(obj) == 5
             and "__PowerSeries__" in obj
             and "vname" in obj
             and "base" in obj
             and "prec" in obj
         ):
             assert SAGE_MODE
             base = cls.extract(obj["base"])
             prec = infinity if obj["prec"] == "inf" else int(obj["prec"])
             return base[[obj["vname"]]]([cls._extract(base, c) for c in obj["data"]], prec=prec)
         elif len(obj) == 2 and "__date__" in obj:
             return datetime.datetime.strptime(obj["data"], "%Y-%m-%d").date()
         elif len(obj) == 2 and "__time__" in obj:
             return datetime.datetime.strptime(obj["data"], "%H:%M:%S.%f").time()
         elif len(obj) == 2 and "__datetime__" in obj:
             return datetime.datetime.strptime(obj["data"], "%Y-%m-%d %H:%M:%S.%f")
     return obj
Exemplo n.º 38
0
def diamond_cut(V, GM, C, verbose=False):
    r"""
    Perform diamond cutting on polyhedron ``V`` with basis matrix ``GM``
    and radius ``C``.

    INPUT:

    - ``V`` -- polyhedron to cut from

    - ``GM`` -- half of the basis matrix of the lattice

    - ``C`` -- radius to use in cutting algorithm

    - ``verbose`` -- (default: ``False``) whether to print debug information

    OUTPUT:

    A :class:``Polyhedron`` instance.

    EXAMPLES::

        sage: from sage.modules.diamond_cutting import diamond_cut
        sage: V = Polyhedron([[0], [2]])
        sage: GM = matrix([2])
        sage: V = diamond_cut(V, GM, 4)
        sage: V.vertices()
        (A vertex at (2), A vertex at (0))
    """
    # coerce to floats
    GM = GM.N()
    C = float(C)
    if verbose:
        print("Cut\n{}\nwith radius {}".format(GM, C))

    dim = GM.dimensions()
    if dim[0] != dim[1]:
        raise ValueError("the matrix must be square")
    dim = dim[0]
    T = [0] * dim
    U = [0] * dim
    x = [0] * dim
    L = [0] * dim

    # calculate the Gram matrix
    q = matrix(
        [[sum(GM[i][k] * GM[j][k] for k in range(dim)) for j in range(dim)]
         for i in range(dim)])
    if verbose:
        print("q:\n{}".format(q.N()))
    # apply Cholesky/Jacobi decomposition
    q = jacobi(q)
    if verbose:
        print("q:\n{}".format(q.N()))

    i = dim - 1
    T[i] = C
    U[i] = 0

    new_dimension = True
    cut_count = 0
    inequalities = []
    while True:
        if verbose:
            print("Dimension: {}".format(i))
        if new_dimension:
            Z = sqrt(T[i] / q[i][i])
            if verbose:
                print("Z: {}".format(Z))
            L[i] = int(floor(Z - U[i]))
            if verbose:
                print("L: {}".format(L))
            x[i] = int(ceil(-Z - U[i]) - 1)
            new_dimension = False

        x[i] += 1
        if verbose:
            print("x: {}".format(x))
        if x[i] > L[i]:
            i += 1
        elif i > 0:
            T[i - 1] = T[i] - q[i][i] * (x[i] + U[i])**2
            i -= 1
            U[i] = 0
            for j in range(i + 1, dim):
                U[i] += q[i][j] * x[j]
            new_dimension = True
        else:
            if all(elmt == 0 for elmt in x):
                break
            hv = [0] * dim
            for k in range(dim):
                for j in range(dim):
                    hv[k] += x[j] * GM[j][k]
            hv = vector(hv)

            for hv in [hv, -hv]:
                cut_count += 1
                if verbose:
                    print "\n%d) Cut using normal vector %s" % (cut_count, hv)
                hv = [QQ(round(elmt, 6)) for elmt in hv]
                inequalities.append(plane_inequality(hv))
                #cut = Polyhedron(ieqs=[plane_inequality(hv)])
                #V = V.intersection(cut)

    if verbose:
        print("Final cut")
    cut = Polyhedron(ieqs=inequalities)
    V = V.intersection(cut)

    if verbose:
        print("End")

    return V
Exemplo n.º 39
0
    def has_singular_point(self, point=False):
        r"""
        Return True if and only if the conic ``self`` has a rational
        singular point.

        If ``point`` is True, then also return a rational singular
        point (or ``None`` if no such point exists).

        EXAMPLES:

        ::

            sage: c = Conic(QQ, [1,0,1]); c
            Projective Conic Curve over Rational Field defined by x^2 + z^2
            sage: c.has_singular_point(point = True)
            (True, (0 : 1 : 0))

            sage: P.<x,y,z> = GF(7)[]
            sage: e = Conic((x+y+z)*(x-y+2*z)); e
            Projective Conic Curve over Finite Field of size 7 defined by x^2 - y^2 + 3*x*z + y*z + 2*z^2
            sage: e.has_singular_point(point = True)
            (True, (2 : 4 : 1))

            sage: Conic([1, 1, -1]).has_singular_point()
            False
            sage: Conic([1, 1, -1]).has_singular_point(point = True)
            (False, None)

        ``has_singular_point`` is not implemented over all fields
        of characteristic `2`. It is implemented over finite fields.

        ::

            sage: F.<a> = FiniteField(8)
            sage: Conic([a, a+1, 1]).has_singular_point(point = True)
            (True, (a + 1 : 0 : 1))

            sage: P.<t> = GF(2)[]
            sage: C = Conic(P, [t,t,1]); C
            Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using NTL) defined by t*x^2 + t*y^2 + z^2
            sage: C.has_singular_point(point = False)
            Traceback (most recent call last):
            ...
            NotImplementedError: Sorry, find singular point on conics not implemented over all fields of characteristic 2.
        """
        if not point:
            ret = self.has_singular_point(point=True)
            return ret[0]
        B = self.base_ring()
        if B.characteristic() == 2:
            [a, b, c, d, e, f] = self.coefficients()
            if b == 0 and c == 0 and e == 0:
                for i in range(3):
                    if [a, d, f][i] == 0:
                        return True, self.point(vector(B, {2: 0, i: 1}))
                if hasattr(a / f, 'is_square') and hasattr(a / f, 'sqrt'):
                    if (a / f).is_square():
                        return True, self.point([1, 0, (a / f).sqrt()])
                    if (d / f).is_square():
                        return True, self.point([0, 1, (d / f).sqrt()])
                raise NotImplementedError, "Sorry, find singular point on conics not implemented over all fields of characteristic 2."
            pt = [e, c, b]
            if self.defining_polynomial()(pt) == 0:
                return True, self.point(pt)
            return False, None
        D = self.symmetric_matrix()
        if D.determinant() == 0:
            return True, self.point(Sequence(D.right_kernel().gen()))
        return False, None
Exemplo n.º 40
0
    def has_rational_point(self,
                           point=False,
                           algorithm='default',
                           read_cache=True):
        r"""
        Returns True if and only if the conic ``self``
        has a point over its base field `B`.

        If ``point`` is True, then returns a second output, which is
        a rational point if one exists.

        Points are cached whenever they are found. Cached information
        is used if and only if ``read_cache`` is True.

        ALGORITHM:

        The parameter ``algorithm`` specifies the algorithm
        to be used:

         - ``'default'`` -- If the base field is real or complex,
           use an elementary native Sage implementation.

         - ``'magma'`` (requires Magma to be installed) --
           delegates the task to the Magma computer algebra
           system.

        EXAMPLES::

            sage: Conic(RR, [1, 1, 1]).has_rational_point()
            False
            sage: Conic(CC, [1, 1, 1]).has_rational_point()
            True

            sage: Conic(RR, [1, 2, -3]).has_rational_point(point = True)
            (True, (1.73205080756888 : 0.000000000000000 : 1.00000000000000))

        Conics over polynomial rings can be solved internally::

            sage: R.<t> = QQ[]
            sage: C = Conic([-2,t^2+1,t^2-1])
            sage: C.has_rational_point()
            True

        And they can also be solved with Magma::

            sage: C.has_rational_point(algorithm='magma') # optional - magma
            True
            sage: C.has_rational_point(algorithm='magma', point=True) # optional - magma
            (True, (-t : 1 : 1))

            sage: D = Conic([t,1,t^2])
            sage: D.has_rational_point(algorithm='magma') # optional - magma
            False

        TESTS:

        One of the following fields comes with an embedding into the complex
        numbers, one does not. Check that they are both handled correctly by
        the Magma interface. ::

            sage: K.<i> = QuadraticField(-1)
            sage: K.coerce_embedding()
            Generic morphism:
              From: Number Field in i with defining polynomial x^2 + 1 with i = 1*I
              To:   Complex Lazy Field
              Defn: i -> 1*I
            sage: Conic(K, [1,1,1]).rational_point(algorithm='magma') # optional - magma
            (-i : 1 : 0)

            sage: x = QQ['x'].gen()
            sage: L.<i> = NumberField(x^2+1, embedding=None)
            sage: Conic(L, [1,1,1]).rational_point(algorithm='magma') # optional - magma
            (-i : 1 : 0)
            sage: L == K
            False
        """
        if read_cache:
            if self._rational_point is not None:
                if point:
                    return True, self._rational_point
                else:
                    return True

        B = self.base_ring()

        if algorithm == 'magma':
            from sage.interfaces.magma import magma
            M = magma(self)
            b = M.HasRationalPoint().sage()
            if not point:
                return b
            if not b:
                return False, None
            M_pt = M.HasRationalPoint(nvals=2)[1]

            # Various attempts will be made to convert `pt` to
            # a Sage object. The end result will always be checked
            # by self.point().

            pt = [M_pt[1], M_pt[2], M_pt[3]]

            # The first attempt is to use sequences. This is efficient and
            # succeeds in cases where the Magma interface fails to convert
            # number field elements, because embeddings between number fields
            # may be lost on conversion to and from Magma.
            # This should deal with all absolute number fields.
            try:
                return True, self.point([B(c.Eltseq().sage()) for c in pt])
            except TypeError:
                pass

            # The second attempt tries to split Magma elements into
            # numerators and denominators first. This is necessary
            # for the field of rational functions, because (at the moment of
            # writing) fraction field elements are not converted automatically
            # from Magma to Sage.
            try:
                return True, self.point( \
                  [B(c.Numerator().sage()/c.Denominator().sage()) for c in pt])
            except (TypeError, NameError):
                pass

            # Finally, let the Magma interface handle conversion.
            try:
                return True, self.point([B(c.sage()) for c in pt])
            except (TypeError, NameError):
                pass

            raise NotImplementedError(
                "No correct conversion implemented for converting the Magma point %s on %s to a correct Sage point on self (=%s)"
                % (M_pt, M, self))

        if algorithm != 'default':
            raise ValueError("Unknown algorithm: %s" % algorithm)

        if is_ComplexField(B):
            if point:
                [_, _, _, d, e, f] = self._coefficients
                if d == 0:
                    return True, self.point([0, 1, 0])
                return True, self.point(
                    [0, ((e**2 - 4 * d * f).sqrt() - e) / (2 * d), 1],
                    check=False)
            return True
        if is_RealField(B):
            D, T = self.diagonal_matrix()
            [a, b, c] = [D[0, 0], D[1, 1], D[2, 2]]
            if a == 0:
                ret = True, self.point(T * vector([1, 0, 0]), check=False)
            elif a * c <= 0:
                ret = True, self.point(T * vector([(-c / a).sqrt(), 0, 1]),
                                       check=False)
            elif b == 0:
                ret = True, self.point(T * vector([0, 1, 0]), check=False)
            elif b * c <= 0:
                ret = True, self.point(T * vector([0, (-c / b).sqrt(), 0, 1]),
                                       check=False)
            else:
                ret = False, None
            if point:
                return ret
            return ret[0]
        raise NotImplementedError("has_rational_point not implemented for " \
                                   "conics over base field %s" % B)
Exemplo n.º 41
0
    def to_surface(self, point, v=None, label=None, ring=None, return_all=False, \
                   singularity_limit=None, search_all = False, search_limit=None):
        r""" Converts from graphical coordinates to similarity surface coordinates.

        A point always must be provided. If a vector v is provided then a
        SimilaritySurfaceTangentVector will be returned. If v is not provided, then a
        SurfacePoint is returned.

        INPUT:

        - ``point`` -- Coordinates of a point in graphical coordinates to be
            converted to graphical coordinates.

        - ``v`` -- (default ``None``) If provided a tangent vector in graphical
            coordinates based at the provided point.

        - ``label`` -- (default ``None``) If provided, then we only convert
            points and tangent vectors in the corresponding graphical polygon.

        - ``ring`` -- (default ``None``) If provided, then objects returned
            will be defined over the given ring, otherwise we use the base_ring
            of the surface.

        - ``return_all`` -- (default ``False``) By default we return the first
            point or vector we find. However if the graphical polygons overlap,
            then a point or vector might correspond to more than one point or
            vector on the surface. If ``return_all`` is set to ``True`` then we
            return a set of all points we find instead.

        - ``singularity_limit`` -- (default ``None``) This only has an effect
            if returning a singular point (i.e., ``v`` is ``None``) and the
            surface is infinite. In this case, the singularity should be
            returned but it could be infinite. Then singularity_limit controls
            how far we look for the singularity to close. This value is passed
            to ``SimilaritySurface.surface_point``.

        - ``search_all`` -- (default ``False``) By default we look just in
            polygons with visible label. If set to `True``, then we instead
            look in all labels.

        - ``search_limit`` -- (default ``None``) If ``search_all`` is ``True``,
            then we look at the first ``search_limit`` polygons instead of all
            polygons. This must be set to an positive integer if ``search_all``
            is and the surface is infinite.

        EXAMPLES::

            sage: from flatsurf import *
            sage: s = similarity_surfaces.example()
            sage: gs = s.graphical_surface()
            sage: gs.to_surface((1,-2))
            Surface point located at (1, 1/2) in polygon 1
            sage: gs.to_surface((1,-2), v=(1,0))
            SimilaritySurfaceTangentVector in polygon 1 based at (1, 1/2) with vector (1, -1/2)

            sage: s = translation_surfaces.infinite_staircase()
            sage: gs = s.graphical_surface()
            sage: gs.to_surface((4,4), (1,1), search_all=True, search_limit=20)
            SimilaritySurfaceTangentVector in polygon 8 based at (0, 0) with vector (1, 1)

            sage: s = translation_surfaces.square_torus()
            sage: pc = s.minimal_cover(cover_type="planar")
            sage: gs = pc.graphical_surface()
            sage: gs.to_surface((3,2), search_all=True, search_limit=20)
            Traceback (most recent call last):
            ...
            ValueError: To obtain a singularity on an infinite surface, singularity_limit must be set.
            sage: gs.to_surface((3,2), search_all=True, search_limit=20, singularity_limit=4)
            Surface point with 4 coordinate representations
            sage: p = gs.to_surface((sqrt(3),sqrt(2)), ring=AA, search_all=True, search_limit=20)
            sage: next(iter(p.coordinates(p.labels()[0]))).parent()
            Vector space of dimension 2 over Algebraic Real Field
            sage: v = gs.to_surface((3/2,3/2),(sqrt(3),sqrt(2)),ring=AA,search_all=True, search_limit=20)
            sage: v.bundle()
            Tangent bundle of TranslationSurface built from infinitely many polygons defined over Algebraic Real Field
        """
        if label is None:
            if return_all:
                ret = set()
            s = self.get_surface()
            if search_all:
                if search_limit is None:
                    if s.is_finite():
                        it = s.label_iterator()
                    else:
                        raise ValueError(
                            "If search_all=True and the surface is infinite, then a search_limit must be provided."
                        )
                else:
                    from itertools import islice
                    it = islice(s.label_iterator(), search_limit)
            else:
                it = self.visible()
            for label in it:
                try:
                    val = self.to_surface(point,
                                          v=v,
                                          label=label,
                                          ring=ring,
                                          singularity_limit=singularity_limit)
                    if return_all:
                        ret.add(val)
                    else:
                        return val
                except AssertionError:
                    # Not in the polygon
                    pass
                except ValueError as e:
                    if e.args[
                            0] == 'need a limit when working with an infinite surface':
                        raise ValueError("To obtain a singularity on an infinite surface, " + \
                            "singularity_limit must be set.")
                    # Otherwise it is not in the polygon.
            if return_all:
                return ret
            else:
                raise ValueError(
                    "Point or vector is not in a visible graphical_polygon.")
        else:
            gp = self.graphical_polygon(label)
            coords = gp.transform_back(point)
            s = self.get_surface()
            if v is None:
                return s.surface_point(label,
                                       coords,
                                       ring=ring,
                                       limit=singularity_limit)
            else:
                return s.tangent_vector(
                    label,
                    coords, (~(gp.transformation().derivative())) * vector(v),
                    ring=ring)
Exemplo n.º 42
0
def skew_hadamard_matrix(n, existence=False, skew_normalize=True, check=True):
    r"""
    Tries to construct a skew Hadamard matrix

    A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix
    and `-S=S^\top`. Currently constructions from Section 14.1 of [Ha83]_ and few
    more exotic ones are implemented.

    INPUT:

    - ``n`` (integer) -- dimension of the matrix

    - ``existence`` (boolean) -- whether to build the matrix or merely query if
      a construction is available in Sage. When set to ``True``, the function
      returns:

        - ``True`` -- meaning that Sage knows how to build the matrix

        - ``Unknown`` -- meaning that Sage does not know how to build the
          matrix, but that the design may exist (see :mod:`sage.misc.unknown`).

        - ``False`` -- meaning that the matrix does not exist.

    - ``skew_normalize`` (boolean) -- whether to make the 1st row all-one, and
      adjust the 1st column accordingly. Set to ``True`` by default.

    - ``check`` (boolean) -- whether to check that output is correct before
      returning it. As this is expected to be useless (but we are cautious
      guys), you may want to disable it whenever you want speed. Set to ``True``
      by default.

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix
        sage: skew_hadamard_matrix(12).det()
        2985984
        sage: 12^6
        2985984
        sage: skew_hadamard_matrix(1)
        [1]
        sage: skew_hadamard_matrix(2)
        [ 1  1]
        [-1  1]

    TESTS::

        sage: skew_hadamard_matrix(10,existence=True)
        False
        sage: skew_hadamard_matrix(12,existence=True)
        True
        sage: skew_hadamard_matrix(784,existence=True)
        True
        sage: skew_hadamard_matrix(10)
        Traceback (most recent call last):
        ...
        ValueError: A skew Hadamard matrix of order 10 does not exist
        sage: skew_hadamard_matrix(36)
        36 x 36 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(36)==skew_hadamard_matrix(36,skew_normalize=False)
        False
        sage: skew_hadamard_matrix(52)
        52 x 52 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(92)
        92 x 92 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(816)     # long time
        816 x 816 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(100)
        Traceback (most recent call last):
        ...
        ValueError: A skew Hadamard matrix of order 100 is not yet implemented.
        sage: skew_hadamard_matrix(100,existence=True)
        Unknown

    REFERENCES:

    .. [Ha83] \M. Hall,
      Combinatorial Theory,
      2nd edition,
      Wiley, 1983
    """
    def true():
        _skew_had_cache[n] = True
        return True

    M = None
    if existence and n in _skew_had_cache:
        return True
    if not (n % 4 == 0) and (n > 2):
        if existence:
            return False
        raise ValueError("A skew Hadamard matrix of order %s does not exist" %
                         n)
    if n == 2:
        if existence:
            return true()
        M = matrix([[1, 1], [-1, 1]])
    elif n == 1:
        if existence:
            return true()
        M = matrix([1])
    elif is_prime_power(n - 1) and ((n - 1) % 4 == 3):
        if existence:
            return true()
        M = hadamard_matrix_paleyI(n, normalize=False)

    elif n % 8 == 0:
        if skew_hadamard_matrix(n // 2,
                                existence=True):  # (Lemma 14.1.6 in [Ha83]_)
            if existence:
                return true()
            H = skew_hadamard_matrix(n // 2, check=False)
            M = block_matrix([[H, H], [-H.T, H.T]])

        else:  # try Williamson construction (Lemma 14.1.5 in [Ha83]_)
            for d in divisors(n)[2:-2]:  # skip 1, 2, n/2, and n
                n1 = n // d
                if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\
                    and skew_hadamard_matrix(n1,existence=True):
                    if existence:
                        return true()
                    H = skew_hadamard_matrix(n1, check=False) - I(n1)
                    U = matrix(ZZ, d, lambda i, j: -1 if i==j==0 else\
                                        1 if i==j==1 or (i>1 and j-1==d-i)\
                                          else 0)
                    A = block_matrix(
                        [[matrix([0]),
                          matrix(ZZ, 1, d - 1, [1] * (d - 1))],
                         [
                             matrix(ZZ, d - 1, 1, [-1] * (d - 1)),
                             _helper_payley_matrix(d - 1, zero_position=0)
                         ]]) + I(d)
                    M = A.tensor_product(I(n1)) + (U * A).tensor_product(H)
                    break
    if M is None:  # try Williamson-Goethals-Seidel construction
        if GS_skew_hadamard_smallcases(n, existence=True):
            if existence:
                return true()
            M = GS_skew_hadamard_smallcases(n)

        else:
            if existence:
                return Unknown
            raise ValueError(
                "A skew Hadamard matrix of order %s is not yet implemented." %
                n)
    if skew_normalize:
        dd = diagonal_matrix(M[0])
        M = dd * M * dd
    if check:
        assert is_hadamard_matrix(M, normalized=False, skew=True)
        if skew_normalize:
            from sage.modules.free_module_element import vector
            assert M[0] == vector([1] * n)
    _skew_had_cache[n] = True
    return M
Exemplo n.º 43
0
    def hom(self, x, Y=None):
        r"""
        Return the scheme morphism from ``self`` to ``Y`` defined by ``x``.
        Here ``x`` can be a matrix or a sequence of polynomials.
        If ``Y`` is omitted, then a natural image is found if possible.

        EXAMPLES:

        Here are a few Morphisms given by matrices. In the first
        example, ``Y`` is omitted, in the second example, ``Y`` is specified.

        ::

            sage: c = Conic([-1, 1, 1])
            sage: h = c.hom(Matrix([[1,1,0],[0,1,0],[0,0,1]])); h
            Scheme morphism:
              From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2
              To:   Projective Conic Curve over Rational Field defined by -x^2 + 2*x*y + z^2
              Defn: Defined on coordinates by sending (x : y : z) to
                    (x + y : y : z)
            sage: h([-1, 1, 0])
            (0 : 1 : 0)

            sage: c = Conic([-1, 1, 1])
            sage: d = Conic([4, 1, -1])
            sage: c.hom(Matrix([[0, 0, 1/2], [0, 1, 0], [1, 0, 0]]), d)
            Scheme morphism:
              From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2
              To:   Projective Conic Curve over Rational Field defined by 4*x^2 + y^2 - z^2
              Defn: Defined on coordinates by sending (x : y : z) to
                    (1/2*z : y : x)

        ``ValueError`` is raised if the wrong codomain ``Y`` is specified:

        ::

            sage: c = Conic([-1, 1, 1])
            sage: c.hom(Matrix([[0, 0, 1/2], [0, 1, 0], [1, 0, 0]]), c)
            Traceback (most recent call last):
            ...
            ValueError: The matrix x (= [  0   0 1/2]
            [  0   1   0]
            [  1   0   0]) does not define a map from self (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2) to Y (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2)
        """
        if is_Matrix(x):
            from constructor import Conic
            y = x.inverse()
            A = y.transpose() * self.matrix() * y
            im = Conic(A)
            if Y == None:
                Y = im
            else:
                q = Y.defining_polynomial() / im.defining_polynomial()
                if not (q.numerator().is_constant()
                        and q.denominator().is_constant()):
                    raise ValueError, "The matrix x (= %s) does not define a " \
                                      "map from self (= %s) to Y (= %s)" % \
                                      (x, self, Y)
            x = Sequence(x * vector(self.ambient_space().gens()))
            return self.Hom(Y)(x, check=False)
        return ProjectiveCurve_generic.hom(self, x, Y)
Exemplo n.º 44
0
def minimize_constrained(func,
                         cons,
                         x0,
                         gradient=None,
                         algorithm='default',
                         **args):
    r"""
    Minimize a function with constraints.

    INPUT:

    - ``func`` -- Either a symbolic function, or a Python function whose
      argument is a tuple with n components

    - ``cons`` -- constraints. This should be either a function or list of
      functions that must be positive. Alternatively, the constraints can
      be specified as a list of intervals that define the region we are
      minimizing in. If the constraints are specified as functions, the
      functions should be functions of a tuple with `n` components
      (assuming `n` variables). If the constraints are specified as a list
      of intervals and there are no constraints for a given variable, that
      component can be (``None``, ``None``).

    - ``x0`` -- Initial point for finding minimum

    - ``algorithm`` -- Optional, specify the algorithm to use:

      - ``'default'``  -- default choices

      - ``'l-bfgs-b'`` -- only effective if you specify bound constraints.
        See [ZBN97]_.

    - ``gradient`` -- Optional gradient function. This will be computed
      automatically for symbolic functions. This is only used when the
      constraints are specified as a list of intervals.

    EXAMPLES:

    Let us maximize `x + y - 50` subject to the following constraints:
    `50x + 24y \leq 2400`, `30x + 33y \leq 2100`, `x \geq 45`,
    and `y \geq 5`::

        sage: y = var('y')
        sage: f = lambda p: -p[0]-p[1]+50
        sage: c_1 = lambda p: p[0]-45
        sage: c_2 = lambda p: p[1]-5
        sage: c_3 = lambda p: -50*p[0]-24*p[1]+2400
        sage: c_4 = lambda p: -30*p[0]-33*p[1]+2100
        sage: a = minimize_constrained(f,[c_1,c_2,c_3,c_4],[2,3])
        sage: a
        (45.0, 6.25)

    Let's find a minimum of `\sin(xy)`::

        sage: x,y = var('x y')
        sage: f = sin(x*y)
        sage: minimize_constrained(f, [(None,None),(4,10)],[5,5])
        (4.8..., 4.8...)

    Check, if L-BFGS-B finds the same minimum::

        sage: minimize_constrained(f, [(None,None),(4,10)],[5,5], algorithm='l-bfgs-b')
        (4.7..., 4.9...)

    Rosenbrock function, [http://en.wikipedia.org/wiki/Rosenbrock_function]::

        sage: from scipy.optimize import rosen, rosen_der
        sage: minimize_constrained(rosen, [(-50,-10),(5,10)],[1,1],gradient=rosen_der,algorithm='l-bfgs-b')
        (-10.0, 10.0)
        sage: minimize_constrained(rosen, [(-50,-10),(5,10)],[1,1],algorithm='l-bfgs-b')
        (-10.0, 10.0)

    REFERENCES:

    .. [ZBN97] C. Zhu, R. H. Byrd and J. Nocedal. L-BFGS-B: Algorithm 778:
      L-BFGS-B, FORTRAN routines for large scale bound constrained
      optimization. ACM Transactions on Mathematical Software, Vol 23, Num. 4,
      pp.550--560, 1997.
    """
    from sage.symbolic.expression import Expression
    import scipy
    from scipy import optimize
    function_type = type(lambda x, y: x + y)

    if isinstance(func, Expression):
        var_list = func.variables()
        var_names = map(str, var_list)
        fast_f = func._fast_float_(*var_names)
        f = lambda p: fast_f(*p)
        gradient_list = func.gradient()
        fast_gradient_functions = [
            gradient_list[i]._fast_float_(*var_names)
            for i in xrange(len(gradient_list))
        ]
        gradient = lambda p: scipy.array(
            [a(*p) for a in fast_gradient_functions])
    else:
        f = func

    if isinstance(cons, list):
        if isinstance(cons[0], tuple) or isinstance(cons[0],
                                                    list) or cons[0] == None:
            if gradient != None:
                if algorithm == 'l-bfgs-b':
                    min = optimize.fmin_l_bfgs_b(f,
                                                 x0,
                                                 gradient,
                                                 bounds=cons,
                                                 iprint=-1,
                                                 **args)[0]
                else:
                    min = optimize.fmin_tnc(f,
                                            x0,
                                            gradient,
                                            bounds=cons,
                                            messages=0,
                                            **args)[0]
            else:
                if algorithm == 'l-bfgs-b':
                    min = optimize.fmin_l_bfgs_b(f,
                                                 x0,
                                                 approx_grad=True,
                                                 bounds=cons,
                                                 iprint=-1,
                                                 **args)[0]
                else:
                    min = optimize.fmin_tnc(f,
                                            x0,
                                            approx_grad=True,
                                            bounds=cons,
                                            messages=0,
                                            **args)[0]

        elif isinstance(cons[0], function_type):
            min = optimize.fmin_cobyla(f, x0, cons, iprint=0, **args)
    elif isinstance(cons, function_type):
        min = optimize.fmin_cobyla(f, x0, cons, iprint=0, **args)
    return vector(RDF, min)
Exemplo n.º 45
0
    def __call__(self, v):
        """
        Apply the affine transformation to ``v``.

        INPUT:

        - ``v`` -- a polynomial, a multivariate polynomial, a polyhedron, a
          vector, or anything that can be converted into a vector.

        OUTPUT:

        The image of ``v`` under the affine group element.

        EXAMPLES::

            sage: G = AffineGroup(2, QQ)
            sage: g = G([0,1,-1,0],[2,3]);  g
                  [ 0  1]     [2]
            x |-> [-1  0] x + [3]
            sage: v = vector([4,5])
            sage: g(v)
            (7, -1)

            sage: R.<x,y> = QQ[]
            sage: g(x), g(y)
            (y + 2, -x + 3)
            sage: p = x^2 + 2*x*y + y + 1
            sage: g(p)
            -2*x*y + y^2 - 5*x + 10*y + 20

        The action on polynomials is such that it intertwines with
        evaluation. That is::

            sage: p(*g(v)) == g(p)(*v)
            True

        Test that the univariate polynomial ring is covered::

            sage: H = AffineGroup(1, QQ)
            sage: h = H([2],[3]);  h
            x |-> [2] x + [3]
            sage: R.<z> = QQ[]
            sage: h(z+1)
            3*z + 2

        The action on a polyhedron is defined (see :trac:`30327`)::

            sage: F = AffineGroup(3, QQ)
            sage: M = matrix(3, [-1, -2, 0, 0, 0, 1, -2, 1, -1])
            sage: v = vector(QQ,(1,2,3))
            sage: f = F(M, v)
            sage: cube = polytopes.cube()
            sage: f(cube)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices

        """
        parent = self.parent()

        # start with the most probable case, i.e., v is in the vector space
        if v in parent.vector_space():
            return self._A * v + self._b

        from sage.rings.polynomial.polynomial_element import is_Polynomial
        if is_Polynomial(v) and parent.degree() == 1:
            ring = v.parent()
            return ring([self._A[0, 0], self._b[0]])

        from sage.rings.polynomial.multi_polynomial import is_MPolynomial
        if is_MPolynomial(v) and parent.degree() == v.parent().ngens():
            ring = v.parent()
            from sage.modules.free_module_element import vector
            image_coords = self._A * vector(ring, ring.gens()) + self._b
            return v(*image_coords)

        import sage.geometry.abc
        if isinstance(v, sage.geometry.abc.Polyhedron):
            return self._A * v + self._b

        # otherwise, coerce v into the vector space
        v = parent.vector_space()(v)
        return self._A * v + self._b
Exemplo n.º 46
0
    def reynolds_operator(self, poly, chi=None):
        r"""
        Compute the Reynolds operator of this finite group `G`.

        This is the projection from a polynomial ring to the ring of
        relative invariants [Stu1993]_. If possible, the invariant is
        returned defined over the base field of the given polynomial
        ``poly``, otherwise, it is returned over the compositum of the
        fields involved in the computation.
        Only implemented for absolute fields.

        ALGORITHM:

        Let `K[x]` be a polynomial ring and `\chi` a linear character for `G`. Let

        .. MATH:

            K[x]^G_{\chi} = \{f \in K[x] | \pi f = \chi(\pi) f \forall \pi\in G\}

        be the ring of invarants of `G` relative to `\chi`. Then the Reynold's operator
        is a map `R` from `K[x]` into `K[x]^G_{\chi}` defined by

        .. MATH:

            f \mapsto \frac{1}{|G|} \sum_{ \pi \in G} \chi(\pi) f.

        INPUT:

        - ``poly`` -- a polynomial

        - ``chi`` -- (default: trivial character) a linear group character of this group

        OUTPUT: an invariant polynomial relative to `\chi`

        AUTHORS:

        Rebecca Lauren Miller and Ben Hutz

        EXAMPLES::

            sage: S3 = MatrixGroup(SymmetricGroup(3))
            sage: R.<x,y,z> = QQ[]
            sage: f = x*y*z^3
            sage: S3.reynolds_operator(f)
            1/3*x^3*y*z + 1/3*x*y^3*z + 1/3*x*y*z^3

        ::

            sage: G = MatrixGroup(CyclicPermutationGroup(4))
            sage: chi = G.character(G.character_table()[3])
            sage: K.<v> = CyclotomicField(4)
            sage: R.<x,y,z,w> = K[]
            sage: G.reynolds_operator(x, chi)
            1/4*x + (1/4*v)*y - 1/4*z + (-1/4*v)*w
            sage: chi = G.character(G.character_table()[2])
            sage: R.<x,y,z,w> = QQ[]
            sage: G.reynolds_operator(x*y, chi)
            1/4*x*y + (-1/4*zeta4)*y*z + (1/4*zeta4)*x*w - 1/4*z*w

        ::

            sage: K.<i> = CyclotomicField(4)
            sage: G =  MatrixGroup(CyclicPermutationGroup(3))
            sage: chi = G.character(G.character_table()[1])
            sage: R.<x,y,z> = K[]
            sage: G.reynolds_operator(x*y^5, chi)
            1/3*x*y^5 + (2/3*izeta3^3 + izeta3^2 + 8/3*izeta3 + 1)*x^5*z +
            (-2/3*izeta3^3 - izeta3^2 - 8/3*izeta3 - 4/3)*y*z^5
            sage: R.<x,y,z> = QQbar[]
            sage: G.reynolds_operator(x*y^5, chi)
            1/3*x*y^5 + (-0.1666666666666667? - 0.2886751345948129?*I)*x^5*z +
            (-0.1666666666666667? + 0.2886751345948129?*I)*y*z^5

        ::

            sage: K.<i> = CyclotomicField(4)
            sage: Tetra =  MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0])
            sage: chi = Tetra.character(Tetra.character_table()[4])
            sage: L.<v> = QuadraticField(-3)
            sage: R.<x,y> = L[]
            sage: Tetra.reynolds_operator(x^4)
            0
            sage: Tetra.reynolds_operator(x^4, chi)
            1/4*x^4 + (1/2*v)*x^2*y^2 + 1/4*y^4
            sage: R.<x>=L[]
            sage: LL.<w> = L.extension(x^2+v)
            sage: R.<x,y> = LL[]
            sage: Tetra.reynolds_operator(x^4, chi)
            Traceback (most recent call last):
            ...
            NotImplementedError: only implemented for absolute fields

        ::

            sage: G =  MatrixGroup(DihedralGroup(4))
            sage: chi = G.character(G.character_table()[1])
            sage: R.<x,y> = QQ[]
            sage: f = x^4
            sage: G.reynolds_operator(f, chi)
            Traceback (most recent call last):
            ...
            TypeError: number of variables in polynomial must match size of matrices
            sage: R.<x,y,z,w> = QQ[]
            sage: f = x^3*y
            sage: G.reynolds_operator(f, chi)
            1/8*x^3*y - 1/8*x*y^3 + 1/8*y^3*z - 1/8*y*z^3 - 1/8*x^3*w + 1/8*z^3*w +
            1/8*x*w^3 - 1/8*z*w^3

        Characteristic p>0 examples::

            sage: G = MatrixGroup([[0,1,1,0]])
            sage: R.<w,x> = GF(2)[]
            sage: G.reynolds_operator(x)
            Traceback (most recent call last):
            ...
            NotImplementedError: not implemented when characteristic divides group order

        ::

            sage: i = GF(7)(3)
            sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]])
            sage: chi = G.character(G.character_table()[4])
            sage: R.<w,x> = GF(7)[]
            sage: f = w^5*x + x^6
            sage: G.reynolds_operator(f, chi)
            Traceback (most recent call last):
            ...
            NotImplementedError: nontrivial characters not implemented for characteristic > 0
            sage: G.reynolds_operator(f)
            x^6

        ::

            sage: K = GF(3^2,'t')
            sage: G = MatrixGroup([matrix(K,2,2, [0,K.gen(),1,0])])
            sage: R.<x,y> = GF(3)[]
            sage: G.reynolds_operator(x^8)
            -x^8 - y^8

        ::

            sage: K = GF(3^2,'t')
            sage: G = MatrixGroup([matrix(GF(3),2,2, [0,1,1,0])])
            sage: R.<x,y> = K[]
            sage: f = -K.gen()*x
            sage: G.reynolds_operator(f)
            (t)*x + (t)*y
        """
        if poly.parent().ngens() != self.degree():
            raise TypeError(
                "number of variables in polynomial must match size of matrices"
            )
        R = FractionField(poly.base_ring())
        C = FractionField(self.base_ring())
        if chi is None:  #then this is the trivial character
            if R.characteristic() == 0:
                #non-modular case
                if C == QQbar or R == QQbar:
                    L = QQbar
                elif not C.is_absolute() or not R.is_absolute():
                    raise NotImplementedError(
                        "only implemented for absolute fields")
                else:  #create the compositum
                    if C.absolute_degree() == 1:
                        L = R
                    elif R.absolute_degree() == 1:
                        L = C
                    else:
                        L = C.composite_fields(R)[0]
            elif not R.characteristic().divides(self.order()):
                if R.characteristic() != C.characteristic():
                    raise ValueError(
                        "base fields must have same characteristic")
                else:
                    if R.degree() >= C.degree():
                        L = R
                    else:
                        L = C
            else:
                raise NotImplementedError(
                    "not implemented when characteristic divides group order")
            poly = poly.change_ring(L)
            poly_gens = vector(poly.parent().gens())
            F = L.zero()
            for g in self:
                F += poly(*g.matrix() * vector(poly.parent().gens()))
            F /= self.order()
            return F
        #non-trivial character case
        K = chi.values()[0].parent()
        if R.characteristic() == 0:
            #extend base_ring to compositum
            if C == QQbar or K == QQbar or R == QQbar:
                L = QQbar
            elif not C.is_absolute() or not K.is_absolute(
            ) or not R.is_absolute():
                raise NotImplementedError(
                    "only implemented for absolute fields")
            else:
                fields = []
                for M in [R, K, C]:
                    if M.absolute_degree() != 1:
                        fields.append(M)
                l = len(fields)
                if l == 0:
                    # all are QQ
                    L = R
                elif l == 1:
                    #only one is an extension
                    L = fields[0]
                elif l == 2:
                    #only two are extensions
                    L = fields[0].composite_fields(fields[1])[0]
                else:
                    #all three are extensions
                    L1 = fields[0].composite_fields(fields[1])[0]
                    L = L1.composite_fields(fields[2])[0]
        else:
            raise NotImplementedError(
                "nontrivial characters not implemented for characteristic > 0")
        poly = poly.change_ring(L)
        poly_gens = vector(poly.parent().gens())
        F = L.zero()
        for g in self:
            F += L(chi(g)) * poly(*g.matrix().change_ring(L) * poly_gens)
        F /= self.order()
        try:  # attempt to move F to base_ring of polyomial
            F = F.change_ring(R)
        except (TypeError, ValueError):
            pass
        return F
Exemplo n.º 47
0
def repr_pretty(coefficients,
                type,
                prefix='x',
                indices=None,
                latex=False,
                style='>=',
                split=False):
    r"""
    Return a pretty representation of equation/inequality represented
    by the coefficients.

    INPUT:

    - ``coefficients`` -- a tuple or other iterable

    - ``type`` -- either ``0`` (``PolyhedronRepresentation.INEQUALITY``)
      or ``1`` (``PolyhedronRepresentation.EQUATION``)

    - ``prefix`` -- a string

    - ``indices`` -- a tuple or other iterable

    - ``latex`` -- a boolean

    - ``split`` -- a boolean; (Default: ``False``). If set to ``True``,
                   the output is split into a 3-tuple containing the left-hand side,
                   the relation, and the right-hand side of the object.

    - ``style`` -- either ``"positive"`` (making all coefficients positive), or
                   ``"<="`` or ``">="``.

    OUTPUT:

    A string or 3-tuple of strings (depending on ``split``).

    EXAMPLES::

        sage: from sage.geometry.polyhedron.representation import repr_pretty
        sage: from sage.geometry.polyhedron.representation import PolyhedronRepresentation
        sage: print(repr_pretty((0, 1, 0, 0), PolyhedronRepresentation.INEQUALITY))
        x0 >= 0
        sage: print(repr_pretty((1, 2, 1, 0), PolyhedronRepresentation.INEQUALITY))
        2*x0 + x1 >= -1
        sage: print(repr_pretty((1, -1, -1, 1), PolyhedronRepresentation.EQUATION))
        -x0 - x1 + x2 == -1
    """
    from sage.misc.latex import latex as latex_function
    from sage.modules.free_module_element import vector
    from sage.symbolic.ring import SR

    coeffs = vector(coefficients)
    if indices is None:
        indices = range(len(coeffs) - 1)
    vars = vector([1] + list(SR(prefix + '{}'.format(i)) for i in indices))
    f = latex_function if latex else repr
    if type == PolyhedronRepresentation.EQUATION:
        rel = '=' if latex else '=='
    elif type == PolyhedronRepresentation.INEQUALITY:
        if style == '<=':
            rel = r'\leq' if latex else '<='
        else:
            rel = r'\geq' if latex else '>='
    else:
        raise NotImplementedError(
            'no pretty printing available: wrong type {}'.format(type))

    if style == 'positive':
        pos_part = vector([max(c, 0) for c in coeffs])
        neg_part = pos_part - coeffs
        assert coeffs == pos_part - neg_part
        left_part = f(pos_part * vars)
        right_part = f(neg_part * vars)
    elif style == '>=':
        left_part = f(coeffs[1:] * vars[1:])
        right_part = f(-coeffs[0])
    elif style == '<=':
        left_part = f(-coeffs[1:] * vars[1:])
        right_part = f(coeffs[0])
    else:
        raise NotImplementedError(
            'no pretty printing available: wrong style {}'.format(style))

    if not split:
        return '{} {} {}'.format(left_part, rel, right_part)
    else:
        return (str(left_part), rel, str(right_part))
Exemplo n.º 48
0
def ruler(start,
          end,
          ticks=4,
          sub_ticks=4,
          absolute=False,
          snap=False,
          **kwds):
    """
    Draw a ruler in 3-D, with major and minor ticks.

    INPUT:

    - ``start`` -- the beginning of the ruler, as a list,
      tuple, or vector.

    - ``end`` -- the end of the ruler, as a list, tuple,
      or vector.

    - ``ticks`` -- (default: 4) the number of major ticks
      shown on the ruler.

    - ``sub_ticks`` -- (default: 4) the number of shown
      subdivisions between each major tick.

    - ``absolute`` -- (default: ``False``) if ``True``, makes a huge ruler
      in the direction of an axis.

    - ``snap`` -- (default: ``False``) if ``True``, snaps to an implied
      grid.

    EXAMPLES:

    A ruler::

        sage: from sage.plot.plot3d.shapes2 import ruler
        sage: R = ruler([1,2,3],vector([2,3,4])); R
        Graphics3d Object

    A ruler with some options::

        sage: R = ruler([1,2,3],vector([2,3,4]),ticks=6, sub_ticks=2, color='red'); R
        Graphics3d Object

    The keyword ``snap`` makes the ticks not necessarily coincide
    with the ruler::

        sage: ruler([1,2,3],vector([1,2,4]),snap=True)
        Graphics3d Object

    The keyword ``absolute`` makes a huge ruler in one of the axis
    directions::

        sage: ruler([1,2,3],vector([1,2,4]),absolute=True)
        Graphics3d Object

    TESTS::

        sage: ruler([1,2,3],vector([1,3,4]),absolute=True)
        Traceback (most recent call last):
        ...
        ValueError: Absolute rulers only valid for axis-aligned paths
    """
    start = vector(RDF, start)
    end = vector(RDF, end)
    dir = end - start
    dist = math.sqrt(dir.dot_product(dir))
    dir /= dist

    one_tick = dist / ticks * 1.414
    unit = 10**math.floor(math.log(dist / ticks, 10))
    if unit * 5 < one_tick:
        unit *= 5
    elif unit * 2 < one_tick:
        unit *= 2

    if dir[0]:
        tick = dir.cross_product(vector(RDF, (0, 0, -dist / 30)))
    elif dir[1]:
        tick = dir.cross_product(vector(RDF, (0, 0, dist / 30)))
    else:
        tick = vector(RDF, (dist / 30, 0, 0))

    if snap:
        for i in range(3):
            start[i] = unit * math.floor(start[i] / unit + 1e-5)
            end[i] = unit * math.ceil(end[i] / unit - 1e-5)

    if absolute:
        if dir[0] * dir[1] or dir[1] * dir[2] or dir[0] * dir[2]:
            raise ValueError(
                "Absolute rulers only valid for axis-aligned paths")
        m = max(dir[0], dir[1], dir[2])
        if dir[0] == m:
            off = start[0]
        elif dir[1] == m:
            off = start[1]
        else:
            off = start[2]
        first_tick = unit * math.ceil(off / unit - 1e-5) - off
    else:
        off = 0
        first_tick = 0

    ruler = shapes.LineSegment(start, end, **kwds)
    for k in range(1, int(sub_ticks * first_tick / unit)):
        P = start + dir * (k * unit / sub_ticks)
        ruler += shapes.LineSegment(P, P + tick / 2, **kwds)
    for d in srange(first_tick, dist + unit / (sub_ticks + 1), unit):
        P = start + dir * d
        ruler += shapes.LineSegment(P, P + tick, **kwds)
        ruler += shapes.Text(str(d + off), **kwds).translate(P - tick)
        if dist - d < unit:
            sub_ticks = int(sub_ticks * (dist - d) / unit)
        for k in range(1, sub_ticks):
            P += dir * (unit / sub_ticks)
            ruler += shapes.LineSegment(P, P + tick / 2, **kwds)
    return ruler
Exemplo n.º 49
0
    def _element_constructor_(self, x, check=True):
        r"""
        Defines coercions and conversions.

        INPUT:

        - ``x`` -- an element of this group, a GAP element

        EXAMPLES::

            sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap
            sage: G = AbelianGroupGap([2,3])
            sage: A = AbelianGroup([2,3])
            sage: a = A.an_element()
            sage: a
            f0*f1
            sage: G(a)
            f1*f2
            sage: A = AdditiveAbelianGroup([2,3])
            sage: a = A.an_element()
            sage: a
            (1, 0)
            sage: G(a)
            f1

        For general ``fgp_modules`` conversion is implemented if our
        group is in Smith form::

            sage: G = AbelianGroupGap([6])
            sage: A = ZZ^2
            sage: e0,e1 = A.gens()
            sage: A = A / A.submodule([2*e0, 3*e1])
            sage: a = 2 * A.an_element()
            sage: a
            (2)
            sage: G(a)
            f2
        """
        if isinstance(x, AbelianGroupElement_gap):
            x = x.gap()
        elif x == 1 or x == ():
            x = self.gap().Identity()
        elif not isinstance(x, GapElement):
            from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
            from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroupElement
            from sage.modules.fg_pid.fgp_element import FGP_Element
            if isinstance(x, AbelianGroupElement):
                exp = x.exponents()
            elif isinstance(x, AdditiveAbelianGroupElement):
                exp = x._hermite_lift()
            elif isinstance(x, FGP_Element):
                exp = x.vector()
            else:
                from sage.modules.free_module_element import vector
                exp = vector(ZZ, x)
            # turn the exponents into a gap element
            gens_gap = self.gens()
            if len(exp) != len(gens_gap):
                raise ValueError(
                    "input does not match the number of generators")
            x = gens_gap[0]**0
            for i in range(len(exp)):
                x *= gens_gap[i]**exp[i]
            x = x.gap()
        return self.element_class(self, x, check=check)
Exemplo n.º 50
0
def bezier3d(path, **options):
    """
    Draw a 3-dimensional bezier path.

    Input is similar to bezier_path, but each point in the path and
    each control point is required to have 3 coordinates.

    INPUT:

    -  ``path`` -- a list of curves, which each is a list of points. See further
        detail below.

    -  ``thickness`` -- (default: 2)

    - ``color`` -- a string (``"red"``, ``"green"`` etc)
      or a tuple (r, g, b) with r, g, b numbers between 0 and 1

    -  ``opacity`` -- (default: 1) if less than 1 then is
       transparent

    -  ``aspect_ratio`` -- (default:[1,1,1])

    The path is a list of curves, and each curve is a list of points.
    Each point is a tuple (x,y,z).

    The first curve contains the endpoints as the first and last point
    in the list.  All other curves assume a starting point given by the
    last entry in the preceding list, and take the last point in the list
    as their opposite endpoint.  A curve can have 0, 1 or 2 control points
    listed between the endpoints.  In the input example for path below,
    the first and second curves have 2 control points, the third has one,
    and the fourth has no control points::

        path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5], ...]

    In the case of no control points, a straight line will be drawn
    between the two endpoints.  If one control point is supplied, then
    the curve at each of the endpoints will be tangent to the line from
    that endpoint to the control point.  Similarly, in the case of two
    control points, at each endpoint the curve will be tangent to the line
    connecting that endpoint with the control point immediately after or
    immediately preceding it in the list.

    So in our example above, the curve between p1 and p2 is tangent to the
    line through p1 and c1 at p1, and tangent to the line through p2 and c2
    at p2.  Similarly, the curve between p2 and p3 is tangent to line(p2,c3)
    at p2 and tangent to line(p3,c4) at p3.  Curve(p3,p4) is tangent to
    line(p3,c5) at p3 and tangent to line(p4,c5) at p4.  Curve(p4,p5) is a
    straight line.

    EXAMPLES::

        sage: path = [[(0,0,0),(.5,.1,.2),(.75,3,-1),(1,1,0)],[(.5,1,.2),(1,.5,0)],[(.7,.2,.5)]]
        sage: b = bezier3d(path, color='green')
        sage: b
        Graphics3d Object

    To construct a simple curve, create a list containing a single list::

        sage: path = [[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]]
        sage: curve = bezier3d(path, thickness=5, color='blue')
        sage: curve
        Graphics3d Object

    TESTS:

    Check for :trac:`31640`::

        sage: p2d = [[(3,0.0),(3,0.13),(2,0.2),(2,0.3)], [(2.7,0.4),(2.6,0.5),(2.5,0.5)], [(2.3,0.5),(2.2,0.4),(2.1,0.3)]]
        sage: bp = bezier_path(p2d)
        sage: bp.plot3d()
        Graphics3d Object

        sage: p3d = p3d = [[(3,0,0),(3,0.1,0),(2.9,0.2,0),(2.8,0.3,0)], [(2.7,0.4,0),(2,0.5,0),(2.5,0.5,0)], [(2.3,0.5,0),(2.2,0.4,0),(2.1,0.3,0)]]
        sage: bezier3d(p3d)
        Graphics3d Object
    """
    from . import parametric_plot3d as P3D
    from sage.modules.free_module_element import vector
    from sage.symbolic.ring import SR

    p0 = vector(path[0][-1])
    t = SR.var('t')
    if len(path[0]) > 2:
        B = (1 - t)**3 * vector(path[0][0]) + 3 * t * (1 - t)**2 * vector(
            path[0][1]) + 3 * t**2 * (1 - t) * vector(path[0][-2]) + t**3 * p0
        G = P3D.parametric_plot3d(list(B), (0, 1),
                                  color=options['color'],
                                  aspect_ratio=options['aspect_ratio'],
                                  thickness=options['thickness'],
                                  opacity=options['opacity'])
    else:
        G = line3d([path[0][0], p0],
                   color=options['color'],
                   thickness=options['thickness'],
                   opacity=options['opacity'])

    for curve in path[1:]:
        if len(curve) > 1:
            p1 = vector(curve[0])
            p2 = vector(curve[-2])
            p3 = vector(curve[-1])
            B = (1 - t)**3 * p0 + 3 * t * (1 - t)**2 * p1 + 3 * t**2 * (
                1 - t) * p2 + t**3 * p3
            G += P3D.parametric_plot3d(list(B), (0, 1),
                                       color=options['color'],
                                       aspect_ratio=options['aspect_ratio'],
                                       thickness=options['thickness'],
                                       opacity=options['opacity'])
        else:
            G += line3d([p0, curve[0]],
                        color=options['color'],
                        thickness=options['thickness'],
                        opacity=options['opacity'])
        p0 = vector(curve[-1])
    return G
Exemplo n.º 51
0
def series_sum_regular(Intervals, dop, bwrec, ini, pt, stop, stride):
    r"""
    Sum a (logarithmic) series solution of an operator that may have a regular
    singular point at the origin.

    TESTS::

        sage: from ore_algebra import *
        sage: from ore_algebra.analytic.naive_sum import *
        sage: Dops, x, Dx = DifferentialOperators()

    Test that we correctly compute solutions of large valuations, and that when
    there are several solutions with very different valuations, we can stop
    before reaching the largest one if the initial values there are zero.
    (Unfortunately, the bounds in this kind of situation are currently so
    pessimistic that this ability rarely helps in practice!) ::

        sage: #dop = (Dx-1).lclm(x*Dx-1000)
        sage: dop = (x^2-1000*x)*Dx^2 + (-x^2+999000)*Dx + 1000*x - 999000
        sage: logger = logging.getLogger('ore_algebra.analytic.naive_sum')
        sage: logger.setLevel(logging.INFO) # TBI
        sage: dop.numerical_transition_matrix([0,1/10000000])
        INFO:ore_algebra.analytic.naive_sum:...
        INFO:ore_algebra.analytic.naive_sum:summed 50 terms, ...
        [ [1.000000100000005...] [1.0000000000000000e-7000...]]
        [ [1.000000100000005...] [1.0000000000000000e-6990...]]
        sage: logger.setLevel(logging.WARNING)
        sage: series_sum(dop, {0: (1,), 1000: (1/1000,)}, 1, 1e-10)
        ([2.719281828...])

    Test that we correctly take into account the errors on terms of polynomials
    that are not represented because they are zero::

        sage: dop = x*Dx^2 + Dx + x
        sage: ini = LogSeriesInitialValues(0, {0: (1, 0)})
        sage: maj = bounds.DiffOpBound(dop, special_shifts=[(0, 1)], max_effort=0)
        sage: series_sum(dop, ini, QQ(2), 1e-8, stride=1, maj=maj)
        ([0.2238907...])

    Some simple tests involving large non-integer valuations::

        sage: dop = (x*Dx-1001/2).symmetric_product(Dx-1)
        sage: dop = dop._normalize_base_ring()[-1]
        sage: (exp(CBF(1/2))/RBF(2)^(1001/2)).overlaps(dop.numerical_transition_matrix([0, 1/2], 1e-10)[0,0])
        True
        sage: (exp(CBF(2))/RBF(1/2)^(1001/2)).overlaps(dop.numerical_transition_matrix([0, 2], 1e-10)[0,0])
        True

        sage: dop = (x*Dx+1001/2).symmetric_product(Dx-1)
        sage: dop = dop._normalize_base_ring()[-1]
        sage: (CBF(1/2)^(-1001/2)*exp(CBF(1/2))).overlaps(dop.numerical_transition_matrix([0, 1/2], 1e-10)[0,0])
        True
        sage: (CBF(2)^(-1001/2)*exp(CBF(2))).overlaps(dop.numerical_transition_matrix([0, 2], 1e-10)[0,0])
        True

        sage: h = CBF(1/2)
        sage: #dop = (Dx-1).lclm(x^2*Dx^2 - x*(2*x+1999)*Dx + (x^2 + 1999*x + 1000^2))
        sage: dop = x^2*Dx^3 + (-3*x^2 - 1997*x)*Dx^2 + (3*x^2 + 3994*x + 998001)*Dx - x^2 - 1997*x - 998001
        sage: mat = dop.numerical_transition_matrix([0,1/2], 1e-5) # XXX: long time with the simplified bounds on rational functions
        sage: mat[0,0].overlaps(exp(h)) # long time
        True
        sage: mat[0,1].overlaps(exp(h)*h^1000*log(h)) # long time
        True
        sage: mat[0,2].overlaps(exp(h)*h^1000) # long time
        True

        sage: dop = (x^3 + x^2)*Dx^3 + (-1994*x^2 - 1997*x)*Dx^2 + (994007*x + 998001)*Dx + 998001
        sage: mat = dop.numerical_transition_matrix([0, 1/2], 1e-5)
        sage: mat[0,0].overlaps(1/(1+h))
        True
        sage: mat[0,1].overlaps(h^1000/(1+h)*log(h))
        True
        sage: mat[0,2].overlaps(h^1000/(1+h))
        True
    """

    jet = pt.jet(Intervals)
    Jets = jet.parent()
    ord = pt.jet_order
    jetpow = Jets.one()
    radpow = bounds.IR.one(
    )  # bound on abs(pt)^n in the series part (=> starts
    # at 1 regardless of ini.expo)

    log_prec = sum(len(v) for v in ini.shift.itervalues())
    last_index_with_ini = max([dop.order()] + [
        s for s, vals in ini.shift.iteritems() if not all(v.is_zero()
                                                          for v in vals)
    ])
    last = collections.deque(
        [vector(Intervals, log_prec) for _ in xrange(bwrec.order + 1)])
    psum = vector(Jets, log_prec)

    # Every few iterations, heuristically check if we have converged and if
    # we still have enough precision. If it looks like the target error may
    # be reached, perform a rigorous check. Our stopping criterion currently
    # (1) only works at “generic” indices, and (2) assumes that the initial
    # values at exceptional indices larger than n are zero, so we also
    # ensure that we are in this case. (Both assumptions could be lifted,
    # (1) by using a slightly more complicated formula for the tail bound,
    # and (2) if we had code to compute lower bounds on coefficients of
    # series expansions of majorants.)
    tail_bound = bounds.IR(infinity)
    bit_prec = Intervals.precision()
    ini_are_accurate = 2 * min(pt.accuracy(), ini.accuracy()) > bit_prec

    # TODO: improve the automatic increase of precision for large x^λ:
    # we currently check the series part only (which would sort of make
    # sense in a relative error setting)
    val = [None]  # XXX could be more elegant :-)

    def get_bound(maj):
        tb = maj.bound(pt.rad, rows=pt.jet_order)
        my_psum = vector(Jets, [[t[i].add_error(tb.abs()) for i in range(ord)]
                                for t in psum])
        # XXX decouple this from the summation => less redundant computation of
        # local monodromy matrices
        val[0] = log_series_value(Jets,
                                  ord,
                                  ini.expo,
                                  my_psum,
                                  jet[0],
                                  branch=pt.branch)
        return max([RBF.zero()] + [_get_error(c) for c in val[0]])

    def get_residuals():
        return [stop.maj.normalized_residual(n, list(last)[1:], bwrec_nplus)]

    def get_value():
        my_psum = vector(Jets, [[t[i] for i in range(ord)] for t in psum])
        my_val = log_series_value(Jets,
                                  ord,
                                  ini.expo,
                                  my_psum,
                                  jet[0],
                                  branch=pt.branch)
        return my_val

    precomp_len = max(1, bwrec.order)  # hack for recurrences of order zero
    bwrec_nplus = collections.deque((bwrec.eval_series(Intervals, i, log_prec)
                                     for i in xrange(precomp_len)),
                                    maxlen=precomp_len)
    for n in itertools.count():
        last.rotate(1)
        logger.log(logging.DEBUG - 2, "n = %s, [c(n), c(n-1), ...] = %s", n,
                   list(last))
        logger.log(logging.DEBUG - 1, "n = %s, sum = %s", n, psum)
        mult = len(ini.shift.get(n, ()))

        if n % stride == 0:
            radpowest = abs(jetpow[0])
            est = sum(abs(a) for log_jet in last for a in log_jet) * radpowest
            sing = (n <= last_index_with_ini) or (mult > 0)
            done, tail_bound = stop.check(get_bound, get_residuals, get_value,
                                          sing, n, tail_bound, est, stride)
            if done:
                break

        for p in xrange(log_prec - mult - 1, -1, -1):
            combin = sum(bwrec_nplus[0][i][j] * last[i][p + j]
                         for j in xrange(log_prec - p)
                         for i in xrange(bwrec.order, 0, -1))
            combin += sum(bwrec_nplus[0][0][j] * last[0][p + j]
                          for j in xrange(mult + 1, log_prec - p))
            last[0][mult + p] = -~bwrec_nplus[0][0][mult] * combin
        for p in xrange(mult - 1, -1, -1):
            last[0][p] = ini.shift[n][p]
        psum += last[0] * jetpow
        jetpow = jetpow._mul_trunc_(jet, ord)
        radpow *= pt.rad
        bwrec_nplus.append(
            bwrec.eval_series(Intervals, n + precomp_len, log_prec))
    logger.info("summed %d terms, global tail bound = %s (est = %s)", n,
                tail_bound, bounds.IR(est))
    result = vector(val[0][i] for i in xrange(ord))
    return result
def find_primitive_p_divisible_vector__next(self, p, v=None):
    """
    Finds the next `p`-primitive vector (up to scaling) in `L/pL` whose
    value is `p`-divisible, where the last vector returned was `v`.  For
    an initial call, no `v` needs to be passed.

    Returns vectors whose last non-zero entry is normalized to 0 or 1 (so no
    lines are counted repeatedly).  The ordering is by increasing the
    first non-normalized entry.  If we have tested all (lines of)
    vectors, then return None.

    OUTPUT:

        vector or None

    EXAMPLES::

        sage: Q = QuadraticForm(ZZ, 2, [10,1,4])
        sage: v = Q.find_primitive_p_divisible_vector__next(5); v
        (1, 1)
        sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v
        (1, 0)
        sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v


    """
    ## Initialize
    n = self.dim()
    if v is None:
        w = vector([ZZ(0) for i in range(n - 1)] + [ZZ(1)])
    else:
        w = deepcopy(v)

    ## Handle n = 1 separately.
    if n <= 1:
        raise RuntimeError("Sorry -- Not implemented yet!")

    ## Look for the last non-zero entry (which must be 1)
    nz = n - 1
    while w[nz] == 0:
        nz += -1

    ## Test that the last non-zero entry is 1 (to detect tampering).
    if w[nz] != 1:
        print(
            "Warning: The input vector to QuadraticForm.find_primitive_p_divisible_vector__next() is not normalized properly."
        )

    ## Look for the next vector, until w == 0
    while True:

        ## Look for the first non-maximal (non-normalized) entry
        ind = 0
        while (ind < nz) and (w[ind] == p - 1):
            ind += 1

        ## Increment
        if (ind < nz):
            w[ind] += 1
            for j in range(ind):
                w[j] = 0
        else:
            for j in range(ind + 1):  ## Clear all entries
                w[j] = 0

            if nz != 0:  ## Move the non-zero normalized index over by one, or return the zero vector
                w[nz - 1] = 1
                nz += -1

        ## Test for zero vector
        if w == 0:
            return None

        ## Test for p-divisibility
        if (self(w) % p == 0):
            return w
 def is_convex(self):
     """
     sage: from cutgeneratingfunctionology.spam.polyhedral_complex import PolyhedralComplex
     sage: from sage.geometry.polyhedron.constructor import Polyhedron
     sage: pc = PolyhedralComplex([Polyhedron(base_ring=QQ, vertices=[[1,0],[0,1]],
     ....: rays=[[1,0],[0,1]])])
     sage: pc.is_convex()
     True
     sage: pc = PolyhedralComplex([Polyhedron(base_ring=QQ, vertices=[[1,0,0],[0,1,0]],
     ....: rays=[[1,0,0],[0,1,0]])])
     sage: pc.is_convex()
     True
     sage: pc = PolyhedralComplex([Polyhedron(base_ring=QQ, vertices=[[-1,0],[1,0]],
     ....: lines=[[0,1]])])
     sage: pc.is_convex()
     True
     sage: pc = PolyhedralComplex([Polyhedron(base_ring=QQ, vertices=[[1,0],[0,1]],
     ....: rays=[[1,0],[0,1]]),Polyhedron(base_ring=QQ, vertices=[[1,0],[0,-1]],
     ....: rays=[[1,0],[0,-1]])])
     sage: pc.is_convex()
     False
     sage: pc = PolyhedralComplex([Polyhedron(base_ring=QQ, vertices=[[0,0]],
     ....: rays=[[1,0],[-1,1]]),Polyhedron(base_ring=QQ, vertices=[[0,0]],
     ....: rays=[[1,0],[-1,-1]])])
     sage: pc.is_convex()
     False
     sage: pc = PolyhedralComplex([Polyhedron(base_ring=QQ, vertices=[[0,0,0]],
     ....: rays=[[1,0,0],[-1,1,0]]),Polyhedron(base_ring=QQ, vertices=[[0,0,0]],
     ....: rays=[[1,0,0],[-1,-1,0]])])
     sage: pc.is_convex()
     False
     sage: pc = PolyhedralComplex([Polyhedron(base_ring=QQ, vertices=[[0,0,0]],rays=[[1,0,0],[0,1,0],[0,0,-1]]),
     ....: Polyhedron(base_ring=QQ, vertices=[[0,0,0]],rays=[[1,0,0],[0,-1,0],[0,0,-1]]),
     ....: Polyhedron(base_ring=QQ, vertices=[[0,0,0]],rays=[[1,0,0],[0,-1,0],[0,0,1]]),
     ....: Polyhedron(base_ring=QQ, vertices=[[0,0,0]],rays=[[-1,0,0],[0,-1,0],[0,0,-1]]),
     ....: Polyhedron(base_ring=QQ, vertices=[[0,0,0]],rays=[[-1,0,0],[0,-1,0],[0,0,1]]),
     ....: Polyhedron(base_ring=QQ, vertices=[[0,0,0]],rays=[[-1,0,0],[0,1,0],[0,0,-1]]),
     ....: Polyhedron(base_ring=QQ, vertices=[[0,0,0]],rays=[[-1,0,0],[0,1,0],[0,0,1]])])
     sage: pc.is_convex()
     False
     """
     if hasattr(self, '_is_convex'): # FIXME: bad! _is_convex can not be changed later.
         return self._is_convex
     if not self.is_pure():
         self._is_convex = False
         return False
     if not self.is_full_dimensional():
         from sage.modules.free_module import span
         face = self._maximal_cells[self._dim][0]
         affine_space = span(face.equations_list(), face.base_ring())
         for face in self._maximal_cells[self._dim][1::]:
             if span(face.equations_list(), face.base_ring()) != affine_space:
                 self._is_convex = False
                 return False
         # # If they lie in different subspaces, can't be convex. When they all lie in the same subspace, then you orient the boundary halfspaces toward a strict convex combination of the vertices. Then you check whether all vertices are contained. After you made sure that the affine hulls of the cells are the same, it does not matter that is not full dimensional.
     boundaries = self.boundary_cells()
     vertices = set([])
     rays = set([])
     lines = set([])
     # lines are useless, because they are in the affine space of each boundary cell.
     for cell in boundaries: # is that enough, or need vertices of all cells? I think that is enough.
         for v in cell.vertices_list():
             vv = vector(v)
             vv.set_immutable()
             vertices.add(vv)
     for cell in self._maximal_cells[self._dim]:
         for r in cell.rays_list():
             rr = vector(r)
             rr.set_immutable()
             rays.add(rr)
         for l in cell.lines_list():
             ll = vector(l)
             ll.set_immutable()
             lines.add(ll)
     center = sum(vertices) / len(vertices)
     for cell in boundaries:
         for equation in cell.equations_list(): # if not full-dim, cell has more than one equaiton.
             coeff = vector(equation[1::])
             const = equation[0]
             if const + coeff * center == 0:
                 sign = 0
             elif const + coeff * center > 0:
                 sign = 1
                 for v in vertices:
                     if const + coeff * v < 0:
                         self._is_convex = False
                         return False
             elif const + coeff * center < 0:
                 sign = -1
                 for v in vertices:
                     if const + coeff * v > 0:
                         self._is_convex = False
                         return False
             for r in rays:
                 if sign == 0:
                     sign = coeff * r
                 else:
                     if sign * (coeff * r) < 0:
                         self._is_convex = False
                         return False
     self._is_convex = True
     self._polyhedron = Polyhedron(vertices=vertices,rays=rays,lines=lines)
     return True
def find_p_neighbor_from_vec(self, p, v):
    """
    Finds the `p`-neighbor of this quadratic form associated to a given
    vector `v` satisfying:

    #. `Q(v) = 0  \pmod p`
    #. `v` is a non-singular point of the conic `Q(v) = 0 \pmod p`.

    Reference:  Gonzalo Tornaria's Thesis, Thrm 3.5, p34.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1])
        sage: v = vector([0,2,1,1])
        sage: X = Q.find_p_neighbor_from_vec(3,v); X
        Quadratic form in 4 variables over Integer Ring with coefficients:
        [ 3 10 0 -4 ]
        [ * 9 0 -6 ]
        [ * * 1 0 ]
        [ * * * 2 ]

    """
    R = self.base_ring()
    n = self.dim()
    B2 = self.matrix()

    ## Find a (dual) vector w with B(v,w) != 0 (mod p)
    v_dual = B2 * vector(
        v)  ## We want the dot product with this to not be divisible by 2*p.
    y_ind = 0
    while ((y_ind < n) and (v_dual[y_ind] % p)
           == 0):  ## Check the dot product for the std basis vectors!
        y_ind += 1
    if y_ind == n:
        raise RuntimeError(
            "Oops!  One of the standard basis vectors should have worked.")
    w = vector([R(i == y_ind) for i in range(n)])
    vw_prod = (v * self.matrix()).dot_product(w)

    ## DIAGNOSTIC
    #if vw_prod == 0:
    #   print "v = ", v
    #   print "v_dual = ", v_dual
    #   print "v_dual[y_ind] = ", v_dual[y_ind]
    #   print "(v_dual[y_ind] % p) = ", (v_dual[y_ind] % p)
    #   print "w = ", w
    #   print "p = ", p
    #   print "vw_prod = ", vw_prod
    #   raise RuntimeError, "ERROR: Why is vw_prod = 0?"

    ## DIAGNOSTIC
    #print "v = ", v
    #print "w = ", w
    #print "vw_prod = ", vw_prod

    ## Lift the vector v to a vector v1 s.t. Q(v1) = 0 (mod p^2)
    s = self(v)
    if (s % p**2 != 0):
        al = (-s / (p * vw_prod)) % p
        v1 = v + p * al * w
        v1w_prod = (v1 * self.matrix()).dot_product(w)
    else:
        v1 = v
        v1w_prod = vw_prod

    ## DIAGNOSTIC
    #if (s % p**2 != 0):
    #    print "al = ", al
    #print "v1 = ", v1
    #print "v1w_prod = ", v1w_prod

    ## Construct a special p-divisible basis to use for the p-neighbor switch
    good_basis = extend_to_primitive([v1, w])
    for i in range(2, n):
        ith_prod = (good_basis[i] * self.matrix()).dot_product(v)
        c = (ith_prod / v1w_prod) % p
        good_basis[i] = good_basis[
            i] - c * w  ## Ensures that this extension has <v_i, v> = 0 (mod p)

    ## DIAGNOSTIC
    #print "original good_basis = ", good_basis

    ## Perform the p-neighbor switch
    good_basis[0] = vector([x / p for x in good_basis[0]])  ## Divide v1 by p
    good_basis[1] = good_basis[1] * p  ## Multiply w by p

    ## Return the associated quadratic form
    M = matrix(good_basis)
    new_Q = deepcopy(
        self)  ## Note: This avoids a circular import of QuadraticForm!
    new_Q.__init__(R, M * self.matrix() * M.transpose())
    return new_Q
    return QuadraticForm(R, M * self.matrix() * M.transpose())
Exemplo n.º 55
0
def semi_norm_cone(M, cone,  p=2, verbose=False):
    r"""
    Return the semi norm on the hyperplane orthogonal to v where v lives in
    the cone.

    EXAMPLES:

    For Arnoux-Rauzy, only the 1-norm works::

        sage: from slabbe.matrix_cocycle import semi_norm_cone
        sage: A1 = matrix(3, [1,1,1, 0,1,0, 0,0,1])
        sage: cone = A1
        sage: semi_norm_cone(A1.transpose(), cone, p=1)    # tolerance 0.00001
        0.9999999999999998
        sage: semi_norm_cone(A1.transpose(), cone, p=oo)   # tolerance 0.0001
        1.9999757223144654
        sage: semi_norm_cone(A1.transpose(), cone, p=2)   # tolerance 0.00001
        1.3065629648763757

    For Poincaré, all norms work::

        sage: P21 = matrix(3, [1,1,1, 0,1,1, 0,0,1])
        sage: H21 = matrix(3, [1,0,0, 0,1,0, 1,0,1])
        sage: cone = P21 * H21
        sage: semi_norm_cone(P21.transpose(), cone, p=1)   # tolerance 0.00001
        0.9999957276014074
        sage: semi_norm_cone(P21.transpose(), cone, p=oo)   # tolerance 0.00001
        1.0
        sage: semi_norm_cone(P21.transpose(), cone, p=2)   # tolerance 0.00001
        0.9999999999670175

    For Poincaré on the whole cone, it works for some norms::

        sage: P21 = matrix(3, [1,1,1, 0,1,1, 0,0,1])
        sage: cone = P21
        sage: semi_norm_cone(P21.transpose(), cone, p=1)   # tolerance 0.0001
        1.9999675644077723
        sage: semi_norm_cone(P21.transpose(), cone, p=2)   # tolerance 0.00001
        1.6180339887021953
        sage: semi_norm_cone(P21.transpose(), cone, p=oo)   # tolerance 0.00001
        1.0

    For a product, all norms work::

        sage: A1 = matrix(3, [1,1,1, 0,1,0, 0,0,1])
        sage: P21 = matrix(3, [1,1,1, 0,1,1, 0,0,1])
        sage: H21 = matrix(3, [1,0,0, 0,1,0, 1,0,1])
        sage: M = A1 * P21
        sage: cone = A1 * P21 * H21
        sage: semi_norm_cone(M.transpose(), cone, p=1)   # tolerance 0.00001
        0.999993244882415
        sage: semi_norm_cone(M.transpose(), cone, p=oo)   # tolerance 0.00001
        0.9999935206958908
        sage: semi_norm_cone(M.transpose(), cone, p=2)   # tolerance 0.00001
        0.7529377601317161
    """
    from sage.modules.free_module_element import vector
    from sage.numerical.optimize import minimize_constrained
    a,b,c = cone.columns()
    ab = vector(matrix((a,b)).right_kernel_matrix().row(0))
    ac = vector(matrix((a,c)).right_kernel_matrix().row(0))
    bc = vector(matrix((b,c)).right_kernel_matrix().row(0))
    middle = a+b+c
    cons = []
    if ab * middle < 0:
        cons.append(lambda z: -ab * vector(z))
    else:
        cons.append(lambda z: ab * vector(z))
    if ac * middle < 0:
        cons.append(lambda z: -ac * vector(z))
    else:
        cons.append(lambda z: ac * vector(z))
    if bc * middle < 0:
        cons.append(lambda z: -bc * vector(z))
    else:
        cons.append(lambda z: bc * vector(z))
    if not all(con(middle) > 0 for con in cons):
        raise ValueError("the middle should be in the cone")
    func = lambda v : - semi_norm_v(M,vector(v),p)
    x0 = middle
    rep = minimize_constrained(func, cons, x0)
    if not all((con(rep) >= 0 or abs(con(rep)) < 1e-7) for con in cons):
        raise ValueError("the answer (={}) should be in the cone".format(rep))
    if not all(r >= 0 or abs(r) < 1e-7 for r in rep):
        raise ValueError("the answer (={}) should be positive".format(rep))
    if verbose:
        print "optimal found at ", rep / rep.norm(p)
    return -func(rep)
Exemplo n.º 56
0
def jacobian(*X):
    r"""
    Compute the Jacobian (Rankin--Cohen--Ibukiyama) operator.

    INPUT:
    - ``X`` -- a list [F_1, ..., F_N] of N orthogonal modular forms for the same Gram matrix, where N = 3 + (number of self's gram matrix rows)

    OUTPUT: OrthogonalModularForm. (If F_1, ..., F_N have weights k_1, ..., k_N then the result has weight k_1 + ... + k_N + N - 1.)

    EXAMPLES::

        sage: from weilrep import *
        sage: jacobian([ParamodularForms(1).eisenstein_series(k, 7) for k in [4, 6, 10, 12]]) / (-589927441461779261030400000/2354734631251) #funny multiple
        (r^-1 - r)*q^3*s^2 + (-r^-1 + r)*q^2*s^3 + (-r^-3 - 69*r^-1 + 69*r + r^3)*q^4*s^2 + (r^-3 + 69*r^-1 - 69*r - r^3)*q^2*s^4 + O(q, s)^7
    """
    N = len(X)
    if N == 1:
        X = X[0]
        N = len(X)
    Xref = X[0]
    nvars = Xref.nvars()
    f = Xref.true_fourier_expansion()
    t, = f.parent().gens()
    rb_x = f.base_ring()
    x, = rb_x.gens()
    r_list = rb_x.base_ring().gens()
    if N != nvars + 1:
        raise ValueError('The Jacobian requires %d modular forms.' %
                         (nvars + 1))
    k = N - 1
    v = vector([0] * nvars)
    r_deriv = [[] for _ in r_list]
    t_deriv = []
    x_deriv = []
    u = []
    S = Xref.gram_matrix()
    new_scale = lcm(x.scale() for x in X)
    for y in X:
        if y.gram_matrix() != S:
            raise ValueError('These forms do not have the same Gram matrix.')
        f = y.rescale(new_scale // y.scale()).true_fourier_expansion()
        t_deriv.append(t * f.derivative())
        if nvars > 1:
            x_deriv.append(f.map_coefficients(lambda a: x * a.derivative()))
            if nvars > 2:
                for i, r in enumerate(r_list):
                    r_deriv[i].append(
                        f.map_coefficients(lambda a: rb_x([
                            r * y.derivative(r) for y in list(a)
                        ]) * (x**(a.polynomial_construction()[1]))))
        y_k = y.weight()
        k += y_k
        v += y.weyl_vector()
        u.append(y_k * f)
    L = [u, t_deriv]
    if nvars > 1:
        L.append(x_deriv)
        if nvars > 2:
            L.extend(r_deriv)
    return OrthogonalModularForm(
        k,
        Xref.weilrep(),
        matrix(L).determinant(),
        scale=new_scale,
        weylvec=v,
        qexp_representation=Xref.qexp_representation())
Exemplo n.º 57
0
def balance_sample(s, q=None):
    r"""
    Given ``(a,c) = s`` return a tuple ``(a',c')`` where ``a'`` is a integer
    vector with entries between -q//2 and q//2 and ``c`` is also within these
    bounds.

    If ``q`` is given ``(a,c) = s`` may live in the integers. If ``q`` is not
    given, then ``(a,c)`` are assumed to live in `\Zmod{q}`.

    INPUT:

    - ``s`` - sample of the form (a,c) where a is a vector and c is a scalar
    - ``q`` - modulus (default: ``None``)

    EXAMPLE::

        sage: map(balance_sample, samples(10, 5, Regev))
        [((-9, -4, -4, 4, -4), 6), ((-3, -10, 8, -3, -1), -10), ((-6, -12, -3, -2, -6), -6),
        ...
        ((-1, -8, -11, 13, 4), -6), ((10, 11, -3, -13, 0), 6), ((6, -1, 2, -11, 14), 2)]


        sage: D = DiscreteGaussianPolynomialSamplerRejection(8, 5)
        sage: rlwe = RingLWE(20, 257, D)
        sage: map(balance_sample, samples(10, 8, rlwe))
        [((5, -55, -31, -90, 6, 100, -46, -107), (6, -64, -40, 117, 27, 54, -98, -56)),
         ((109, -106, 28, 77, -14, -109, 115, 34), (82, 17, -89, 62, 1, -77, 128, 64)), 
         ...
         ((-32, 51, -110, -106, 35, -82, 14, -113), (126, -120, 126, 119, 101, 3, -122, -75))]

    .. note::

        This function is useful to convert between Sage's standard
        representation of elements in `\Zmod{q}` as integers between 0 and q-1
        and the usual representation of such elements in lattice cryptography as
        integers between -q//2 and q//2.
    """
    a, c = s

    try:
        c[0]
        scalar = False
    except TypeError:
        c = vector(c.parent(), [c])
        scalar = True

    if q is None:
        q = parent(c[0]).order()
        a = a.change_ring(ZZ)
        c = c.change_ring(ZZ)
    else:
        K = IntegerModRing(q)
        a = a.change_ring(K).change_ring(ZZ)
        c = c.change_ring(K).change_ring(ZZ)

    q2 = q // 2

    if scalar:
        return vector(ZZ, len(a),
                      [e if e <= q2 else e - q
                       for e in a]), c[0] if c[0] <= q2 else c[0] - q
    else:
        return vector(ZZ, len(a),
                      [e if e <= q2 else e - q for e in a]), vector(
                          ZZ, len(c), [e if e <= q2 else e - q for e in c])
Exemplo n.º 58
0
def elem_vector(i, dim):
    vec = [0] * dim
    vec[i] = 1
    return vector(vec)
Exemplo n.º 59
0
def linear_program(c, G, h, A=None, b=None, solver=None):
    """
    Solves the dual linear programs:

    - Minimize  `c'x` subject to `Gx + s = h`, `Ax = b`, and `s \geq 0` where
      `'` denotes transpose.

    - Maximize  `-h'z - b'y` subject to `G'z + A'y + c = 0` and `z \geq 0`.

    INPUT:

    - ``c`` -- a vector

    - ``G`` -- a matrix

    - ``h`` -- a vector

    - ``A`` -- a matrix

    - ``b`` --- a vector

    - ``solver`` (optional) --- solver to use. If None, the cvxopt's lp-solver
                                is used. If it is 'glpk', then glpk's solver
                                is used.

    These can be over any field that can be turned into a floating point
    number.

    OUTPUT:

    A dictionary ``sol`` with keys ``x``, ``s``, ``y``, ``z`` corresponding
    to the variables above:

    - ``sol['x']`` -- the solution to the linear program

    - ``sol['s']`` -- the slack variables for the solution

    - ``sol['z']``, ``sol['y']`` -- solutions to the dual program

    EXAMPLES:

    First, we minimize `-4x_1 - 5x_2` subject to `2x_1 + x_2 \leq 3`,
    `x_1 +  2x_2 \leq 3`, `x_1 \geq 0`, and `x_2 \geq 0`::

        sage: c=vector(RDF,[-4,-5])
        sage: G=matrix(RDF,[[2,1],[1,2],[-1,0],[0,-1]])
        sage: h=vector(RDF,[3,3,0,0])
        sage: sol=linear_program(c,G,h)
        sage: sol['x']
        (0.999..., 1.000...)

    Next, we maximize `x+y-50` subject to `50x + 24y \leq 2400`,
    `30x + 33y \leq 2100`, `x \geq 45`, and `y \geq 5`::

        sage: v=vector([-1.0,-1.0,-1.0])
        sage: m=matrix([[50.0,24.0,0.0],[30.0,33.0,0.0],[-1.0,0.0,0.0],[0.0,-1.0,0.0],[0.0,0.0,1.0],[0.0,0.0,-1.0]])
        sage: h=vector([2400.0,2100.0,-45.0,-5.0,1.0,-1.0])
        sage: sol=linear_program(v,m,h)
        sage: sol['x']
        (45.000000..., 6.2499999...3, 1.00000000...)
        sage: sol=linear_program(v,m,h,solver='glpk')
        GLPK Simplex Optimizer...
        OPTIMAL SOLUTION FOUND
        sage: sol['x']
        (45.0..., 6.25, 1.0...)
    """
    from cvxopt.base import matrix as m
    from cvxopt import solvers
    solvers.options['show_progress'] = False
    if solver == 'glpk':
        from cvxopt import glpk
        glpk.options['LPX_K_MSGLEV'] = 0
    c_ = m(c.base_extend(RDF).numpy())
    G_ = m(G.base_extend(RDF).numpy())
    h_ = m(h.base_extend(RDF).numpy())
    if A != None and b != None:
        A_ = m(A.base_extend(RDF).numpy())
        b_ = m(b.base_extend(RDF).numpy())
        sol = solvers.lp(c_, G_, h_, A_, b_, solver=solver)
    else:
        sol = solvers.lp(c_, G_, h_, solver=solver)
    status = sol['status']
    if status != 'optimal':
        return {
            'primal objective': None,
            'x': None,
            's': None,
            'y': None,
            'z': None,
            'status': status
        }
    x = vector(RDF, list(sol['x']))
    s = vector(RDF, list(sol['s']))
    y = vector(RDF, list(sol['y']))
    z = vector(RDF, list(sol['z']))
    return {
        'primal objective': sol['primal objective'],
        'x': x,
        's': s,
        'y': y,
        'z': z,
        'status': status
    }
Exemplo n.º 60
0
def minimize(func,
             x0,
             gradient=None,
             hessian=None,
             algorithm="default",
             **args):
    r"""
    This function is an interface to a variety of algorithms for computing
    the minimum of a function of several variables.

    INPUT:

    - ``func`` -- Either a symbolic function or a Python function whose
      argument is a tuple with `n` components

    - ``x0`` -- Initial point for finding minimum.

    - ``gradient`` -- Optional gradient function. This will be computed
      automatically for symbolic functions.  For Python functions, it allows
      the use of algorithms requiring derivatives.  It should accept a
      tuple of arguments and return a NumPy array containing the partial
      derivatives at that point.

    - ``hessian`` --  Optional hessian function. This will be computed
      automatically for symbolic functions. For Python functions, it allows
      the use of algorithms requiring derivatives. It should accept a tuple
      of arguments and return a NumPy array containing the second partial
      derivatives of the function.

    - ``algorithm`` -- String specifying algorithm to use. Options are
      ``'default'`` (for Python functions, the simplex method is the default)
      (for symbolic functions bfgs is the default):

       - ``'simplex'``

       - ``'powell'``

       - ``'bfgs'`` -- (Broyden-Fletcher-Goldfarb-Shanno) requires
         ``gradient``

       - ``'cg'`` -- (conjugate-gradient) requires gradient

       - ``'ncg'`` -- (newton-conjugate gradient) requires gradient and hessian

    EXAMPLES::

        sage: vars=var('x y z')
        sage: f=100*(y-x^2)^2+(1-x)^2+100*(z-y^2)^2+(1-y)^2
        sage: minimize(f,[.1,.3,.4],disp=0)
        (1.00..., 1.00..., 1.00...)

        sage: minimize(f,[.1,.3,.4],algorithm="ncg",disp=0)
        (0.9999999..., 0.999999..., 0.999999...)

    Same example with just Python functions::

        sage: def rosen(x): # The Rosenbrock function
        ...      return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: minimize(rosen,[.1,.3,.4],disp=0)
        (1.00..., 1.00..., 1.00...)

    Same example with a pure Python function and a Python function to
    compute the gradient::

        sage: def rosen(x): # The Rosenbrock function
        ...      return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: import numpy
        sage: from numpy import zeros
        sage: def rosen_der(x):
        ...      xm = x[1r:-1r]
        ...      xm_m1 = x[:-2r]
        ...      xm_p1 = x[2r:]
        ...      der = zeros(x.shape,dtype=float)
        ...      der[1r:-1r] = 200r*(xm-xm_m1**2r) - 400r*(xm_p1 - xm**2r)*xm - 2r*(1r-xm)
        ...      der[0] = -400r*x[0r]*(x[1r]-x[0r]**2r) - 2r*(1r-x[0])
        ...      der[-1] = 200r*(x[-1r]-x[-2r]**2r)
        ...      return der
        sage: minimize(rosen,[.1,.3,.4],gradient=rosen_der,algorithm="bfgs",disp=0)
        (1.00...,  1.00..., 1.00...)
    """
    from sage.symbolic.expression import Expression
    from sage.ext.fast_eval import fast_callable
    import scipy
    from scipy import optimize
    if isinstance(func, Expression):
        var_list = func.variables()
        var_names = map(str, var_list)
        fast_f = fast_callable(func, vars=var_names, domain=float)
        f = lambda p: fast_f(*p)
        gradient_list = func.gradient()
        fast_gradient_functions = [
            fast_callable(gradient_list[i], vars=var_names, domain=float)
            for i in xrange(len(gradient_list))
        ]
        gradient = lambda p: scipy.array(
            [a(*p) for a in fast_gradient_functions])
    else:
        f = func

    if algorithm == "default":
        if gradient == None:
            min = optimize.fmin(f, map(float, x0), **args)
        else:
            min = optimize.fmin_bfgs(f,
                                     map(float, x0),
                                     fprime=gradient,
                                     **args)
    else:
        if algorithm == "simplex":
            min = optimize.fmin(f, map(float, x0), **args)
        elif algorithm == "bfgs":
            min = optimize.fmin_bfgs(f,
                                     map(float, x0),
                                     fprime=gradient,
                                     **args)
        elif algorithm == "cg":
            min = optimize.fmin_cg(f, map(float, x0), fprime=gradient, **args)
        elif algorithm == "powell":
            min = optimize.fmin_powell(f, map(float, x0), **args)
        elif algorithm == "ncg":
            if isinstance(func, Expression):
                hess = func.hessian()
                hess_fast = [[
                    fast_callable(a, vars=var_names, domain=float) for a in row
                ] for row in hess]
                hessian = lambda p: [[a(*p) for a in row] for row in hess_fast]
                hessian_p = lambda p, v: scipy.dot(scipy.array(hessian(p)), v)
                min = optimize.fmin_ncg(f,
                                        map(float, x0),
                                        fprime=gradient,
                                        fhess=hessian,
                                        fhess_p=hessian_p,
                                        **args)
    return vector(RDF, min)