def is_package_installed_and_updated(pkg): from sage.misc.package import is_package_installed try: pkginfo = all_packages[pkg] except KeyError: # Might be an installed old-style package condition = is_package_installed(pkg) else: condition = (pkginfo["installed_version"] == pkginfo["remote_version"]) return condition
def OptionalExtension(*args, **kwds): """ If some condition (see INPUT) is satisfied, return an ``Extension``. Otherwise, return a ``CythonizeExtension``. Typically, the condition is some optional package or something depending on the operating system. INPUT: - ``condition`` -- (boolean) the actual condition - ``package`` -- (string) the condition is that this package is installed and up-to-date (only used if ``condition`` is not given) EXAMPLES:: sage: from sage_setup.optional_extension import OptionalExtension sage: ext = OptionalExtension("foo", ["foo.c"], condition=False) sage: print(ext.__class__) sage_setup.optional_extension.CythonizeExtension sage: ext = OptionalExtension("foo", ["foo.c"], condition=True) sage: print(ext.__class__) distutils.extension.Extension sage: ext = OptionalExtension("foo", ["foo.c"], package="no_such_package") sage: print(ext.__class__) sage_setup.optional_extension.CythonizeExtension sage: ext = OptionalExtension("foo", ["foo.c"], package="pari") sage: print(ext.__class__) distutils.extension.Extension """ try: condition = kwds.pop("condition") except KeyError: pkg = kwds.pop("package") from sage.misc.package import is_package_installed try: pkginfo = all_packages[pkg] except KeyError: # Might be an installed old-style package condition = is_package_installed(pkg) else: condition = ( pkginfo["installed_version"] == pkginfo["remote_version"]) if condition: return Extension(*args, **kwds) else: return CythonizeExtension(*args, **kwds)
def OptionalExtension(*args, **kwds): """ If some condition (see INPUT) is satisfied, return an ``Extension``. Otherwise, return a ``CythonizeExtension``. Typically, the condition is some optional package or something depending on the operating system. INPUT: - ``condition`` -- (boolean) the actual condition - ``package`` -- (string) the condition is that this package is installed and up-to-date (only used if ``condition`` is not given) EXAMPLES:: sage: from sage_setup.optional_extension import OptionalExtension sage: ext = OptionalExtension("foo", ["foo.c"], condition=False) sage: print(ext.__class__) sage_setup.optional_extension.CythonizeExtension sage: ext = OptionalExtension("foo", ["foo.c"], condition=True) sage: print(ext.__class__) distutils.extension.Extension sage: ext = OptionalExtension("foo", ["foo.c"], package="no_such_package") sage: print(ext.__class__) sage_setup.optional_extension.CythonizeExtension sage: ext = OptionalExtension("foo", ["foo.c"], package="pari") sage: print(ext.__class__) distutils.extension.Extension """ try: condition = kwds.pop("condition") except KeyError: pkg = kwds.pop("package") from sage.misc.package import is_package_installed try: pkginfo = all_packages[pkg] except KeyError: # Might be an installed old-style package condition = is_package_installed(pkg) else: condition = (pkginfo["installed_version"] == pkginfo["remote_version"]) if condition: return Extension(*args, **kwds) else: return CythonizeExtension(*args, **kwds)
def QuasiQuadraticResidueCode(p): r""" A (binary) quasi-quadratic residue code (or QQR code). Follows the definition of Proposition 2.2 in [BM]. The code has a generator matrix in the block form `G=(Q,N)`. Here `Q` is a `p \times p` circulant matrix whose top row is `(0,x_1,...,x_{p-1})`, where `x_i=1` if and only if `i` is a quadratic residue `\mod p`, and `N` is a `p \times p` circulant matrix whose top row is `(0,y_1,...,y_{p-1})`, where `x_i+y_i=1` for all `i`. INPUT: - ``p`` -- a prime `>2`. OUTPUT: Returns a QQR code of length `2p`. EXAMPLES:: sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_packages (Guava package) [22, 11] linear code over GF(2) These are self-orthogonal in general and self-dual when $p \\equiv 3 \\pmod 4$. AUTHOR: David Joyner (11-2005) """ if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') F = GF(2) gap.load_package("guava") gap.eval("C:=QQRCode(" + str(p) + ")") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[ gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) for j in range(1, n + 1) ] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
def RandomLinearCodeGuava(n, k, F): r""" The method used is to first construct a `k \times n` matrix of the block form `(I,A)`, where `I` is a `k \times k` identity matrix and `A` is a `k \times (n-k)` matrix constructed using random elements of `F`. Then the columns are permuted using a randomly selected element of the symmetric group `S_n`. INPUT: - ``n,k`` -- integers with `n>k>1`. OUTPUT: Returns a "random" linear code with length `n`, dimension `k` over field `F`. EXAMPLES:: sage: C = codes.RandomLinearCodeGuava(30,15,GF(2)); C # optional - gap_packages (Guava package) [30, 15] linear code over GF(2) sage: C = codes.RandomLinearCodeGuava(10,5,GF(4,'a')); C # optional - gap_packages (Guava package) [10, 5] linear code over GF(4) AUTHOR: David Joyner (11-2005) """ current_randstate().set_seed_gap() q = F.order() if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') gap.load_package("guava") gap.eval("C:=RandomLinearCode(" + str(n) + "," + str(k) + ", GF(" + str(q) + "))") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[ gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) for j in range(1, n + 1) ] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
def OptionalExtension(*args, **kwds): """ If some condition (see INPUT) is satisfied, return an ``Extension``. Otherwise, return a ``CythonizeExtension``. Typically, the condition is some optional package or something depending on the operating system. INPUT: - ``condition`` -- (boolean) the actual condition - ``package`` -- (string) the condition is that this package is installed (only used if ``condition`` is not given) EXAMPLES:: sage: from sage_setup.optional_extension import OptionalExtension sage: ext = OptionalExtension("foo", ["foo.c"], condition=False) sage: print ext.__class__ sage_setup.optional_extension.CythonizeExtension sage: ext = OptionalExtension("foo", ["foo.c"], condition=True) sage: print ext.__class__ distutils.extension.Extension sage: ext = OptionalExtension("foo", ["foo.c"], package="no_such_package") sage: print ext.__class__ sage_setup.optional_extension.CythonizeExtension sage: ext = OptionalExtension("foo", ["foo.c"], package="pari") sage: print ext.__class__ distutils.extension.Extension """ try: condition = kwds.pop("condition") except KeyError: pkg = kwds.pop("package") condition = is_package_installed(pkg) if condition: return Extension(*args, **kwds) else: return CythonizeExtension(*args, **kwds)
def best_linear_code_in_guava(n, k, F): r""" Returns the linear code of length ``n``, dimension ``k`` over field ``F`` with the maximal minimum distance which is known to the GAP package GUAVA. The function uses the tables described in ``bounds_on_minimum_distance_in_guava`` to construct this code. This requires the optional GAP package GUAVA. INPUT: - ``n`` -- the length of the code to look up - ``k`` -- the dimension of the code to look up - ``F`` -- the base field of the code to look up OUTPUT: - A :class:`LinearCode` which is a best linear code of the given parameters known to GUAVA. EXAMPLES:: sage: codes.databases.best_linear_code_in_guava(10,5,GF(2)) # long time; optional - gap_packages (Guava package) [10, 5] linear code over GF(2) sage: gap.eval("C:=BestKnownLinearCode(10,5,GF(2))") # long time; optional - gap_packages (Guava package) 'a linear [10,5,4]2..4 shortened code' This means that the best possible binary linear code of length 10 and dimension 5 is a code with minimum distance 4 and covering radius s somewhere between 2 and 4. Use ``bounds_on_minimum_distance_in_guava(10,5,GF(2))`` for further details. """ if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') gap.load_package("guava") q = F.order() C = gap("BestKnownLinearCode(%s,%s,GF(%s))" % (n, k, q)) from .linear_code import LinearCode return LinearCode(C.GeneratorMat()._matrix_(F))
def best_linear_code_in_guava(n, k, F): r""" Returns the linear code of length ``n``, dimension ``k`` over field ``F`` with the maximal minimum distance which is known to the GAP package GUAVA. The function uses the tables described in ``bounds_on_minimum_distance_in_guava`` to construct this code. This requires the optional GAP package GUAVA. INPUT: - ``n`` -- the length of the code to look up - ``k`` -- the dimension of the code to look up - ``F`` -- the base field of the code to look up OUTPUT: - A :class:`LinearCode` which is a best linear code of the given parameters known to GUAVA. EXAMPLES:: sage: codes.databases.best_linear_code_in_guava(10,5,GF(2)) # long time; optional - gap_packages (Guava package) [10, 5] linear code over GF(2) sage: gap.eval("C:=BestKnownLinearCode(10,5,GF(2))") # long time; optional - gap_packages (Guava package) 'a linear [10,5,4]2..4 shortened code' This means that the best possible binary linear code of length 10 and dimension 5 is a code with minimum distance 4 and covering radius s somewhere between 2 and 4. Use ``bounds_on_minimum_distance_in_guava(10,5,GF(2))`` for further details. """ if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') gap.load_package("guava") q = F.order() C = gap("BestKnownLinearCode(%s,%s,GF(%s))"%(n,k,q)) from .linear_code import LinearCode return LinearCode(C.GeneratorMat()._matrix_(F))
def QuasiQuadraticResidueCode(p): r""" A (binary) quasi-quadratic residue code (or QQR code). Follows the definition of Proposition 2.2 in [BM]. The code has a generator matrix in the block form `G=(Q,N)`. Here `Q` is a `p \times p` circulant matrix whose top row is `(0,x_1,...,x_{p-1})`, where `x_i=1` if and only if `i` is a quadratic residue `\mod p`, and `N` is a `p \times p` circulant matrix whose top row is `(0,y_1,...,y_{p-1})`, where `x_i+y_i=1` for all `i`. INPUT: - ``p`` -- a prime `>2`. OUTPUT: Returns a QQR code of length `2p`. EXAMPLES:: sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_packages (Guava package) [22, 11] linear code over GF(2) These are self-orthogonal in general and self-dual when $p \\equiv 3 \\pmod 4$. AUTHOR: David Joyner (11-2005) """ if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') F = GF(2) gap.load_package("guava") gap.eval("C:=QQRCode(" + str(p) + ")") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) for j in range(1, n + 1)] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
def RandomLinearCodeGuava(n, k, F): r""" The method used is to first construct a `k \times n` matrix of the block form `(I,A)`, where `I` is a `k \times k` identity matrix and `A` is a `k \times (n-k)` matrix constructed using random elements of `F`. Then the columns are permuted using a randomly selected element of the symmetric group `S_n`. INPUT: - ``n,k`` -- integers with `n>k>1`. OUTPUT: Returns a "random" linear code with length `n`, dimension `k` over field `F`. EXAMPLES:: sage: C = codes.RandomLinearCodeGuava(30,15,GF(2)); C # optional - gap_packages (Guava package) [30, 15] linear code over GF(2) sage: C = codes.RandomLinearCodeGuava(10,5,GF(4,'a')); C # optional - gap_packages (Guava package) [10, 5] linear code over GF(4) AUTHOR: David Joyner (11-2005) """ current_randstate().set_seed_gap() q = F.order() if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') gap.load_package("guava") gap.eval("C:=RandomLinearCode("+str(n)+","+str(k)+", GF("+str(q)+"))") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) for j in range(1, n + 1)] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
if (os.path.isfile(SAGE_INC + "cplex.h") and os.path.isfile(os.path.join(SAGE_LOCAL,"lib","libcplex.a"))): ext_modules.append( Extension("sage.numerical.backends.cplex_backend", sources = ["sage/numerical/backends/cplex_backend.pyx"], include_dirs = [os.path.join(SAGE_INC,"sage","c_lib","include")], language = 'c', libraries = ["csage", "stdc++", "cplex"]) ) else: exclude_modules.append('sage/numerical/backends/cplex_backend.pyx') if is_package_installed('cbc'): ext_modules.append( Extension("sage.numerical.backends.coin_backend", sources = ["sage/numerical/backends/coin_backend.pyx"], include_dirs = [os.path.join(SAGE_INC,"sage","c_lib","include")], language = 'c++', libraries = ["csage", "stdc++", "Cbc", "CbcSolver", "Cgl", "Clp", "CoinUtils", "OsiCbc", "OsiClp", "Osi"]) ) else: exclude_modules.append('sage/numerical/backends/coin_backend.pyx') # Only include darwin_utilities on OS_X >= 10.5 UNAME = os.uname() if UNAME[0] == "Darwin" and not UNAME[2].startswith('8.'):
def tournaments_nauty(self, n, min_out_degree=None, max_out_degree=None, strongly_connected=False, debug=False, options=""): r""" Returns all tournaments on `n` vertices using Nauty. INPUT: - ``n`` (integer) -- number of vertices. - ``min_out_degree``, ``max_out_degree`` (integers) -- if set to ``None`` (default), then the min/max out-degree is not constrained. - ``debug`` (boolean) -- if ``True`` the first line of genbg's output to standard error is captured and the first call to the generator's ``next()`` function will return this line as a string. A line leading with ">A" indicates a successful initiation of the program with some information on the arguments, while a line beginning with ">E" indicates an error with the input. - ``options`` (string) -- anything else that should be forwarded as input to Nauty's genbg. See its documentation for more information : `<http://cs.anu.edu.au/~bdm/nauty/>`_. .. NOTE:: To use this method you must first install the Nauty spkg. EXAMPLES:: sage: for g in digraphs.tournaments_nauty(4): # optional - nauty ....: print g.edges(labels = False) # optional - nauty [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)] [(1, 0), (1, 3), (2, 0), (2, 1), (3, 0), (3, 2)] [(0, 2), (1, 0), (2, 1), (3, 0), (3, 1), (3, 2)] [(0, 2), (0, 3), (1, 0), (2, 1), (3, 1), (3, 2)] sage: tournaments = digraphs.tournaments_nauty sage: [len(list(tournaments(x))) for x in range(1,8)] # optional - nauty [1, 1, 2, 4, 12, 56, 456] sage: [len(list(tournaments(x, strongly_connected = True))) for x in range(1,9)] # optional - nauty [1, 0, 1, 1, 6, 35, 353, 6008] """ import subprocess from sage.misc.package import is_package_installed if not is_package_installed("nauty"): raise TypeError( "The optional nauty spkg does not seem to be installed") nauty_input = options if min_out_degree is None: min_out_degree = 0 if max_out_degree is None: max_out_degree = n - 1 nauty_input += " -d" + str(min_out_degree) nauty_input += " -D" + str(max_out_degree) if strongly_connected: nauty_input += " -c" nauty_input += " " + str(n) + " " sp = subprocess.Popen("nauty-gentourng {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) if debug: yield sp.stderr.readline() gen = sp.stdout while True: try: s = gen.next() except StopIteration: raise StopIteration("Exhausted list of graphs from nauty geng") G = DiGraph(n) i = 0 j = 1 for b in s[:-1]: if b == '0': G.add_edge(i, j) else: G.add_edge(j, i) if j == n - 1: i += 1 j = i + 1 else: j += 1 yield G
def nauty(self, number_of_sets, number_of_vertices, multiple_sets = False, vertex_min_degree = None, vertex_max_degree = None, set_max_size = None, set_min_size = None, regular = False, uniform = False, max_intersection = None, connected = False, options="", debug=False): r""" Enumerates hypergraphs up to isomorphism using Nauty. INPUT: - ``number_of_sets``, ``number_of_vertices`` (integers) - ``multiple_sets`` (boolean) -- whether to allow several sets of the hypergraph to be equal (set to ``False`` by default). - ``vertex_min_degree``, ``vertex_max_degree`` (integers) -- define the maximum and minimum degree of an element from the ground set (i.e. the number of sets which contain it). Set to ``None`` by default. - ``set_min_size``, ``set_max_size`` (integers) -- define the maximum and minimum size of a set. Set to ``None`` by default. - ``regular`` (integer) -- if set to an integer value `k`, requires the hypergraphs to be `k`-regular. It is actually a shortcut for the corresponing min/max values. - ``uniform`` (integer) -- if set to an integer value `k`, requires the hypergraphs to be `k`-uniform. It is actually a shortcut for the corresponing min/max values. - ``max_intersection`` (integer) -- constraints the maximum cardinality of the intersection of two sets fro the hypergraphs. Set to ``None`` by default. - ``connected`` (boolean) -- whether to require the hypergraphs to be connected. Set to ``False`` by default. - ``debug`` (boolean) -- if ``True`` the first line of genbg's output to standard error is captured and the first call to the generator's ``next()`` function will return this line as a string. A line leading with ">A" indicates a successful initiation of the program with some information on the arguments, while a line beginning with ">E" indicates an error with the input. - ``options`` (string) -- anything else that should be forwarded as input to Nauty's genbg. See its documentation for more information : `<http://cs.anu.edu.au/~bdm/nauty/>`_. .. NOTE:: For genbg the *first class* elements are vertices, and *second class* elements are the hypergraph's sets. OUTPUT: A tuple of tuples. EXAMPLES: Small hypergraphs:: sage: list(hypergraphs.nauty(4,2)) # optional - nauty [((), (0,), (1,), (0, 1))] Only connected ones:: sage: list(hypergraphs.nauty(2,2, connected = True)) # optional - nauty [((0,), (0, 1))] Non-empty sets only:: sage: list(hypergraphs.nauty(3,2, set_min_size = 1)) # optional - nauty [((0,), (1,), (0, 1))] The Fano Plane, as the only 3-uniform hypergraph with 7 sets and 7 vertices:: sage: fano = next(hypergraphs.nauty(7, 7, uniform=3, max_intersection=1)) # optional - nauty sage: print fano # optional - nauty ((0, 1, 2), (0, 3, 4), (0, 5, 6), (1, 3, 5), (2, 4, 5), (2, 3, 6), (1, 4, 6)) The Fano Plane, as the only 3-regular hypergraph with 7 sets and 7 vertices:: sage: fano = next(hypergraphs.nauty(7, 7, regular=3, max_intersection=1)) # optional - nauty sage: print fano # optional - nauty ((0, 1, 2), (0, 3, 4), (0, 5, 6), (1, 3, 5), (2, 4, 5), (2, 3, 6), (1, 4, 6)) """ import subprocess from sage.misc.package import is_package_installed if not is_package_installed("nauty"): raise TypeError("The optional nauty spkg does not seem to be installed") nauty_input = options if connected: nauty_input += " -c" if not multiple_sets: nauty_input += " -z" if not max_intersection is None: nauty_input += " -Z"+str(max_intersection) # degrees and sizes if not regular is False: vertex_max_degree = vertex_min_degree = regular if vertex_max_degree is None: vertex_max_degree = number_of_sets if vertex_min_degree is None: vertex_min_degree = 0 if not uniform is False: set_max_size = set_min_size = uniform if set_max_size is None: set_max_size = number_of_vertices if set_min_size is None: set_min_size = 0 nauty_input += " -d"+str(vertex_min_degree)+":"+str(set_min_size) nauty_input += " -D"+str(vertex_max_degree)+":"+str(set_max_size) nauty_input += " "+str(number_of_vertices) +" "+str(number_of_sets)+" " sp = subprocess.Popen("genbg {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) if debug: yield sp.stderr.readline() gen = sp.stdout total = number_of_sets + number_of_vertices while True: try: s = next(gen) except StopIteration: raise StopIteration("Exhausted list of graphs from nauty geng") from sage.graphs.graph import Graph G = Graph(s[:-1], format='graph6') yield tuple( tuple( x for x in G.neighbors(v)) for v in range(number_of_vertices, total))
def bounds_on_minimum_distance_in_guava(n, k, F): r""" Computes a lower and upper bound on the greatest minimum distance of a `[n,k]` linear code over the field ``F``. This function requires the optional GAP package GUAVA. The function returns a GAP record with the two bounds and an explanation for each bound. The function Display can be used to show the explanations. The values for the lower and upper bound are obtained from a table constructed by Cen Tjhai for GUAVA, derived from the table of Brouwer. See http://www.codetables.de/ for the most recent data. These tables contain lower and upper bounds for `q=2` (when ``n <= 257``), `q=3` (when ``n <= 243``), `q=4` (``n <= 256``). (Current as of 11 May 2006.) For codes over other fields and for larger word lengths, trivial bounds are used. INPUT: - ``n`` -- the length of the code to look up - ``k`` -- the dimension of the code to look up - ``F`` -- the base field of the code to look up OUTPUT: - A GAP record object. See below for an example. EXAMPLES:: sage: gap_rec = codes.databases.bounds_on_minimum_distance_in_guava(10,5,GF(2)) # optional - gap_packages (Guava package) sage: print(gap_rec) # optional - gap_packages (Guava package) rec( construction := [ <Operation "ShortenedCode">, [ [ <Operation "UUVCode">, [ [ <Operation "DualCode">, [ [ <Operation "RepetitionCode">, [ 8, 2 ] ] ] ], [ <Operation "UUVCode">, [ [ <Operation "DualCode">, [ [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ] , [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ] ] ], [ 1, 2, 3, 4, 5, 6 ] ] ], k := 5, lowerBound := 4, lowerBoundExplanation := ... n := 10, q := 2, references := rec( ), upperBound := 4, upperBoundExplanation := ... ) """ if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') gap.load_package("guava") q = F.order() gap.eval("data := BoundsMinimumDistance(%s,%s,GF(%s))"%(n,k,q)) Ldata = gap.eval("Display(data)") return Ldata
else: exclude_modules.append('sage/numerical/backends/gurobi_backend.pyx') if (os.path.isfile(SAGE_INC + "cplex.h") and os.path.isfile(os.path.join(SAGE_LOCAL, "lib", "libcplex.a"))): ext_modules.append( Extension( "sage.numerical.backends.cplex_backend", sources=["sage/numerical/backends/cplex_backend.pyx"], include_dirs=[os.path.join(SAGE_INC, "sage", "c_lib", "include")], language='c', libraries=["csage", "stdc++", "cplex"])) else: exclude_modules.append('sage/numerical/backends/cplex_backend.pyx') if is_package_installed('cbc'): ext_modules.append( Extension( "sage.numerical.backends.coin_backend", sources=["sage/numerical/backends/coin_backend.pyx"], include_dirs=[os.path.join(SAGE_INC, "sage", "c_lib", "include")], language='c++', libraries=[ "csage", "stdc++", "Cbc", "CbcSolver", "Cgl", "Clp", "CoinUtils", "OsiCbc", "OsiClp", "Osi" ])) else: exclude_modules.append('sage/numerical/backends/coin_backend.pyx') # Only include darwin_utilities on OS_X >= 10.5 UNAME = os.uname()
def lovasz_theta(graph): r""" Return the value of Lovász theta-function of graph For a graph `G` this function is denoted by `\theta(G)`, and it can be computed in polynomial time. Mathematically, its most important property is the following: .. MATH:: \alpha(G)\leq\theta(G)\leq\chi(\overline{G}) with `\alpha(G)` and `\chi(\overline{G})` being, respectively, the maximum size of an :meth:`independent set <sage.graphs.graph.Graph.independent_set>` set of `G` and the :meth:`chromatic number <sage.graphs.graph.Graph.chromatic_number>` of the :meth:`complement <sage.graphs.generic_graph.GenericGraph.complement>` `\overline{G}` of `G`. For more information, see the :wikipedia:`Lovász_number`. .. NOTE:: - Implemented for undirected graphs only. Use to_undirected to convert a digraph to an undirected graph. - This function requires the optional package ``csdp``, which you can install with with ``sage -i csdp``. EXAMPLES:: sage: C=graphs.PetersenGraph() sage: C.lovasz_theta() # optional csdp 4.0 sage: graphs.CycleGraph(5).lovasz_theta() # optional csdp 2.236068 TEST:: sage: g = Graph() sage: g.lovasz_theta() # indirect doctest 0 """ n = graph.order() if n == 0: return 0 from networkx import write_edgelist from sage.misc.temporary_file import tmp_filename import os, subprocess from sage.env import SAGE_LOCAL from sage.misc.package import is_package_installed, PackageNotFoundError if not is_package_installed('csdp'): raise PackageNotFoundError("csdp") g = graph.relabel(inplace=False, perm=range(1, n + 1)).networkx_graph() tf_name = tmp_filename() tf = open(tf_name, 'wb') tf.write(str(n) + '\n' + str(g.number_of_edges()) + '\n') write_edgelist(g, tf, data=False) tf.close() lines = subprocess.check_output( [os.path.join(SAGE_LOCAL, 'bin', 'theta'), tf_name]) return float(lines.split()[-1])
def CossidentePenttilaGraph(q): r""" Cossidente-Penttila `((q^3+1)(q+1)/2,(q^2+1)(q-1)/2,(q-3)/2,(q-1)^2/2)`-strongly regular graph For each odd prime power `q`, one can partition the points of the `O_6^-(q)`-generalized quadrange `GQ(q,q^2)` into two parts, so that on any of them the induced subgraph of the point graph of the GQ has parameters as above [CP05]_. Directly follwing the construction in [CP05]_ is not efficient, as one then needs to construct the dual `GQ(q^2,q)`. Thus we describe here a more efficient approach that we came up with, following a suggestion by T.Penttila. Namely, this partition is invariant under the subgroup `H=\Omega_3(q^2)<O_6^-(q)`. We build the appropriate `H`, which leaves the form `B(X,Y,Z)=XY+Z^2` invariant, and pick up two orbits of `H` on the `F_q`-points. One them is `B`-isotropic, and we take the representative `(1:0:0)`. The other one corresponds to the points of `PG(2,q^2)` that have all the lines on them either missing the conic specified by `B`, or intersecting the conic in two points. We take `(1:1:e)` as the representative. It suffices to pick `e` so that `e^2+1` is not a square in `F_{q^2}`. Indeed, The conic can be viewed as the union of `\{(0:1:0)\}` and `\{(1:-t^2:t) | t \in F_{q^2}\}`. The coefficients of a generic line on `(1:1:e)` are `[1:-1-eb:b]`, for `-1\neq eb`. Thus, to make sure the intersection with the conic is always even, we need that the discriminant of `1+(1+eb)t^2+tb=0` never vanishes, and this is if and only if `e^2+1` is not a square. Further, we need to adjust `B`, by multiplying it by appropriately chosen `\nu`, so that `(1:1:e)` becomes isotropic under the relative trace norm `\nu B(X,Y,Z)+(\nu B(X,Y,Z))^q`. The latter is used then to define the graph. INPUT: - ``q`` -- an odd prime power. EXAMPLES: For `q=3` one gets Sims-Gewirtz graph. :: sage: G=graphs.CossidentePenttilaGraph(3) # optional - gap_packages (grape) sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) (56, 10, 0, 2) For `q>3` one gets new graphs. :: sage: G=graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) (378, 52, 1, 8) TESTS:: sage: G=graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time (1376, 150, 2, 18) sage: graphs.CossidentePenttilaGraph(2) Traceback (most recent call last): ... ValueError: q(=2) must be an odd prime power REFERENCES: .. [CP05] \A.Cossidente and T.Penttila Hemisystems on the Hermitian surface Journal of London Math. Soc. 72(2005), 731-741 """ p, k = is_prime_power(q,get_data=True) if k==0 or p==2: raise ValueError('q(={}) must be an odd prime power'.format(q)) from sage.libs.gap.libgap import libgap from sage.misc.package import is_package_installed, PackageNotFoundError if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') adj_list=libgap.function_factory("""function(q) local z, e, so, G, nu, G1, G0, B, T, s, O1, O2, x; LoadPackage("grape"); G0:=SO(3,q^2); so:=GeneratorsOfGroup(G0); G1:=Group(Comm(so[1],so[2]),Comm(so[1],so[3]),Comm(so[2],so[3])); B:=InvariantBilinearForm(G0).matrix; z:=Z(q^2); e:=z; sqo:=(q^2-1)/2; if IsInt(sqo/Order(e^2+z^0)) then e:=z^First([2..q^2-2], x-> not IsInt(sqo/Order(z^(2*x)+z^0))); fi; nu:=z^First([0..q^2-2], x->z^x*(e^2+z^0)+(z^x*(e^2+z^0))^q=0*z); T:=function(x) local r; r:=nu*x*B*x; return r+r^q; end; s:=Group([Z(q)*IdentityMat(3,GF(q))]); O1:=Orbit(G1, Set(Orbit(s,z^0*[1,0,0])), OnSets); O2:=Orbit(G1, Set(Orbit(s,z^0*[1,1,e])), OnSets); G:=Graph(G1,Concatenation(O1,O2),OnSets, function(x,y) return x<>y and 0*z=T(x[1]+y[1]); end); return List([1..OrderGraph(G)],x->Adjacency(G,x)); end;""") adj = adj_list(q) # for each vertex, we get the list of vertices it is adjacent to G = Graph(((i,int(j-1)) for i,ni in enumerate(adj) for j in ni), format='list_of_edges', multiedges=False) G.name('CossidentePenttila('+str(q)+')') return G
if new is not None: self.alias().add(new, store=store, cur=cur) else: with DBParams(locals(), store, cur): return Graph.name(self, new, *largs, **kargs) @override.determined(is_bipartite=PlusInfinity(), is_forest=PlusInfinity()) def odd_girth(self, value, attrs, **kargs): inf = value == PlusInfinity() if inf: del attrs["is_forest"] return (not inf, attrs) AVAILABLE_ALGORITHMS = ["sage"] if is_package_installed("bliss"): AVAILABLE_ALGORITHMS.insert(0, "bliss") def canonical_label(graph, **kargs): r""" Return the canonical labeling of ``graph``. INPUT: - ``graph`` - the graph to compute the canonical labelling for. - ``algorithm`` - the algorithm to use to compute the canonical labelling. The default value ``None`` means that ``'bliss'`` will be used if available, and ``'sage'`` otherwise. """
def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, verbose=False, **kwds): r""" Find solutions of this boolean polynomial system. This function provide a unified interface to several algorithms dedicated to solving systems of boolean equations. Depending on the particular nature of the system, some might be much faster than some others. INPUT: * ``self`` - a sequence of boolean polynomials * ``algorithm`` - the method to use. Possible values are ``polybori``, ``sat`` and ``exhaustive_search``. (default: ``polybori``, since it is always available) * ``n`` - number of solutions to return. If ``n == +Infinity`` then all solutions are returned. If `n < \infty` then `n` solutions are returned if the equations have at least `n` solutions. Otherwise, all the solutions are returned. (default: ``1``) * ``eliminate_linear_variables`` - whether to eliminate variables that appear linearly. This reduces the number of variables (makes solving faster a priori), but is likely to make the equations denser (may make solving slower depending on the method). * ``verbose`` - whether to display progress and (potentially) useful information while the computation runs. (default: ``False``) EXAMPLES: Without argument, a single arbitrary solution is returned:: sage: R.<x,y,z> = BooleanPolynomialRing() sage: S = Sequence([x*y+z, y*z+x, x+y+z+1]) sage: sol = S.solve(); sol # random [{y: 1, z: 0, x: 0}] We check that it is actually a solution:: sage: S.subs( sol[0] ) [0, 0, 0] We obtain all solutions:: sage: sols = S.solve(n=Infinity); sols # random [{x: 0, y: 1, z: 0}, {x: 1, y: 1, z: 1}] sage: map( lambda x: S.subs(x), sols) [[0, 0, 0], [0, 0, 0]] We can force the use of exhaustive search if the optional package ``FES`` is present:: sage: sol = S.solve(algorithm='exhaustive_search'); sol # random, optional - FES [{x: 1, y: 1, z: 1}] sage: S.subs( sol[0] ) [0, 0, 0] And we may use SAT-solvers if they are available:: sage: sol = S.solve(algorithm='sat'); sol # random, optional - CryptoMiniSat [{y: 1, z: 0, x: 0}] sage: S.subs( sol[0] ) [0, 0, 0] TESTS: Make sure that variables not occuring in the equations are no problem:: sage: R.<x,y,z,t> = BooleanPolynomialRing() sage: S = Sequence([x*y+z, y*z+x, x+y+z+1]) sage: sols = S.solve(n=Infinity) sage: map( lambda x: S.subs(x), sols) [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] Not eliminating linear variables:: sage: sols = S.solve(n=Infinity, eliminate_linear_variables=False) sage: map( lambda x: S.subs(x), sols) [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] A tricky case where the linear equations are insatisfiable:: sage: R.<x,y,z> = BooleanPolynomialRing() sage: S = Sequence([x*y*z+x*y+z*y+x*z, x+y+z+1, x+y+z]) sage: S.solve() [] """ from sage.rings.polynomial.pbori import BooleanPolynomialRing from sage.modules.free_module import VectorSpace S = self R_origin = R_solving = self.ring() reductors = [] if eliminate_linear_variables: T, reductors = self.eliminate_linear_variables(return_reductors=True) if T.variables() != (): R_solving = BooleanPolynomialRing( T.nvariables(), map(str, list(T.variables())) ) S = PolynomialSequence( R_solving, [ R_solving(f) for f in T] ) if S != []: if algorithm == "exhaustive_search": if not is_package_installed('fes'): raise ValueError('algorithm=exhaustive_search requires the optional library FES. Run "install_package(\'fes\')" to install it.') from sage.libs.fes import exhaustive_search solutions = exhaustive_search(S, max_sols=n, verbose=verbose, **kwds) elif algorithm == "polybori": I = S.ideal() if verbose: I.groebner_basis(full_prot=True, **kwds) else: I.groebner_basis(**kwds) solutions = I.variety() if len(solutions) >= n: solutions = solutions[:n] elif algorithm == "sat": from sage.sat.boolean_polynomials import solve as solve_sat if verbose: solutions = solve_sat(S, n=n, s_verbosity=1, **kwds) else: solutions = solve_sat(S, n=n, **kwds) else: raise ValueError("unknown 'algorithm' value") else: solutions = [] if S.variables() == (): solved_variables = set() else: solved_variables = { R_origin(x).lm() for x in R_solving.gens() } eliminated_variables = { f.lex_lead() for f in reductors } leftover_variables = { x.lm() for x in R_origin.gens() } - solved_variables - eliminated_variables if leftover_variables != set(): partial_solutions = solutions solutions = [] for sol in partial_solutions: for v in VectorSpace( GF(2), len(leftover_variables) ): new_solution = sol.copy() for var,val in zip(leftover_variables, v): new_solution[ var ] = val solutions.append( new_solution ) for r in reductors: for sol in solutions: sol[ r.lm() ] = r.subs(sol).constant_coefficient() return solutions
# theme to set a Pygments style, stylesheet, and insert jsMath macros. See # the directory doc/common/themes/sage/ for files comprising the custom Sage # theme. html_theme = 'sage' # Theme options are theme-specific and customize the look and feel of # a theme further. For a list of options available for each theme, # see the documentation. html_theme_options = {} if 'SAGE_DOC_JSMATH' in os.environ: from sage.misc.latex_macros import sage_jsmath_macros_easy html_theme_options['jsmath_macros'] = sage_jsmath_macros_easy from sage.misc.package import is_package_installed html_theme_options['jsmath_image_fonts'] = is_package_installed('jsmath-image-fonts') # Add any paths that contain custom themes here, relative to this directory. html_theme_path = [os.path.join(SAGE_DOC, 'common/themes')] # HTML style sheet NOTE: This overrides a HTML theme's corresponding # setting. #html_style = 'default.css' # The name for this set of Sphinx documents. If None, it defaults to # "<project> v<release> documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None
def structure_description(G, latex=False): r""" Return a string that tries to describe the structure of ``G``. This methods wraps GAP's ``StructureDescription`` method. Requires the *optional* ``database_gap`` package. For full details, including the form of the returned string and the algorithm to build it, see `GAP's documentation <http://www.gap-system.org/Manuals/doc/ref/chap39.html>`_. INPUT: - ``latex`` -- a boolean (default: ``False``). If ``True`` return a LaTeX formatted string. OUTPUT: - string .. WARNING:: From GAP's documentation: The string returned by ``StructureDescription`` is **not** an isomorphism invariant: non-isomorphic groups can have the same string value, and two isomorphic groups in different representations can produce different strings. EXAMPLES:: sage: G = CyclicPermutationGroup(6) sage: G.structure_description() # optional - database_gap 'C6' sage: G.structure_description(latex=True) # optional - database_gap 'C_{6}' sage: G2 = G.direct_product(G, maps=False) sage: LatexExpr(G2.structure_description(latex=True)) # optional - database_gap C_{6} \times C_{6} This method is mainly intended for small groups or groups with few normal subgroups. Even then there are some surprises:: sage: D3 = DihedralGroup(3) sage: D3.structure_description() # optional - database_gap 'S3' We use the Sage notation for the degree of dihedral groups:: sage: D4 = DihedralGroup(4) sage: D4.structure_description() # optional - database_gap 'D4' Works for finitely presented groups (:trac:`17573`):: sage: F.<x, y> = FreeGroup() sage: G=F / [x^2*y^-1, x^3*y^2, x*y*x^-1*y^-1] sage: G.structure_description() # optional - database_gap 'C7' And matrix groups (:trac:`17573`):: sage: groups.matrix.GL(4,2).structure_description() # optional - database_gap 'A8' """ import re from sage.misc.package import is_package_installed def correct_dihedral_degree(match): return "%sD%d" % (match.group(1), int(match.group(2)) / 2) try: description = G._gap_().StructureDescription().__str__() except RuntimeError: if not is_package_installed('database_gap'): raise RuntimeError( "You must install the optional database_gap package first.") raise description = re.sub(r"(\A|\W)D(\d+)", correct_dihedral_degree, description) if not latex: return description description = description.replace("x", r"\times").replace(":", r"\rtimes") description = re.sub(r"([A-Za-z]+)([0-9]+)", r"\g<1>_{\g<2>}", description) description = re.sub(r"O([+-])", r"O^{\g<1>}", description) return description
def CossidentePenttilaGraph(q): r""" Cossidente-Penttila `((q^3+1)(q+1)/2,(q^2+1)(q-1)/2,(q-3)/2,(q-1)^2/2)`-strongly regular graph For each odd prime power `q`, one can partition the points of the `O_6^-(q)`-generalized quadrange `GQ(q,q^2)` into two parts, so that on any of them the induced subgraph of the point graph of the GQ has parameters as above [CP05]_. Directly follwing the construction in [CP05]_ is not efficient, as one then needs to construct the dual `GQ(q^2,q)`. Thus we describe here a more efficient approach that we came up with, following a suggestion by T.Penttila. Namely, this partition is invariant under the subgroup `H=\Omega_3(q^2)<O_6^-(q)`. We build the appropriate `H`, which leaves the form `B(X,Y,Z)=XY+Z^2` invariant, and pick up two orbits of `H` on the `F_q`-points. One them is `B`-isotropic, and we take the representative `(1:0:0)`. The other one corresponds to the points of `PG(2,q^2)` that have all the lines on them either missing the conic specified by `B`, or intersecting the conic in two points. We take `(1:1:e)` as the representative. It suffices to pick `e` so that `e^2+1` is not a square in `F_{q^2}`. Indeed, The conic can be viewed as the union of `\{(0:1:0)\}` and `\{(1:-t^2:t) | t \in F_{q^2}\}`. The coefficients of a generic line on `(1:1:e)` are `[1:-1-eb:b]`, for `-1\neq eb`. Thus, to make sure the intersection with the conic is always even, we need that the discriminant of `1+(1+eb)t^2+tb=0` never vanishes, and this is if and only if `e^2+1` is not a square. Further, we need to adjust `B`, by multiplying it by appropriately chosen `\nu`, so that `(1:1:e)` becomes isotropic under the relative trace norm `\nu B(X,Y,Z)+(\nu B(X,Y,Z))^q`. The latter is used then to define the graph. INPUT: - ``q`` -- an odd prime power. EXAMPLES: For `q=3` one gets Sims-Gewirtz graph. :: sage: G=graphs.CossidentePenttilaGraph(3) # optional - gap_packages (grape) sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) (56, 10, 0, 2) For `q>3` one gets new graphs. :: sage: G=graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) (378, 52, 1, 8) TESTS:: sage: G=graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time (1376, 150, 2, 18) sage: graphs.CossidentePenttilaGraph(2) Traceback (most recent call last): ... ValueError: q(=2) must be an odd prime power REFERENCES: .. [CP05] A.Cossidente and T.Penttila Hemisystems on the Hermitian surface Journal of London Math. Soc. 72(2005), 731-741 """ p, k = is_prime_power(q,get_data=True) if k==0 or p==2: raise ValueError('q(={}) must be an odd prime power'.format(q)) from sage.libs.gap.libgap import libgap from sage.misc.package import is_package_installed, PackageNotFoundError if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') adj_list=libgap.function_factory("""function(q) local z, e, so, G, nu, G1, G0, B, T, s, O1, O2, x; LoadPackage("grape"); G0:=SO(3,q^2); so:=GeneratorsOfGroup(G0); G1:=Group(Comm(so[1],so[2]),Comm(so[1],so[3]),Comm(so[2],so[3])); B:=InvariantBilinearForm(G0).matrix; z:=Z(q^2); e:=z; sqo:=(q^2-1)/2; if IsInt(sqo/Order(e^2+z^0)) then e:=z^First([2..q^2-2], x-> not IsInt(sqo/Order(z^(2*x)+z^0))); fi; nu:=z^First([0..q^2-2], x->z^x*(e^2+z^0)+(z^x*(e^2+z^0))^q=0*z); T:=function(x) local r; r:=nu*x*B*x; return r+r^q; end; s:=Group([Z(q)*IdentityMat(3,GF(q))]); O1:=Orbit(G1, Set(Orbit(s,z^0*[1,0,0])), OnSets); O2:=Orbit(G1, Set(Orbit(s,z^0*[1,1,e])), OnSets); G:=Graph(G1,Concatenation(O1,O2),OnSets, function(x,y) return x<>y and 0*z=T(x[1]+y[1]); end); return List([1..OrderGraph(G)],x->Adjacency(G,x)); end;""") adj = adj_list(q) # for each vertex, we get the list of vertices it is adjacent to G = Graph(((i,int(j-1)) for i,ni in enumerate(adj) for j in ni), format='list_of_edges', multiedges=False) G.name('CossidentePenttila('+str(q)+')') return G
def lovasz_theta(graph): r""" Return the value of Lovász theta-function of graph For a graph `G` this function is denoted by `\theta(G)`, and it can be computed in polynomial time. Mathematically, its most important property is the following: .. MATH:: \alpha(G)\leq\theta(G)\leq\chi(\overline{G}) with `\alpha(G)` and `\chi(\overline{G})` being, respectively, the maximum size of an :meth:`independent set <sage.graphs.graph.Graph.independent_set>` set of `G` and the :meth:`chromatic number <sage.graphs.graph.Graph.chromatic_number>` of the :meth:`complement <sage.graphs.generic_graph.GenericGraph.complement>` `\overline{G}` of `G`. For more information, see the :wikipedia:`Lovász_number`. .. NOTE:: - Implemented for undirected graphs only. Use to_undirected to convert a digraph to an undirected graph. - This function requires the optional package ``csdp``, which you can install with with ``sage -i csdp``. EXAMPLES:: sage: C=graphs.PetersenGraph() sage: C.lovasz_theta() # optional csdp 4.0 sage: graphs.CycleGraph(5).lovasz_theta() # optional csdp 2.236068 TEST:: sage: g = Graph() sage: g.lovasz_theta() # indirect doctest 0 """ n = graph.order() if n == 0: return 0 from networkx import write_edgelist from sage.misc.temporary_file import tmp_filename import os, subprocess from sage.env import SAGE_LOCAL from sage.misc.package import is_package_installed, PackageNotFoundError if not is_package_installed('csdp'): raise PackageNotFoundError("csdp") g = graph.relabel(inplace=False, perm=range(1,n+1)).networkx_graph() tf_name = tmp_filename() tf = open(tf_name, 'wb') tf.write(str(n)+'\n'+str(g.number_of_edges())+'\n') write_edgelist(g, tf, data=False) tf.close() lines = subprocess.check_output([os.path.join(SAGE_LOCAL, 'bin', 'theta'), tf_name]) return float(lines.split()[-1])
def nauty(self, number_of_sets, number_of_vertices, multiple_sets=False, vertex_min_degree=None, vertex_max_degree=None, set_max_size=None, set_min_size=None, regular=False, uniform=False, max_intersection=None, connected=False, options="", debug=False): r""" Enumerates hypergraphs up to isomorphism using Nauty. INPUT: - ``number_of_sets``, ``number_of_vertices`` (integers) - ``multiple_sets`` (boolean) -- whether to allow several sets of the hypergraph to be equal (set to ``False`` by default). - ``vertex_min_degree``, ``vertex_max_degree`` (integers) -- define the maximum and minimum degree of an element from the ground set (i.e. the number of sets which contain it). Set to ``None`` by default. - ``set_min_size``, ``set_max_size`` (integers) -- define the maximum and minimum size of a set. Set to ``None`` by default. - ``regular`` (integer) -- if set to an integer value `k`, requires the hypergraphs to be `k`-regular. It is actually a shortcut for the corresponing min/max values. - ``uniform`` (integer) -- if set to an integer value `k`, requires the hypergraphs to be `k`-uniform. It is actually a shortcut for the corresponing min/max values. - ``max_intersection`` (integer) -- constraints the maximum cardinality of the intersection of two sets fro the hypergraphs. Set to ``None`` by default. - ``connected`` (boolean) -- whether to require the hypergraphs to be connected. Set to ``False`` by default. - ``debug`` (boolean) -- if ``True`` the first line of genbg's output to standard error is captured and the first call to the generator's ``next()`` function will return this line as a string. A line leading with ">A" indicates a successful initiation of the program with some information on the arguments, while a line beginning with ">E" indicates an error with the input. - ``options`` (string) -- anything else that should be forwarded as input to Nauty's genbg. See its documentation for more information : `<http://cs.anu.edu.au/~bdm/nauty/>`_. .. NOTE:: For genbg the *first class* elements are vertices, and *second class* elements are the hypergraph's sets. OUTPUT: A tuple of tuples. EXAMPLES: Small hypergraphs:: sage: list(hypergraphs.nauty(4,2)) # optional - nauty [((), (0,), (1,), (0, 1))] Only connected ones:: sage: list(hypergraphs.nauty(2,2, connected = True)) # optional - nauty [((0,), (0, 1))] Non-empty sets only:: sage: list(hypergraphs.nauty(3,2, set_min_size = 1)) # optional - nauty [((0,), (1,), (0, 1))] The Fano Plane, as the only 3-uniform hypergraph with 7 sets and 7 vertices:: sage: fano = next(hypergraphs.nauty(7, 7, uniform=3, max_intersection=1)) # optional - nauty sage: print fano # optional - nauty ((0, 1, 2), (0, 3, 4), (0, 5, 6), (1, 3, 5), (2, 4, 5), (2, 3, 6), (1, 4, 6)) The Fano Plane, as the only 3-regular hypergraph with 7 sets and 7 vertices:: sage: fano = next(hypergraphs.nauty(7, 7, regular=3, max_intersection=1)) # optional - nauty sage: print fano # optional - nauty ((0, 1, 2), (0, 3, 4), (0, 5, 6), (1, 3, 5), (2, 4, 5), (2, 3, 6), (1, 4, 6)) """ import subprocess from sage.misc.package import is_package_installed if not is_package_installed("nauty"): raise TypeError( "The optional nauty spkg does not seem to be installed") nauty_input = options if connected: nauty_input += " -c" if not multiple_sets: nauty_input += " -z" if not max_intersection is None: nauty_input += " -Z" + str(max_intersection) # degrees and sizes if not regular is False: vertex_max_degree = vertex_min_degree = regular if vertex_max_degree is None: vertex_max_degree = number_of_sets if vertex_min_degree is None: vertex_min_degree = 0 if not uniform is False: set_max_size = set_min_size = uniform if set_max_size is None: set_max_size = number_of_vertices if set_min_size is None: set_min_size = 0 nauty_input += " -d" + str(vertex_min_degree) + ":" + str(set_min_size) nauty_input += " -D" + str(vertex_max_degree) + ":" + str(set_max_size) nauty_input += " " + str(number_of_vertices) + " " + str( number_of_sets) + " " sp = subprocess.Popen("genbg {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) if debug: yield sp.stderr.readline() gen = sp.stdout total = number_of_sets + number_of_vertices while True: try: s = next(gen) except StopIteration: raise StopIteration("Exhausted list of graphs from nauty geng") from sage.graphs.graph import Graph G = Graph(s[:-1], format='graph6') yield tuple( tuple(x for x in G.neighbors(v)) for v in range(number_of_vertices, total))
def bounds_on_minimum_distance_in_guava(n, k, F): r""" Computes a lower and upper bound on the greatest minimum distance of a `[n,k]` linear code over the field ``F``. This function requires the optional GAP package GUAVA. The function returns a GAP record with the two bounds and an explanation for each bound. The function Display can be used to show the explanations. The values for the lower and upper bound are obtained from a table constructed by Cen Tjhai for GUAVA, derived from the table of Brouwer. See http://www.codetables.de/ for the most recent data. These tables contain lower and upper bounds for `q=2` (when ``n <= 257``), `q=3` (when ``n <= 243``), `q=4` (``n <= 256``). (Current as of 11 May 2006.) For codes over other fields and for larger word lengths, trivial bounds are used. INPUT: - ``n`` -- the length of the code to look up - ``k`` -- the dimension of the code to look up - ``F`` -- the base field of the code to look up OUTPUT: - A GAP record object. See below for an example. EXAMPLES:: sage: gap_rec = codes.databases.bounds_on_minimum_distance_in_guava(10,5,GF(2)) # optional - gap_packages (Guava package) sage: print(gap_rec) # optional - gap_packages (Guava package) rec( construction := [ <Operation "ShortenedCode">, [ [ <Operation "UUVCode">, [ [ <Operation "DualCode">, [ [ <Operation "RepetitionCode">, [ 8, 2 ] ] ] ], [ <Operation "UUVCode">, [ [ <Operation "DualCode">, [ [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ] , [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ] ] ], [ 1, 2, 3, 4, 5, 6 ] ] ], k := 5, lowerBound := 4, lowerBoundExplanation := ... n := 10, q := 2, references := rec( ), upperBound := 4, upperBoundExplanation := ... ) """ if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') gap.load_package("guava") q = F.order() gap.eval("data := BoundsMinimumDistance(%s,%s,GF(%s))" % (n, k, q)) Ldata = gap.eval("Display(data)") return Ldata
def structure_description(G, latex=False): r""" Return a string that tries to describe the structure of ``G``. This methods wraps GAP's ``StructureDescription`` method. Requires the *optional* ``database_gap`` package. For full details, including the form of the returned string and the algorithm to build it, see `GAP's documentation <http://www.gap-system.org/Manuals/doc/ref/chap39.html>`_. INPUT: - ``latex`` -- a boolean (default: ``False``). If ``True`` return a LaTeX formatted string. OUTPUT: - string .. WARNING:: From GAP's documentation: The string returned by ``StructureDescription`` is **not** an isomorphism invariant: non-isomorphic groups can have the same string value, and two isomorphic groups in different representations can produce different strings. EXAMPLES:: sage: G = CyclicPermutationGroup(6) sage: G.structure_description() # optional - database_gap 'C6' sage: G.structure_description(latex=True) # optional - database_gap 'C_{6}' sage: G2 = G.direct_product(G, maps=False) sage: LatexExpr(G2.structure_description(latex=True)) # optional - database_gap C_{6} \times C_{6} This method is mainly intended for small groups or groups with few normal subgroups. Even then there are some surprises:: sage: D3 = DihedralGroup(3) sage: D3.structure_description() # optional - database_gap 'S3' We use the Sage notation for the degree of dihedral groups:: sage: D4 = DihedralGroup(4) sage: D4.structure_description() # optional - database_gap 'D4' Works for finitely presented groups (:trac:`17573`):: sage: F.<x, y> = FreeGroup() sage: G=F / [x^2*y^-1, x^3*y^2, x*y*x^-1*y^-1] sage: G.structure_description() # optional - database_gap 'C7' And matrix groups (:trac:`17573`):: sage: groups.matrix.GL(4,2).structure_description() # optional - database_gap 'A8' """ import re from sage.misc.package import is_package_installed def correct_dihedral_degree(match): return "%sD%d" % (match.group(1), int(match.group(2))/2) try: description = str(G._gap_().StructureDescription()) except RuntimeError: if not is_package_installed('database_gap'): raise RuntimeError("You must install the optional database_gap package first.") raise description = re.sub(r"(\A|\W)D(\d+)", correct_dihedral_degree, description) if not latex: return description description = description.replace("x", r"\times").replace(":", r"\rtimes") description = re.sub(r"([A-Za-z]+)([0-9]+)", r"\g<1>_{\g<2>}", description) description = re.sub(r"O([+-])", r"O^{\g<1>}", description) return description
def tournaments_nauty(self, n, min_out_degree = None, max_out_degree = None, strongly_connected = False, debug=False, options=""): r""" Returns all tournaments on `n` vertices using Nauty. INPUT: - ``n`` (integer) -- number of vertices. - ``min_out_degree``, ``max_out_degree`` (integers) -- if set to ``None`` (default), then the min/max out-degree is not constrained. - ``debug`` (boolean) -- if ``True`` the first line of genbg's output to standard error is captured and the first call to the generator's ``next()`` function will return this line as a string. A line leading with ">A" indicates a successful initiation of the program with some information on the arguments, while a line beginning with ">E" indicates an error with the input. - ``options`` (string) -- anything else that should be forwarded as input to Nauty's genbg. See its documentation for more information : `<http://cs.anu.edu.au/~bdm/nauty/>`_. .. NOTE:: To use this method you must first install the Nauty spkg. EXAMPLES:: sage: for g in digraphs.tournaments_nauty(4): # optional - nauty ....: print g.edges(labels = False) # optional - nauty [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)] [(1, 0), (1, 3), (2, 0), (2, 1), (3, 0), (3, 2)] [(0, 2), (1, 0), (2, 1), (3, 0), (3, 1), (3, 2)] [(0, 2), (0, 3), (1, 0), (2, 1), (3, 1), (3, 2)] sage: tournaments = digraphs.tournaments_nauty sage: [len(list(tournaments(x))) for x in range(1,8)] # optional - nauty [1, 1, 2, 4, 12, 56, 456] sage: [len(list(tournaments(x, strongly_connected = True))) for x in range(1,9)] # optional - nauty [1, 0, 1, 1, 6, 35, 353, 6008] """ import subprocess from sage.misc.package import is_package_installed if not is_package_installed("nauty"): raise TypeError("The optional nauty spkg does not seem to be installed") nauty_input = options if min_out_degree is None: min_out_degree = 0 if max_out_degree is None: max_out_degree = n-1 nauty_input += " -d"+str(min_out_degree) nauty_input += " -D"+str(max_out_degree) if strongly_connected: nauty_input += " -c" nauty_input += " "+str(n) +" " sp = subprocess.Popen("nauty-gentourng {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) if debug: yield sp.stderr.readline() gen = sp.stdout while True: try: s = gen.next() except StopIteration: raise StopIteration("Exhausted list of graphs from nauty geng") G = DiGraph(n) i = 0 j = 1 for b in s[:-1]: if b == '0': G.add_edge(i,j) else: G.add_edge(j,i) if j == n-1: i += 1 j = i+1 else: j += 1 yield G
{self._spec["primary_key"]: self._zooid}, cur = cur) update(self._graphprops, "name", new) else: return Graph.name(self, new, *largs, **kargs) @override.determined(is_bipartite = PlusInfinity(), is_forest = PlusInfinity()) def odd_girth(self, value, attrs, **kargs): inf = value == PlusInfinity() if inf: del attrs["is_forest"] return (not inf, attrs) AVAILABLE_ALGORITHMS = ["sage"] if is_package_installed("bliss"): AVAILABLE_ALGORITHMS.insert(0, "bliss") def canonical_label(graph, **kargs): r""" Return the canonical labeling of ``graph``. INPUT: - ``graph`` - the graph to compute the canonical labelling for. - ``algorithm`` - the algorithm to use to compute the canonical labelling. The default value ``None`` means that ``'bliss'`` will be used if available, and ``'sage'`` otherwise. """ algorithm = lookup(kargs, "algorithm", default = None)