3351 | | def feedback_edge_set(self,value_only=False): |
3352 | | r""" |
3353 | | Computes the minimum feedback edge set of a digraph |
3354 | | ( also called feedback arc set ). |
3355 | | |
3356 | | The minimum feedback edge set of a digraph is a set of edges |
3357 | | that intersect all the circuits of the digraph. |
3358 | | Equivalently, a minimum feedback arc set of a DiGraph is a set |
3359 | | `S` of arcs such that the digraph `G-S` is acyclic. For more |
3360 | | information, see the |
3361 | | `Wikipedia article on feedback arc sets |
3362 | | <http://en.wikipedia.org/wiki/Feedback_arc_set>`_. |
3363 | | |
3364 | | INPUT : |
3365 | | |
3366 | | - ``value_only`` (boolean) -- |
3367 | | - When set to ``True``, only the minimum |
3368 | | cardinal of a minimum edge set is |
3369 | | returned. |
3370 | | |
3371 | | - When set to ``False``, the ``Set`` of edges |
3372 | | of a minimal edge set is returned. |
3373 | | |
3374 | | This problem is solved using Linear Programming, which certainly |
3375 | | is not the best way and will have to be updated. The program solved |
3376 | | is the following : |
3377 | | |
3378 | | .. MATH: |
3379 | | \mbox{Minimize : }&\sum_{(u,v)\in G} b_{(u,v)}\\ |
3380 | | \mbox{Such that : }&\\ |
3381 | | &\forall v\in G, \sum_{i\in [0,\dots,n-1]}x_{v,i}=1\\ |
3382 | | &\forall i\in [0,\dots,n-1], \sum_{v\in G}x_{v,i}=1\\ |
3383 | | &\forall v\in G,\sum_{i\in [0,\dots,n-1]} ix_{v,i}=d_v\\ |
3384 | | &\forall (u,v)\in G, d_u-d_v+nb_{(u,v)}\geq 0\\ |
3385 | | |
3386 | | An explanation : |
3387 | | |
3388 | | An acyclic digraph can be seen as a poset, and every poset has |
3389 | | a linear extension. This means that in any acyclic digraph |
3390 | | the vertices can be ordered with a total order `<` in such a way |
3391 | | that if `(u,v)\in G`, then `u<v`. |
3392 | | |
3393 | | Thus, this linear program is built in order to assign to each vertex |
3394 | | `v` an unique number `d_v\in [0,\dots,n-1]` such that if there exists |
3395 | | an edge `(u,v)\in G` such that `d_v<d_u`, then the edge `(u,v)` is |
3396 | | removed (`\Rightarrow x_{(u,v)}=1`). |
3397 | | |
3398 | | The number of edges removed is then minimized, which is |
3399 | | the objective. |
3400 | | |
3401 | | EXAMPLE : |
3402 | | |
3403 | | If the digraph is created from a graph, and hence is symmetric |
3404 | | ( if `uv` is an edge, then `vu` is an edge too ), then |
3405 | | obviously the cardinality of its feedback arc set is the number |
3406 | | of edges in the first graph :: |
3407 | | |
3408 | | sage: cycle=graphs.CycleGraph(5) |
3409 | | sage: dcycle=DiGraph(cycle) |
3410 | | sage: cycle.size() |
3411 | | 5 |
3412 | | sage: dcycle.feedback_edge_set(value_only=True) # optional - requires GLPK or CBC |
3413 | | 5.0 |
3414 | | |
3415 | | And in this situation, for any edge `uv` of the first graph, `uv` of `vu` |
3416 | | is in the returned feedback arc set:: |
3417 | | |
3418 | | sage: g = graphs.RandomGNP(5,.3) |
3419 | | sage: dg = DiGraph(g) |
3420 | | sage: feedback = dg.feedback_edge_set() # optional - requires GLPK or CBC |
3421 | | sage: (u,v,l) = g.edge_iterator().next() |
3422 | | sage: (u,v) in feedback or (v,u) in feedback # optional - requires GLPK or CBC |
3423 | | True |
3424 | | """ |
3425 | | |
3426 | | from sage.numerical.mip import MixedIntegerLinearProgram |
3427 | | |
3428 | | p=MixedIntegerLinearProgram(maximization=False) |
3429 | | |
3430 | | b=p.new_variable() |
3431 | | x=p.new_variable(dim=2) |
3432 | | d=p.new_variable() |
3433 | | n=self.order() |
3434 | | N=range(n) |
3435 | | |
3436 | | # First and second constraints |
3437 | | for v in self: |
3438 | | p.add_constraint(sum([x[v][i] for i in N]),min=1,max=1) |
3439 | | |
3440 | | for i in N: |
3441 | | p.add_constraint(sum([x[v][i] for v in self]),min=1,max=1) |
3442 | | |
3443 | | # Definition of d_v |
3444 | | for v in self: |
3445 | | p.add_constraint(sum([i*x[v][i] for i in N])-d[v],max=0,min=0) |
3446 | | |
3447 | | # The removed vertices cover all the back arcs ( third condition ) |
3448 | | for (u,v) in self.edges(labels=None): |
3449 | | p.add_constraint(d[u]-d[v]+n*(b[(u,v)]),min=0) |
3450 | | |
3451 | | p.set_binary(b) |
3452 | | p.set_binary(x) |
3453 | | |
3454 | | p.set_objective(sum([b[(u,v)] for (u,v) in self.edges(labels=None)])) |
3455 | | |
3456 | | if value_only: |
3457 | | return p.solve(objective_only=True) |
3458 | | else: |
3459 | | p.solve() |
3460 | | |
3461 | | b_sol=p.get_values(b) |
3462 | | |
3463 | | from sage.sets.set import Set |
3464 | | return Set([(u,v) for (u,v) in self.edges(labels=None) if b_sol[(u,v)]==1]) |
3465 | | |
3466 | | def feedback_vertex_set(self,value_only=False): |
3467 | | r""" |
3468 | | Computes the minimum feedback vertex set of a digraph. |
3469 | | |
3470 | | The minimum feedback vertex set of a digraph is a set of vertices |
3471 | | that intersect all the circuits of the digraph. |
3472 | | Equivalently, a minimum feedback vertex set of a DiGraph is a set |
3473 | | `S` of vertices such that the digraph `G-S` is acyclic. For more |
3474 | | information, see the |
3475 | | `Wikipedia article on feedback vertex sets |
3476 | | <http://en.wikipedia.org/wiki/Feedback_vertex_set>`_. |
3477 | | |
3478 | | INPUT : |
3479 | | |
3480 | | - ``value_only`` (boolean) -- |
3481 | | - When set to ``True``, only the minimum |
3482 | | cardinal of a minimum vertex set is |
3483 | | returned. |
3484 | | |
3485 | | - When set to ``False``, the ``Set`` of vertices |
3486 | | of a minimal feedback vertex set is returned. |
3487 | | |
3488 | | This problem is solved using Linear Programming, which certainly |
3489 | | is not the best way and will have to be replaced by a better algorithm. |
3490 | | The program solved is the following : |
3491 | | |
3492 | | .. MATH: |
3493 | | \mbox{Minimize : }&\sum_{v\in G} b_v\\ |
3494 | | \mbox{Such that : }&\\ |
3495 | | &\forall v\in G, \sum_{i\in [0,\dots,n-1]}x_{v,i}=1\\ |
3496 | | &\forall i\in [0,\dots,n-1], \sum_{v\in G}x_{v,i}=1\\ |
3497 | | &\forall v\in G,\sum_{i\in [0,\dots,n-1]} ix_{v,i}=d_v\\ |
3498 | | &\forall (u,v)\in G, d_u-d_v+nb_u+nb_v\geq 0\\ |
3499 | | |
3500 | | A brief explanation : |
3501 | | |
3502 | | An acyclic digraph can be seen as a poset, and every poset has |
3503 | | a linear extension. This means that in any acyclic digraph |
3504 | | the vertices can be ordered with a total order `<` in such a way |
3505 | | that if `(u,v)\in G`, then `u<v`. |
3506 | | Thus, this linear program is built in order to assign to each vertex |
3507 | | `v` an unique number `d_v\in [0,\dots,n-1]` such that if there exists |
3508 | | an edge `(u,v)\in G` such that `d_v<d_u`, then either `u` is removed |
3509 | | (`\Rightarrow b_u=1`) or `v` is removed (`\Rightarrow b_v=1`). |
3510 | | The number of vertices removed is then minimized, which is |
3511 | | the objective. |
3512 | | |
3513 | | EXAMPLE: |
3514 | | |
3515 | | In a digraph built from a graph, any edge is replaced by arcs going |
3516 | | in the two opposite directions, thus creating a cycle of length two. |
3517 | | Hence, to remove all the cycles from the graph, each edge must see |
3518 | | one of its neighbors removed : a feedback vertex set is in this |
3519 | | situation a vertex cover :: |
3520 | | |
3521 | | sage: cycle=graphs.CycleGraph(5) |
3522 | | sage: dcycle=DiGraph(cycle) |
3523 | | sage: cycle.vertex_cover(value_only=True) # optional - requires GLPK or CBC |
3524 | | 3 |
3525 | | sage: feedback = dcycle.feedback_vertex_set() # optional - requires GLPK or CBC |
3526 | | sage: feedback.cardinality() # optional - requires GLPK or CBC |
3527 | | 3 |
3528 | | sage: (u,v,l) = cycle.edge_iterator().next() |
3529 | | sage: u in feedback or v in feedback # optional - requires GLPK or CBC |
3530 | | True |
3531 | | |
3532 | | For a circuit, the minimum feedback arc set is clearly `1` :: |
3533 | | |
3534 | | sage: circuit = digraphs.Circuit(5) |
3535 | | sage: circuit.feedback_vertex_set(value_only=True) == 1 # optional - requires GLPK or CBC |
3536 | | True |
3537 | | """ |
3538 | | |
3539 | | from sage.numerical.mip import MixedIntegerLinearProgram |
3540 | | |
3541 | | p=MixedIntegerLinearProgram(maximization=False) |
3542 | | |
3543 | | b=p.new_variable() |
3544 | | x=p.new_variable(dim=2) |
3545 | | d=p.new_variable() |
3546 | | n=self.order() |
3547 | | N=range(n) |
3548 | | |
3549 | | # First and second constraints |
3550 | | for v in self: |
3551 | | p.add_constraint(sum([x[v][i] for i in N]),min=1,max=1) |
3552 | | |
3553 | | for i in N: |
3554 | | p.add_constraint(sum([x[v][i] for v in self]),min=1,max=1) |
3555 | | |
3556 | | # Definition of d_v |
3557 | | for v in self: |
3558 | | p.add_constraint(sum([i*x[v][i] for i in N])-d[v],max=0,min=0) |
3559 | | |
3560 | | # The removed vertices cover all the back arcs ( third condition ) |
3561 | | for (u,v) in self.edges(labels=None): |
3562 | | p.add_constraint(d[u]-d[v]+n*(b[u]+b[v]),min=0) |
3563 | | |
3564 | | p.set_binary(b) |
3565 | | p.set_binary(x) |
3566 | | |
3567 | | p.set_objective(sum([b[v] for v in self])) |
3568 | | |
3569 | | if value_only: |
3570 | | return p.solve(objective_only=True) |
3571 | | else: |
3572 | | p.solve() |
3573 | | b_sol=p.get_values(b) |
3574 | | |
3575 | | from sage.sets.set import Set |
3576 | | return Set([v for v in self if b_sol[v]==1]) |
3577 | | |
3578 | | |