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