Ticket #11384: trac_11384_fan_complex.2.patch

File trac_11384_fan_complex.2.patch, 11.9 KB (added by vbraun, 10 years ago)

Updated patch

  • sage/geometry/fan.py

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1309466932 -3600
    # Node ID 6bdef91e1264d2eeee217672c17c6c39be3d3917
    # Parent  49dc3b86bb7536a38f72ddb548d49b36a2d71e9c
    Trac #11384: Construct the complex of a fan
    
    This patch implements new methods fan.oriented_boundary(cone)
    and fan.complex() to return chosen boundary orientations of
    cones and the resulting homology complex.
    
    diff -r 49dc3b86bb75 -r 6bdef91e1264 sage/geometry/fan.py
    a b  
    24622462                               for i in range(0, self.nrays()) ]) )
    24632463        return ring.ideal(gens)
    24642464
     2465    def oriented_boundary(self, cone):
     2466        r"""
     2467        Return the facets bounding ``cone`` with their induced
     2468        orientation.
     2469
     2470        INPUT:
     2471
     2472        - ``cone`` -- a cone of the fan or the whole fan.
     2473
     2474        OUTPUT:
     2475
     2476        The boundary cones of ``cone`` as a formal linear combination
     2477        of cones with coefficients `\pm 1`. Each summand is a facet of
     2478        ``cone`` and the coefficient indicates whether their (chosen)
     2479        orientation argrees or disagrees with the "outward normal
     2480        first" boundary orientation. Note that the orientation of any
     2481        individial cone is arbitrary. This method once and for all
     2482        picks orientations for all cones and then computes the
     2483        boundaries relative to that chosen orientation.
     2484
     2485        If ``cone`` is the fan itself, the generating cones with their
     2486        orientation relative to the ambient space are returned.
     2487       
     2488        See :meth:`complex` for the associated chain complex. If you
     2489        do not require the orientation, use :meth:`cone.facets()
     2490        <sage.geometry.cone.ConvexRationalPolyhedralCone.facets>`
     2491        instead.
     2492       
     2493        EXAMPLES::
     2494
     2495            sage: fan = toric_varieties.P(3).fan()
     2496            sage: cone = fan(2)[0]
     2497            sage: bdry = fan.oriented_boundary(cone);  bdry
     2498            -1-d cone of Rational polyhedral fan in 3-d lattice N
     2499            + 1-d cone of Rational polyhedral fan in 3-d lattice N
     2500            sage: bdry[0]
     2501            (-1, 1-d cone of Rational polyhedral fan in 3-d lattice N)
     2502            sage: bdry[1]
     2503            (1, 1-d cone of Rational polyhedral fan in 3-d lattice N)
     2504            sage: fan.oriented_boundary(bdry[0][1])
     2505            -0-d cone of Rational polyhedral fan in 3-d lattice N
     2506            sage: fan.oriented_boundary(bdry[1][1])
     2507            -0-d cone of Rational polyhedral fan in 3-d lattice N
     2508           
     2509        If you pass the fan itself, this method returns the
     2510        orientation of the generating cones which is determined by the
     2511        order of the rays in :meth:`cone.ray_basis()
     2512        <sage.geometry.cone.IntegralRayCollection.ray_basis>` ::
     2513
     2514            sage: fan.oriented_boundary(fan)
     2515            3-d cone of Rational polyhedral fan in 3-d lattice N
     2516            - 3-d cone of Rational polyhedral fan in 3-d lattice N
     2517            + 3-d cone of Rational polyhedral fan in 3-d lattice N
     2518            - 3-d cone of Rational polyhedral fan in 3-d lattice N
     2519            sage: [ matrix(cone.ray_basis()).det() for cone in fan.generating_cones() ]
     2520            [-1, 1, -1, 1]
     2521
     2522        A non-full dimensional fan::
     2523       
     2524            sage: cone = Cone([(4,5)])
     2525            sage: fan = Fan([cone])
     2526            sage: fan.oriented_boundary(cone)
     2527            0-d cone of Rational polyhedral fan in 2-d lattice N
     2528            sage: fan.oriented_boundary(fan)
     2529            1-d cone of Rational polyhedral fan in 2-d lattice N
     2530
     2531        TESTS::
     2532
     2533            sage: fan = toric_varieties.P2().fan()
     2534            sage: trivial_cone = fan(0)[0]
     2535            sage: fan.oriented_boundary(trivial_cone)
     2536            0
     2537        """
     2538        if not cone is self:
     2539            cone = self.embed(cone)
     2540        if '_oriented_boundary' in self.__dict__:
     2541            return self._oriented_boundary[cone]
     2542
     2543        # Fix (arbitrary) orientations of the generating cones. Induced
     2544        # by ambient space orientation for full-dimensional cones
     2545        from sage.structure.formal_sum import FormalSum
     2546        def sign(x):
     2547            assert x != 0
     2548            if x>0: return +1
     2549            else: return -1
     2550        N_QQ = self.lattice().base_extend(QQ)
     2551        dim = self.lattice_dim()
     2552        outward_vectors = dict()
     2553        generating_cones = []
     2554        for c in self.generating_cones():
     2555            if c.dim()==dim:
     2556                outward_v = []
     2557            else:
     2558                Q = N_QQ.quotient(c.rays())
     2559                outward_v = [ Q.lift(q) for q in Q.gens() ]
     2560               
     2561            outward_vectors[c] = outward_v
     2562            orientation = sign(matrix(outward_v + list(c.ray_basis())).det())
     2563            generating_cones.append(tuple([orientation, c]))
     2564        boundaries = {self:FormalSum(generating_cones)}
     2565
     2566        # The orientation of each facet is arbitrary, but the
     2567        # partititon of the boundary in positively and negatively
     2568        # oriented facets is not.
     2569        for d in range(dim, -1, -1):
     2570            for c in self(d):
     2571                c_boundary = []
     2572                c_matrix = matrix(outward_vectors[c] + list(c.ray_basis()))
     2573                c_matrix_inv = c_matrix.inverse()
     2574                for facet in c.facets():
     2575                    outward_ray_indices = set(c.ambient_ray_indices()) \
     2576                              .difference(set(facet.ambient_ray_indices()))
     2577                    outward_vector = - sum(self.ray(i) for i in outward_ray_indices)
     2578                    outward_vectors[facet] = [outward_vector] + outward_vectors[c]
     2579                    facet_matrix = matrix(outward_vectors[facet] + list(facet.ray_basis()))
     2580                    orientation = sign((c_matrix_inv * facet_matrix).det())
     2581                    c_boundary.append(tuple([orientation, facet]))
     2582                boundaries[c] = FormalSum(c_boundary)
     2583
     2584        self._oriented_boundary = boundaries
     2585        return boundaries[cone]
     2586
     2587    def complex(self, base_ring=ZZ, extended=False):
     2588        r"""
     2589        Return the chain complex of the fan.
     2590
     2591        To a `d`-dimensional fan `\Sigma`, one can canonically
     2592        associate a chain complex `K^\bullet`
     2593       
     2594        .. math::
     2595
     2596            0 \longrightarrow
     2597            \ZZ^{\Sigma(d)} \longrightarrow
     2598            \ZZ^{\Sigma(d-1)} \longrightarrow
     2599            \cdots \longrightarrow
     2600            \ZZ^{\Sigma(0)} \longrightarrow
     2601            0
     2602           
     2603        where the leftmost non-zero entry is in degree `0` and the
     2604        rightmost entry in degree `d`. See [Klyachko], eq. (3.2). This
     2605        complex computes the homology of `|\Sigma|\subset N_\RR` with
     2606        arbitrary support,
     2607       
     2608        .. math::
     2609
     2610            H_i(K) = H_{d-i}(|\Sigma|, \ZZ)_{\text{non-cpct}}
     2611
     2612        For a complete fan, this is just the non-compactly supported
     2613        homology of `\RR^d`. In this case, `H_0(K)=\ZZ` and `0` in all
     2614        non-zero degrees.
     2615           
     2616        For a complete fan, there is an extended chain complex
     2617
     2618        .. math::
     2619
     2620            0 \longrightarrow
     2621            \ZZ \longrightarrow
     2622            \ZZ^{\Sigma(d)} \longrightarrow
     2623            \ZZ^{\Sigma(d-1)} \longrightarrow
     2624            \cdots \longrightarrow
     2625            \ZZ^{\Sigma(0)} \longrightarrow
     2626            0
     2627
     2628        where we take the first `\ZZ` term to be in degree -1. This
     2629        complex is an exact sequence, that is, all homology groups
     2630        vanish.
     2631
     2632        The orientation of each cone is chose as in
     2633        :meth:`oriented_boundary`.
     2634
     2635        INPUT:
     2636
     2637        - ``extended`` -- Boolean (default:False). Whether to
     2638          construct the extended complex, that is, including the
     2639          `\ZZ`-term at degree -1 or not.
     2640
     2641        - ``base_ring`` -- A ring (default: ``ZZ``). The ring to use
     2642          instead of `\ZZ`.
     2643
     2644        OUTPUT:
     2645
     2646        The complex associated to the fan as a :class:`ChainComplex
     2647        <sage.homology.chain_complex.ChainComplex>`. Raises a
     2648        ``ValueError`` if the extended complex is requested for a
     2649        non-complete fan.
     2650
     2651        EXAMPLES::
     2652
     2653            sage: fan = toric_varieties.P(3).fan()
     2654            sage: K_normal = fan.complex(); K_normal
     2655            Chain complex with at most 4 nonzero terms over Integer Ring
     2656            sage: K_normal.homology()
     2657            {0: Z, 1: 0, 2: 0, 3: 0}
     2658            sage: K_extended = fan.complex(extended=True); K_extended
     2659            Chain complex with at most 5 nonzero terms over Integer Ring
     2660            sage: K_extended.homology()
     2661            {0: 0, 1: 0, 2: 0, 3: 0, -1: 0}
     2662
     2663        Homology computations are much faster over `\QQ` if you don't
     2664        care about the torsion coefficients::
     2665
     2666            sage: toric_varieties.P2_123().fan().complex(extended=True, base_ring=QQ)
     2667            Chain complex with at most 4 nonzero terms over Rational Field
     2668            sage: _.homology()
     2669            {0: Vector space of dimension 0 over Rational Field,
     2670             1: Vector space of dimension 0 over Rational Field,
     2671             2: Vector space of dimension 0 over Rational Field,
     2672             -1: Vector space of dimension 0 over Rational Field}
     2673
     2674        The extended complex is only defined for complete fans::
     2675
     2676            sage: fan = Fan([ Cone([(1,0)]) ])
     2677            sage: fan.is_complete()
     2678            False
     2679            sage: fan.complex(extended=True)
     2680            Traceback (most recent call last):
     2681            ...
     2682            ValueError: The extended complex is only defined for complete fans!
     2683
     2684        The definition of the complex does not refer to the ambient
     2685        space of the fan, so it does not distinguish a fan from the
     2686        same fan embedded in a subspace::
     2687
     2688            sage: K1 = Fan([Cone([(-1,)]), Cone([(1,)])]).complex()
     2689            sage: K2 = Fan([Cone([(-1,0,0)]), Cone([(1,0,0)])]).complex()
     2690            sage: K1 == K2
     2691            True
     2692
     2693        Things get more complicated for non-complete fans::
     2694
     2695            sage: fan = Fan([Cone([(1,1,1)]),
     2696            ...              Cone([(1,0,0),(0,1,0)]),
     2697            ...              Cone([(-1,0,0),(0,-1,0),(0,0,-1)])])
     2698            sage: fan.complex().homology()
     2699            {0: 0, 1: 0, 2: Z x Z, 3: 0}
     2700            sage: fan = Fan([Cone([(1,0,0),(0,1,0)]),
     2701            ...              Cone([(-1,0,0),(0,-1,0),(0,0,-1)])])
     2702            sage: fan.complex().homology()
     2703            {0: 0, 1: 0, 2: Z, 3: 0}
     2704            sage: fan = Fan([Cone([(-1,0,0),(0,-1,0),(0,0,-1)])])
     2705            sage: fan.complex().homology()
     2706            {0: 0, 1: 0, 2: 0, 3: 0}
     2707
     2708        REFERENCES:
     2709
     2710        ..  [Klyachko]
     2711            A. A. Klyachko,
     2712            Equivariant Bundles on Toral Varieties.
     2713            Mathematics of the USSR - Izvestiya 35 (1990), 337-375.
     2714        """
     2715        dim = self.dim()
     2716        delta = dict()
     2717        for degree in range(1, dim+1):
     2718            m = matrix(base_ring, len(self(degree-1)), len(self(degree)), base_ring.zero())
     2719            for i, cone in enumerate(self(degree)):
     2720                boundary = self.oriented_boundary(cone)
     2721                for orientation, d_cone in boundary:
     2722                    m[self(degree-1).index(d_cone), i] = orientation
     2723            delta[dim-degree] = m
     2724
     2725        from sage.homology.chain_complex import ChainComplex
     2726        if not extended:
     2727            return ChainComplex(delta, base_ring=base_ring)
     2728
     2729        # add the extra entry for the extended complex
     2730        if not self.is_complete():
     2731            raise ValueError('The extended complex is only defined for complete fans!')
     2732        extension = matrix(base_ring, len(self(dim)), 1, base_ring.zero())
     2733        generating_cones = self.oriented_boundary(self)
     2734        for orientation, d_cone in generating_cones:
     2735            extension[self(dim).index(d_cone), 0] = orientation
     2736        delta[-1] = extension
     2737        return ChainComplex(delta, base_ring=base_ring)
     2738
    24652739
    24662740def discard_faces(cones):
    24672741    r"""