| 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\\ |
| 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 | |