def UnitaryDualPolarGraph(m, q): r""" Returns the Dual Unitary Polar Graph `U(m,q)`. For more information on Unitary Dual Polar graphs, see [BCN89]_ and Sect. 2.3.1 of [Co81]_. INPUT: - ``m,q`` (integers) -- `q` must be a prime power. EXAMPLES: The point graph of a generalized quadrangle of order (8,4):: sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices sage: G.is_strongly_regular(parameters=True) # long time (297, 40, 7, 5) Another way to get the generalized quadrangle of order (2,4):: sage: G = graphs.UnitaryDualPolarGraph(4,2); G Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-')) True A bigger graph:: sage: G = graphs.UnitaryDualPolarGraph(6,2); G # not tested (long time) Unitary Dual Polar Graph DU(6, 2): Graph on 891 vertices sage: G.is_distance_regular(parameters=True) # not tested (long time) ([42, 40, 32, None], [None, 1, 5, 21]) TESTS:: sage: graphs.UnitaryDualPolarGraph(6,6) Traceback (most recent call last): ... ValueError: libGAP: Error, <subfield> must be a prime or a finite field """ from sage.libs.gap.libgap import libgap G = _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q), intersection_size=(q**(2 * (m // 2 - 1)) - 1) / (q**2 - 1)) G.relabel() G.name("Unitary Dual Polar Graph DU" + str((m, q))) if m == 4: G.name(G.name() + '; GQ' + str((q, q**2))) if m == 5: G.name(G.name() + '; GQ' + str((q**3, q**2))) return G
def NonisotropicUnitaryPolarGraph(m, q): r""" Returns the Graph `NU(m,q)`. Returns the graph on nonisotropic, with respect to a nondegenerate Hermitean form, points of the `(m-1)`-dimensional projective space over `F_q`, with points adjacent whenever they lie on a tangent (to the set of isotropic points) line. For more information, see Sect. 9.9 of [BH12]_ and series C14 in [Hu75]_. INPUT: - ``m,q`` (integers) -- `q` must be a prime power. EXAMPLES:: sage: g=graphs.NonisotropicUnitaryPolarGraph(5,2); g NU(5, 2): Graph on 176 vertices sage: g.is_strongly_regular(parameters=True) (176, 135, 102, 108) TESTS:: sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) (40, 27, 18, 18) sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time (540, 224, 88, 96) sage: graphs.NonisotropicUnitaryPolarGraph(6,6) Traceback (most recent call last): ... ValueError: q must be a prime power REFERENCE: .. [Hu75] X. L. Hubaut. Strongly regular graphs. Disc. Math. 13(1975), pp 357--381. http://dx.doi.org/10.1016/0012-365X(75)90057-6 """ from sage.rings.arith import is_prime_power p, k = is_prime_power(q, get_data=True) if k == 0: raise ValueError('q must be a prime power') from sage.libs.gap.libgap import libgap from itertools import combinations F = libgap.GF(q**2) # F_{q^2} W = libgap.FullRowSpace(F, m) # F_{q^2}^m B = libgap.Elements(libgap.Basis(W)) # the standard basis of W if m % 2 != 0: point = B[(m - 1) / 2] else: if p == 2: point = B[m / 2] + F.PrimitiveRoot() * B[(m - 2) / 2] else: point = B[(m - 2) / 2] + B[m / 2] g = libgap.GeneralUnitaryGroup(m, q) V = libgap.Orbit(g, point, libgap.OnLines) # orbit on nonisotropic points gp = libgap.Action(g, V, libgap.OnLines) # make a permutation group s = libgap.Subspace(W, [point, point + B[0]]) # a tangent line on point # and the points there sp = [ libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1)) ] h = libgap.Set( map(lambda x: libgap.Position(V, x), libgap.Intersection(V, sp))) # indices L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on the tangent lines G = Graph() for x in L: # every pair of points in the subspace is adjacent to each other in G G.add_edges(combinations(x, 2)) G.relabel() G.name("NU" + str((m, q))) return G
def UnitaryPolarGraph(m, q, algorithm="gap"): r""" Returns the Unitary Polar Graph `U(m,q)`. For more information on Unitary Polar graphs, see the `page of Andries Brouwer's website <http://www.win.tue.nl/~aeb/graphs/srghub.html>`_. INPUT: - ``m,q`` (integers) -- `q` must be a prime power. - ``algorithm`` -- if set to 'gap' then the computation is carried via GAP library interface, computing totally singular subspaces, which is faster for large examples (especially with `q>2`). Otherwise it is done directly. EXAMPLES:: sage: G = graphs.UnitaryPolarGraph(4,2); G Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices sage: G.is_strongly_regular(parameters=True) (45, 12, 3, 3) sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True) (165, 36, 3, 9) sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time) Unitary Polar Graph U(6, 2): Graph on 693 vertices TESTS:: sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True) (280, 36, 8, 4) sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) (280, 36, 8, 4) sage: graphs.UnitaryPolarGraph(4,3, algorithm="foo") Traceback (most recent call last): ... ValueError: unknown algorithm! """ if algorithm == "gap": from sage.libs.gap.libgap import libgap G = _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q)) elif algorithm == None: # slow on large examples from sage.schemes.projective.projective_space import ProjectiveSpace from sage.rings.finite_rings.constructor import FiniteField from sage.modules.free_module_element import free_module_element as vector from __builtin__ import sum as psum Fq = FiniteField(q**2, 'a') PG = map(vector, ProjectiveSpace(m - 1, Fq)) map(lambda x: x.set_immutable(), PG) def P(x, y): return psum(map(lambda j: x[j] * y[m - 1 - j]**q, xrange(m))) == 0 V = filter(lambda x: P(x, x), PG) G = Graph( [ V, lambda x, y: # bottleneck is here, of course: P(x, y) ], loops=False) else: raise ValueError("unknown algorithm!") G.relabel() G.name("Unitary Polar Graph U" + str((m, q))) if m == 4: G.name(G.name() + '; GQ' + str((q**2, q))) if m == 5: G.name(G.name() + '; GQ' + str((q**2, q**3))) return G