Ticket #10044: trac_10044-python.patch

File trac_10044-python.patch, 4.3 KB (added by ncohen, 9 years ago)
  • sage/graphs/graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1285889116 -7200
    # Node ID 0c47c4999c2f82d3a022d9bb08ff9bad0ec605af
    # Parent  2c6977d800b5bdbadec51945285b77069f9f6f04
    trac 10044 -- Fractional Chromatic Index
    
    diff -r 2c6977d800b5 -r 0c47c4999c2f sage/graphs/graph.py
    a b  
    23912391            return first_coloring(self, hex_colors=hex_colors)
    23922392        else:
    23932393            raise ValueError("The 'algorithm' keyword must be set to either 'DLX' or 'MILP'.")
     2394
     2395    def fractional_chromatic_index(self, verbose_constraints = 0, verbose = 0):
     2396        r"""
     2397        Computes the fractional chromatic index of ``self``
     2398
     2399        The fractional chromatic index is a relaxed version of edge-coloring. An
     2400        edge coloring of a graph being actually a covering of its edges into the
     2401        smallest possible number of matchings, the fractional chromatic index of
     2402        a graph `G` is the smallest real value `\chi_f(G)` such that there
     2403        exists a list of matchings `M_1, ..., M_k` of `G` and coefficients
     2404        `\alpha_1, ..., \alpha_k` with the property that each edge is covered by
     2405        the matchings in the following relaxed way
     2406
     2407        .. MATH::
     2408
     2409            \forall e \in E(G), \sum_{e \in M_i} \alpha_i \geq 1
     2410
     2411        For more information, see the `Wikipedia article on fractional coloring
     2412        <http://en.wikipedia.org/wiki/Fractional_coloring>`_.
     2413
     2414        ALGORITHM:
     2415
     2416        The fractional chromatic index is computed through Linear Programming
     2417        through its dual. The LP solved by sage is actually:
     2418
     2419        .. MATH::
     2420 
     2421            \mbox{Maximize : }&\sum_{e\in E(G)} r_{e}\\
     2422            \mbox{Such that : }&\\ 
     2423            &\forall M\text{ matching }\subseteq G, \sum_{e\in M}r_{v}\leq 1\\
    23942424   
     2425        INPUT:
     2426
     2427        - ``verbose_constraints`` -- whether to display which constraints are
     2428          being generated.
     2429   
     2430        - ``verbose`` -- level of verbosity required from the LP solver
     2431   
     2432        .. NOTE::
     2433
     2434            This implementation can be improved by computing matchings through a
     2435            LP formulation, and not using the Python implementation of Edmonds'
     2436            algorithm (which requires to copy the graph, etc). It may be more
     2437            efficient to write the matching problem as a LP, as we would then
     2438            just have to update the weights on the edges between each call to
     2439            ``solve`` (and so avoiding the generation of all the constraints).
     2440
     2441
     2442        EXAMPLE:
     2443   
     2444        The fractional chromatic index of a `C_5` is `5/2`::
     2445   
     2446            sage: g = graphs.CycleGraph(5)
     2447            sage: g.fractional_chromatic_index()
     2448            2.5
     2449        """
     2450
     2451        from sage.numerical.mip import MixedIntegerLinearProgram, Sum
     2452       
     2453        g = self.copy()
     2454        p = MixedIntegerLinearProgram()
     2455
     2456        # One variable per edge
     2457        r = p.new_variable(dim = 2)
     2458        R = lambda x,y : r[x][y] if x<y else r[y][x]
     2459       
     2460        # We want to maximize the sum of weights on the edges
     2461        p.set_objective( Sum( R(u,v) for u,v in g.edges(labels = False)))
     2462
     2463        # Each edge being by itself a matching, its weight can not be more than
     2464        # 1
     2465
     2466        for u,v in g.edges(labels = False):
     2467            p.add_constraint( R(u,v), max = 1)
     2468
     2469        obj = p.solve(log = verbose)
     2470
     2471        while True:
     2472
     2473            # Updating the value on the edges of g
     2474            for u,v in g.edges(labels = False):
     2475                g.set_edge_label(u,v,p.get_values(R(u,v)))
     2476
     2477            # Computing a matching of maximum weight...
     2478
     2479            matching = g.matching()
     2480
     2481            # If the maximum matching has weight at most 1, we are done !
     2482            if sum(map(lambda x:x[2],matching)) <= 1:
     2483                break
     2484
     2485            # Otherwise, we add a new constraint
     2486
     2487            if verbose_constraints:
     2488                print "Adding a constraint on matching : ",matching
     2489
     2490            p.add_constraint( Sum( R(u,v) for u,v,_ in matching), max = 1)
     2491
     2492            # And solve again
     2493            obj = p.solve(log = verbose)
     2494
     2495        # Accomplished !
     2496        return obj
     2497
    23952498    def independent_set_of_representatives(self, family, solver=None, verbose=0):
    23962499        r"""
    23972500        Returns an independent set of representatives.