Ticket #11367: trac_11367.patch

File trac_11367.patch, 18.7 KB (added by ncohen, 9 years ago)
  • sage/graphs/digraph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1306060309 -7200
    # Node ID b77905618fccc0cf8a68cd7c025e90cc3ebbbd41
    # Parent  8a0b4f90f1ca76dbdba159897c39209c5da85442
    trac 11367 -- Rounding values, and inconsistencies in graph methods
    
    diff --git a/sage/graphs/digraph.py b/sage/graphs/digraph.py
    a b  
    13381338            sage: cycle.size()
    13391339            5
    13401340            sage: dcycle.feedback_edge_set(value_only=True)
    1341             5.0
     1341            5
    13421342       
    13431343        And in this situation, for any edge `uv` of the first graph, `uv` of
    13441344        `vu` is in the returned feedback arc set::
     
    14161416                obj = p.solve(log = verbose)
    14171417
    14181418            if value_only:
    1419                 return obj
     1419                return Integer(round(obj))
    14201420           
    14211421            else:
    14221422           
     
    14451445            p.set_objective(Sum([b[(u,v)] for (u,v) in self.edges(labels=None)]))
    14461446
    14471447            if value_only:
    1448                 return p.solve(objective_only=True, log=verbose)
     1448                return Integer(round(p.solve(objective_only=True, log=verbose)))
    14491449            else:
    14501450                p.solve(log=verbose)
    14511451               
     
    16531653            p.set_objective(Sum([b[v] for v in self]))
    16541654
    16551655            if value_only:
    1656                 return p.solve(objective_only=True, log=verbose)
     1656                return Integer(round(p.solve(objective_only=True, log=verbose)))
    16571657            else:
    16581658                p.solve(log=verbose)
    16591659                b_sol=p.get_values(b)
  • sage/graphs/generic_graph.py

    diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
    a b  
    39363936           ...      g.set_edge_label(u,v,round(random(),5))
    39373937           sage: g.edge_cut(0,1, method="FF") == g.edge_cut(0,1,method="LP")
    39383938           True
     3939
     3940        Rounded return value when using the LP method::
     3941
     3942           sage: g = graphs.PappusGraph()
     3943           sage: g.edge_cut(1, 2, value_only=True, method = "LP")
     3944           3
    39393945        """
    39403946
    39413947        if vertices:
     
    40054011        p.set_binary(b)
    40064012
    40074013        if value_only:
    4008             return p.solve(objective_only=True, log=verbose)
     4014            if use_edge_labels:
     4015                return p.solve(objective_only=True, log=verbose)
     4016            else:
     4017                return Integer(round(p.solve(objective_only=True, log=verbose)))
    40094018        else:
    40104019            obj = p.solve(log=verbose)
     4020
     4021            if use_edge_labels is False:
     4022                obj = Integer(round(obj))
     4023
    40114024            b = p.get_values(b)
    40124025            answer = [obj]
    40134026            if g.is_directed():
     
    40704083       
    40714084           sage: g = graphs.PappusGraph()
    40724085           sage: g.vertex_cut(1, 16, value_only=True)
    4073            3.0
     4086           3
    40744087
    40754088        In the bipartite complete graph `K_{2,8}`, a cut between the two
    40764089        vertices in the size `2` part consists of the other `8` vertices::
     
    40784091           sage: g = graphs.CompleteBipartiteGraph(2, 8)
    40794092           sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False)
    40804093           sage: print value
    4081            8.0
     4094           8
    40824095           sage: vertices == range(2,10)
    40834096           True
    40844097
     
    41304143        p.set_binary(v)
    41314144
    41324145        if value_only:
    4133             return p.solve(objective_only=True, log=verbose)
    4134         else:
    4135             obj = p.solve(log=verbose)
     4146            return Integer(round(p.solve(objective_only=True, log=verbose)))
     4147        else:
     4148            obj = Integer(round(p.solve(log=verbose)))
    41364149            b = p.get_values(b)
    41374150            answer = [obj,[x for x in g if b[x] == 1]]
    41384151            if vertices:
     
    42864299
    42874300        p.set_binary(cut)       
    42884301        if value_only:
    4289             return p.solve(objective_only = True, log = verbose)
     4302            if use_edge_labels:
     4303                return p.solve(objective_only = True, log = verbose)
     4304            else:
     4305                return Integer(round(p.solve(objective_only = True, log = verbose)))
    42904306
    42914307        p.solve(log = verbose)
    42924308
     
    44604476       
    44614477           sage: g=graphs.PetersenGraph()
    44624478           sage: g.max_cut()
    4463            12.0
     4479           12
    44644480
    44654481        """
    44664482        g=self
     
    45234539
    45244540        if value_only:
    45254541            obj = p.solve(objective_only=True, log=verbose)
    4526             return obj if use_edge_labels else round(obj)
     4542            return obj if use_edge_labels else Integer(round(obj))
    45274543        else:
    45284544            obj = p.solve(log=verbose)
    4529             val = [obj if use_edge_labels else round(obj)]
     4545
     4546            if use_edge_labels:
     4547                obj = Integer(round(obj))
     4548
     4549            val = [obj]
    45304550
    45314551            in_cut = p.get_values(in_cut)
    45324552            in_set = p.get_values(in_set)
     
    45504570
    45514571            return val
    45524572
    4553     def longest_path(self, s=None, t=None, weighted=False, algorithm="MILP", solver=None, verbose=0):
     4573    def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", solver=None, verbose=0):
    45544574        r"""
    45554575        Returns a longest path of ``self``.
    45564576
     
    45664586          ``None`` by default, which means that no constraint is set upon the
    45674587          last vertex in the path.
    45684588
    4569         - ``weighted`` (boolean) -- whether the labels on the edges are to be
    4570           considered as weights (a label set to ``None`` or ``{}`` being
     4589        - ``use_edge_labels`` (boolean) -- whether the labels on the edges are
     4590          to be considered as weights (a label set to ``None`` or ``{}`` being
    45714591          considered as a weight of `1`). Set to ``False`` by default.
    45724592
    45734593        - ``algorithm`` -- one of ``"MILP"`` (default) or ``"backtrack"``. Two
     
    45774597                backtrack algorithm is a randomized heuristic.
    45784598
    45794599              * As the backtrack algorithm does not support edge weighting,
    4580                 setting ``weighted=True`` will force the use of the MILP
     4600                setting ``use_edge_labels=True`` will force the use of the MILP
    45814601                algorithm.
    45824602
    45834603        - ``solver`` -- (default: ``None``) Specify the Linear Program (LP)
     
    45994619        OUTPUT:
    46004620
    46014621        A subgraph of ``self`` corresponding to a (directed if ``self`` is
    4602         directed) longest path. If ``weighted == True``, a pair ``weight, path``
    4603         is returned.
     4622        directed) longest path. If ``use_edge_labels == True``, a pair ``weight,
     4623        path`` is returned.
    46044624
    46054625        ALGORITHM:
    46064626
     
    46614681            sage: for u,v in g.edges(labels=False):
    46624682            ...       g.set_edge_label(u, v, random())
    46634683            sage: g2 = 2 * g1
    4664             sage: lp1 = g1.longest_path(weighted=True)
    4665             sage: lp2 = g2.longest_path(weighted=True)
     4684            sage: lp1 = g1.longest_path(use_edge_labels=True)
     4685            sage: lp2 = g2.longest_path(use_edge_labels=True)
    46664686            sage: lp1[0] == lp2[0]
    46674687            True
    46684688
     
    46704690
    46714691            sage: Graph().longest_path()
    46724692            Graph on 0 vertices
    4673             sage: Graph().longest_path(weighted=True)
     4693            sage: Graph().longest_path(use_edge_labels=True)
    46744694            [0, Graph on 0 vertices]
    46754695            sage: graphs.EmptyGraph().longest_path()
    46764696            Graph on 0 vertices
    4677             sage: graphs.EmptyGraph().longest_path(weighted=True)
     4697            sage: graphs.EmptyGraph().longest_path(use_edge_labels=True)
    46784698            [0, Graph on 0 vertices]
    46794699
    46804700        Trivial graphs::
     
    46834703            sage: G.add_vertex(0)
    46844704            sage: G.longest_path()
    46854705            Graph on 0 vertices
    4686             sage: G.longest_path(weighted=True)
     4706            sage: G.longest_path(use_edge_labels=True)
    46874707            [0, Graph on 0 vertices]
    46884708            sage: graphs.CompleteGraph(1).longest_path()
    46894709            Graph on 0 vertices
    4690             sage: graphs.CompleteGraph(1).longest_path(weighted=True)
     4710            sage: graphs.CompleteGraph(1).longest_path(use_edge_labels=True)
    46914711            [0, Graph on 0 vertices]
    46924712
    46934713        Random test for digraphs::
     
    47044724            ...           print("Error!")
    47054725            ...           break
    47064726        """
    4707         if weighted:
     4727        if use_edge_labels:
    47084728            algorithm = "MILP"
    47094729        if algorithm not in ("backtrack", "MILP"):
    47104730            raise ValueError("algorithm must be either 'backtrack' or 'MILP'")
    47114731
    47124732        # Quick improvement
    47134733        if not self.is_connected():
    4714             if weighted:
     4734            if use_edge_labels:
    47154735                return max(g.longest_path(s=s, t=t,
    4716                                           weighted=weighted,
     4736                                          use_edge_labels=use_edge_labels,
    47174737                                          algorithm=algorithm)
    47184738                           for g in self.connected_components_subgraphs())
    47194739            else:
    47204740                return max((g.longest_path(s=s, t=t,
    4721                                            weighted=weighted,
     4741                                           use_edge_labels=use_edge_labels,
    47224742                                           algorithm=algorithm)
    47234743                            for g in self.connected_components_subgraphs()),
    47244744                           key=lambda x: x.order())
     
    47474767             len(self.shortest_path(s, t) == 0))):
    47484768            if self._directed:
    47494769                from sage.graphs.all import DiGraph
    4750                 return [0, DiGraph()] if weighted else DiGraph()
     4770                return [0, DiGraph()] if use_edge_labels else DiGraph()
    47514771            from sage.graphs.all import Graph
    4752             return [0, Graph()] if weighted else Graph()
     4772            return [0, Graph()] if use_edge_labels else Graph()
    47534773
    47544774        # Calling the backtrack heuristic if asked
    47554775        if algorithm == "backtrack":
     
    47664786        epsilon = 1/(6*float(self.order()))
    47674787
    47684788        # Associating a weight to a label
    4769         if weighted:
     4789        if use_edge_labels:
    47704790            weight = lambda x: x if (x is not None and x != {}) else 1
    47714791        else:
    47724792            weight = lambda x: 1
     
    49004920                vertices=(v for v in self if vertex_used[v] >= 0.5),
    49014921                edges=((u,v,l) for u, v, l in self.edges()
    49024922                       if f_edge_used(u,v) >= 0.5))
    4903         if weighted:
     4923        if use_edge_labels:
    49044924            return sum(map(weight, g.edge_labels())), g
    49054925        else:
    49064926            return g
    49074927
    49084928
    4909     def traveling_salesman_problem(self, weighted = True, solver = None, constraint_generation = None, verbose = 0, verbose_constraints = False):
     4929    def traveling_salesman_problem(self, use_edge_labels = True, solver = None, constraint_generation = None, verbose = 0, verbose_constraints = False):
    49104930        r"""
    49114931        Solves the traveling salesman problem (TSP)
    49124932
    49134933        Given a graph (resp. a digraph) `G` with weighted edges, the traveling
    4914         salesman problem consists in finding a hamiltonian cycle (resp. circuit)
     4934        salesman problem consists in finding a Hamiltonian cycle (resp. circuit)
    49154935        of the graph of minimum cost.
    49164936
    49174937        This TSP is one of the most famous NP-Complete problems, this function
     
    49194939
    49204940        INPUT:
    49214941
    4922         - ``weighted`` (boolean) -- whether to consider the weights of the
    4923           edges.
     4942        - ``use_edge_labels`` (boolean) -- whether to consider the weights of
     4943          the edges.
    49244944
    49254945              - If set to ``False`` (default), all edges are assumed to weight
    49264946                `1`
    49274947
    49284948              - If set to ``True``, the weights are taken into account, and the
    4929                 edges whose weight is ``None`` are assumed to be set to `1`
    49304949
    49314950        - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
    49324951          solver to be used. If set to ``None``, the default one is used. For
     
    50135032            ...          g.add_edge(u,v)
    50145033            ...      g.set_edge_label(u,v,2)
    50155034
    5016             sage: tsp = g.traveling_salesman_problem(weighted = True)
     5035            sage: tsp = g.traveling_salesman_problem(use_edge_labels = True)
    50175036            sage: sum( tsp.edge_labels() ) < 2*10
    50185037            True
    50195038
     
    50235042            sage: for u,v in cycle.edges(labels = None):
    50245043            ...      g.set_edge_label(u,v,1/2)
    50255044
    5026             sage: tsp = g.traveling_salesman_problem(weighted = True)
     5045            sage: tsp = g.traveling_salesman_problem(use_edge_labels = True)
    50275046            sage: sum( tsp.edge_labels() ) == (1/2)*10
    50285047            True
    50295048
     
    51085127            multi = self.multiple_edges()
    51095128            g.delete_edges(multi)
    51105129            g.allow_multiple_edges(False)
    5111             if weighted:
     5130            if use_edge_labels:
    51125131                e = {}
    51135132
    51145133                for u,v,l in multi:
     
    51535172                b = p.new_variable(binary = True, dim = 2)
    51545173
    51555174                # Objective function
    5156                 if weighted:
     5175                if use_edge_labels:
    51575176                    p.set_objective(Sum([ weight(l)*b[u][v]
    51585177                                          for u,v,l in g.edges()]))
    51595178
     
    52085227                B = lambda u,v : b[(u,v)] if u<v else b[(v,u)]
    52095228
    52105229                # Objective function
    5211                 if weighted:
     5230                if use_edge_labels:
    52125231                    p.set_objective(Sum([ weight(l)*B(u,v)
    52135232                                          for u,v,l in g.edges()]) )
    52145233
     
    53365355
    53375356
    53385357
    5339         if weighted:
     5358        if use_edge_labels:
    53405359            p.set_objective(Sum([ weight(l)*E(u,v) for u,v,l in g.edges()]) )
    53415360        else:
    53425361            p.set_objective(None)
     
    54445463            from sage.numerical.mip import MIPSolverException
    54455464
    54465465            try:
    5447                 return self.traveling_salesman_problem(weighted = False)
     5466                return self.traveling_salesman_problem(use_edge_labels = False)
    54485467            except MIPSolverException:
    54495468                raise ValueError("The given graph is not Hamiltonian")
    54505469        elif algorithm=='backtrack':
     
    56655684
    56665685        obj=p.solve(log = verbose)
    56675686
     5687        if integer or use_edge_labels is False:
     5688            obj = Integer(round(obj))
     5689
    56685690        flow=p.get_values(flow)
    56695691        # Builds a clean flow Draph
    56705692        flow_graph = g._build_flow_graph(flow, integer=integer)
     
    62636285
    62646286          - ``"LP"`` uses a Linear Program formulation of the matching problem
    62656287
    6266         - ``use_edge_labels`` -- boolean (default: ``True``)
    6267 
    6268           - When set to ``True``, computes a weighted matching
    6269             where each edge is weighted by its label. (If
    6270             an edge has no label, `1` is assumed.)
     6288        - ``use_edge_labels`` -- boolean (default: ``False``)
     6289
     6290          - When set to ``True``, computes a weighted matching where each edge
     6291            is weighted by its label. (If an edge has no label, `1` is assumed.)
    62716292
    62726293          - When set to ``False``, each edge has weight `1`.
    62736294
     
    63276348                g = self.networkx_graph(copy=False)
    63286349            d = networkx.max_weight_matching(g)
    63296350            if value_only:
    6330                 return sum([weight(self.edge_label(u, v))
    6331                             for u, v in d.iteritems()]) * 0.5
     6351                if use_edge_labels:
     6352                    return sum([weight(self.edge_label(u, v))
     6353                                for u, v in d.iteritems()]) * 0.5
     6354                else:
     6355                    return Integer(len(d))
    63326356            else:
    63336357                return [(u, v, self.edge_label(u, v))
    63346358                        for u, v in d.iteritems() if u < v]
     
    63516375                         for u in g.neighbors(v)]), max=1)
    63526376            p.set_binary(b)
    63536377            if value_only:
    6354                 return p.solve(objective_only=True, log=verbose)
     6378                if use_edge_labels:
     6379                    return p.solve(objective_only=True, log=verbose)
     6380                else:
     6381                    return Integer(round(p.solve(objective_only=True, log=verbose)))
    63556382            else:
    63566383                p.solve(log=verbose)
    63576384                b = p.get_values(b)
     
    64126439       
    64136440           sage: g=graphs.PappusGraph()
    64146441           sage: g.dominating_set(value_only=True)
    6415            5.0
     6442           5
    64166443
    64176444        If we build a graph from two disjoint stars, then link their centers
    64186445        we will find a difference between the cardinality of an independent set
     
    64486475        p.set_integer(b)
    64496476
    64506477        if value_only:
    6451             return p.solve(objective_only=True, log=verbose)
     6478            return Integer(round(p.solve(objective_only=True, log=verbose)))
    64526479        else:
    64536480            p.solve(log=verbose)
    64546481            b=p.get_values(b)
     
    65016528       
    65026529           sage: g = graphs.PappusGraph()
    65036530           sage: g.edge_connectivity()
    6504            3.0
     6531           3
    65056532
    65066533        The edge connectivity of a complete graph ( and of a random graph )
    65076534        is its minimum degree, and one of the two parts of the bipartition
     
    65116538           sage: g = graphs.CompleteGraph(5)
    65126539           sage: [ value, edges, [ setA, setB ]] = g.edge_connectivity(vertices=True)
    65136540           sage: print value
    6514            4.0
     6541           4
    65156542           sage: len(setA) == 1 or len(setB) == 1
    65166543           True
    65176544           sage: cut = Graph()
     
    66326659
    66336660        p.set_objective(Sum([weight(l ) * in_cut[reorder_edge(u,v)] for (u,v,l) in g.edge_iterator()]))
    66346661
     6662        obj = p.solve(objective_only=value_only, log=verbose)
     6663
     6664        if use_edge_labels is False:
     6665            obj = Integer(round(obj))
     6666
    66356667        if value_only:
    6636             obj = p.solve(objective_only=True, log=verbose)
    6637             return obj if use_edge_labels else round(obj)
     6668            return obj
    66386669           
    66396670        else:
    6640             obj = p.solve(log=verbose)
    6641             val = [obj if use_edge_labels else round(obj)]
     6671            val = [obj]
    66426672
    66436673            in_cut = p.get_values(in_cut)
    66446674            in_set = p.get_values(in_set)
     
    67026732       
    67036733           sage: g=graphs.PappusGraph()
    67046734           sage: g.vertex_connectivity()
    6705            3.0
     6735           3
    67066736
    67076737        In a grid, the vertex connectivity is equal to the
    67086738        minimum degree, in which case one of the two sets it
     
    68086838        p.set_objective(Sum([in_set[1][v] for v in g]))
    68096839
    68106840        if value_only:
    6811             return p.solve(objective_only=True, log=verbose)
    6812         else:
    6813             val = [int(p.solve(log=verbose))]
     6841            return Integer(round(p.solve(objective_only=True, log=verbose)))
     6842        else:
     6843            val = [Integer(round(p.solve(log=verbose)))]
    68146844
    68156845            in_set = p.get_values(in_set)
    68166846
     
    1521115241        """
    1521215242
    1521315243        try:
    15214             tsp = self.traveling_salesman_problem(weighted = False)
     15244            tsp = self.traveling_salesman_problem(use_edge_labels = False)
    1521515245            return True
    1521615246
    1521715247        except ValueError: