Splitting fields of representations of generalized symmetric groups, 7

In this post, we discover which representations of the generalized symmetric group G = S_n\ wr\ C_\ell = C_\ell^n\, >\!\!\lhd \, S_n can be realized over a given abelian extension of {\mathbb{Q}}.

Let \theta_{\mu,\rho}\in G^* be the representation defined previously, where \rho\in ((S_n)_\mu)^*.

Let K\subset {\mathbb{Q}}(\zeta_\ell) be a subfield, where \zeta_\ell is a primitive \ell^{th} root of unity. Assume K contains the field generated by the values of the character of \theta_{\mu,\rho}. Assume K/{\mathbb{Q}} is Galois and let \Gamma_K=Gal({\mathbb{Q}}(\zeta_\ell)/K). Note if we regard C_\ell as a subset of {\mathbb{Q}}(\zeta_\ell) then there is an induced action of \Gamma_K on C_\ell,

\sigma:\mu \longmapsto \mu^\sigma, \ \ \ \ \ \ \ \ \ \mu\in (C_\ell)^*,\ \ \sigma\in \Gamma_K,

where \mu^\sigma(z)=\mu(\sigma^{-1}(z)), z\in C_\ell. This action extends to an action on (C_\ell^n)^*=(C_\ell^*)^n.

Key Lemma:
In the notation above, \theta_{\mu,\rho}\cong\theta_{\mu,\rho}^\sigma if and only if \mu is equivalent to \mu^\sigma under the action of S_n on (C_\ell^n)^*.

Let

n_\mu(\chi)=|\{i\ |\ 1\leq i\leq n,\ \mu_i=\chi\}|,

where \mu=(\mu_1,...,\mu_n)\in (C_\ell^n)^* and \chi\in C_\ell^*.

Theorem: The character of \theta_{\mu,\rho}\in G^* has values in K if and only if n_\mu(\chi)=n_\mu(\chi^\sigma),
for all \sigma\in \Gamma_K and all \chi\in C_\ell^*.

This theorem is proven in this paper.

We now determine the splitting field of any irreducible character of a generalized symmetric group.

Theorem: Let \chi=tr(\theta_{\rho,\mu}) be an irreducible character of G=S_n\ wr\ C_\ell. We have

Gal({\mathbb{Q}}(\zeta_\ell)/{\mathbb{Q}}(\chi))= Stab_\Gamma(\chi).

This theorem is also proven in this paper.

In the next post we shall give an example.

Linear systems of graphs in Sage

Let \Gamma be a graph. A divisor on \Gamma is an element of the free group generated by the vertices V, {\mathbb{Z}}[V].

We say that divisors D and D^\prime are linearly equivalent and write D \sim D^\prime if D^\prime-D is a principal divisor, i.e., if D^\prime = D + \text{div}(f) for some function f : V \rightarrow {\mathbb{Z}}. Note that if D and D^\prime are linearly equivalent, they must have the same degree, since the degree of every principal divisor is 0. Divisors of degree 0 are linearly equivalent if and only if they determine the same element of the Jacobian. If D is a divisor of degree 0, we denote by [D] the element of the Jacobian determined by D. A divisor D is said to be effective if D(v) \geq 0 for all vertices v. We write D \geq 0 to mean that D is effective. The linear system associated to a divisor D is the set

|D| = \{ D^\prime \in \text{Div}(\Gamma ) : D^\prime \geq 0 \text{ and } D^\prime \sim D\},

i.e., |D| is the set of all effective divisors linearly equivalent to D. Note that if D_1 \sim D_2, then |D_1| = |D_2|. We note also that if \text{deg}(D)<0, then |D| must be empty.

Sage can be used to compute the linear system of any divisor on a graph.

def linear_system(D, Gamma):
    """
    Returns linear system attached to the divisor D.

    EXAMPLES:
        sage: Gamma2 = graphs.CubeGraph(2)
        sage: Gamma1 = Gamma2.subgraph(vertices = ['00', '01'], edges = [('00', '01')])
        sage: f = [['00', '01', '10', '11'], ['00', '01', '00', '01']]
        sage: is_harmonic_graph_morphism(Gamma1, Gamma2, f)
        True
        sage: PhiV = matrix_of_graph_morphism_vertices(Gamma1, Gamma2, f); PhiV
        [1 0 1 0]
        [0 1 0 1]
        sage: D = vector([1,0,0,1])
        sage: PhiV*D
        (1, 1)
        sage: linear_system(PhiV*D, Gamma1)
        [(2, 0), (1, 1), (0, 2)]
        sage: linear_system(D, Gamma2)
        [(0, 2, 0, 0), (0, 0, 2, 0), (1, 0, 0, 1)]
        sage: [PhiV*x for x in linear_system(D, Gamma2)]
        [(0, 2), (2, 0), (1, 1)]

    """
    Q = Gamma.laplacian_matrix()
    CS = Q.column_space()
    N = len(D.list())
    d = sum(D.list())
    #print d
    lin_sys = []
    if d < 0:
        return lin_sys
    if (d == 0) and (D in CS):
        lin_sys = [CS(0)]
        return lin_sys
    elif (d == 0):
        return lin_sys
    S = IntegerModRing(d+1)^N
    V = QQ^N
    for v in S:
        v = V(v)
        #print D-v,v,D
        if D-v in CS:
            lin_sys.append(v)
    return lin_sys

 

Differential calculus using Sagemath

Granville’s classic text book Elements of the Differential and Integral Calculus fell into the public domain and then much of it (but not all, at the time of this writing) was scanned into wikisource primarily by R. J. Hall. Granville’s entire book contains material on differential, integral, and even multivariable calculus. The material in the subset here is restricted to differential calculus topics, though contains some material which might properly belong to an elementary differential geometry course. The above-mentioned wikisource document uses mathml and latex and some Greek letter fonts.

In particular, the existence of this document owes itself primarily to three great open source projects: TeX/LaTeX, Wikipedia, and Sagemath (http://www.sagemath.org). Some material from Sean Mauch’s public domain text on Applied Mathematics, was also included.

The current latex document is due to David Joyner, who is responsible for re-formatting, editing for readability, the correction (or introduction) of typos from the scanned version, and any extra material added (for example, the hyperlinked cross references, and the Sagemath material). Please email corrections to wdjoyner@gmail.com.

Though the original text of Granville is public domain, the extra material added in this version is licensed under the GNU Free Documentation License (please see the FDL) as is most of Wikipedia.

Acknowledgements: I thank the following readers for reporting typos: Mario Pernici, Jacob Hicks.

Now available from amazon.com for $20 (not including shipping).

Discrete Fourier transforms using Sagemath

Here are some Sagemath examples for DFTs, DCTs, and DST’s. You can try copying and pasting them into the Sagemath cloud, for example.

The Sagemath dft command applies to a sequence S indexed by a set J computes the un-normalized DFT: (in Python)

[sum([S[i]*chi(zeta**(i*j)) for i in J]) for j in J]Here are some examples which explain the syntax:

sage: J = range(6)
sage: A = [ZZ(1) for i in J]
sage: s = IndexedSequence(A,J)
sage: s.dft(lambda x:x^2)
   Indexed sequence: [6, 0, 0, 6, 0, 0]
   indexed by [0, 1, 2, 3, 4, 5]
sage: s.dft()
   Indexed sequence: [6, 0, 0, 0, 0, 0]
   indexed by [0, 1, 2, 3, 4, 5]
sage: G = SymmetricGroup(3)
sage: J = G.conjugacy_classes_representatives()
sage: s = IndexedSequence([1,2,3],J) # 1,2,3 are the values of a class fcn on G
sage: s.dft()   # the "scalar-valued Fourier transform" of this class fcn
    Indexed sequence: [8, 2, 2]
    indexed by [(), (1,2), (1,2,3)]
sage: J = AbelianGroup(2,[2,3],names='ab')
sage: s = IndexedSequence([1,2,3,4,5,6],J)
sage: s.dft()   # the precision of output is somewhat random and arch. dependent.
    Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I]                
     indexed by Multiplicative Abelian Group isomorphic to C2 x C3
sage: J = CyclicPermutationGroup(6)
sage: s = IndexedSequence([1,2,3,4,5,6],J)
sage: s.dft()   # the precision of output is somewhat random and arch. dependent.
    Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I]
     indexed by Cyclic group of order 6 as a permutation group
sage: p = 7; J = range(p); A = [kronecker_symbol(j,p) for j in J]
age: s = IndexedSequence(A,J)
sage: Fs = s.dft()
sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list()
     [0, 1, 1, -1, 1, -1, -1]
     [0, 1, 1, -1, 1, -1, -1]

 

The DFT of the values of the quadratic residue symbol is itself, up to a constant factor (denoted c on the last line above).

Here is a 2nd example:

sage: J = range(5)
sage: A = [ZZ(1) for i in J]
sage: s = IndexedSequence(A,J)
sage: fs = s.dft(); fs
  Indexed sequence: [5, 0, 0, 0, 0]
   indexed by [0, 1, 2, 3, 4]
sage: it = fs.idft(); it
  Indexed sequence: [1, 1, 1, 1, 1]
   indexed by [0, 1, 2, 3, 4]
age: it == s
True
sage: t = IndexedSequence(B,J)
sage: s.convolution(t)
 [1, 2, 3, 4, 5, 4, 3, 2, 1]

Here is a 3rd example:

sage: J = range(5)
sage: A = [exp(-2*pi*i*I/5) for i in J]
sage: s = IndexedSequence(A,J)
sage: s.dct()    # discrete cosine
   Indexed sequence: [2.50000000000011 + 0.00000000000000582867087928207*I, 2.50000000000011 + 0.00000000000000582867087928207*I, 2.50000000000011 + 0.00000000000000582867087928207*I, 2.50000000000011 + 0.00000000000000582867087928207*I, 2.50000000000011 + 0.00000000000000582867087928207*I]
    indexed by [0, 1, 2, 3, 4]
sage: s.dst()        # discrete sine
  Indexed sequence: [0.0000000000000171529457304586 - 2.49999999999915*I, 0.0000000000000171529457304586 - 2.49999999999915*I, 0.0000000000000171529457304586 - 2.49999999999915*I, 0.0000000000000171529457304586 - 2.49999999999915*I, 0.0000000000000171529457304586 - 2.49999999999915*I]
   indexed by [0, 1, 2, 3, 4]

Here is a 4th example:

sage: I = range(3)
sage: A = [ZZ(i^2)+1 for i in I]
sage: s = IndexedSequence(A,I)
sage: P1 = s.plot()
sage: P2 = s.plot_histogram()

P1 and P2 are displayed below:

The plots of P1

The plot of P1

The plot of P2

The plot of P2

Examples of graph-theoretic harmonic maps using Sage

In the case of simple graphs (without multiple edges or loops), a map f between graphs \Gamma_2 = (V_2,E_2) and \Gamma_1 = (V_1, E_1) can be uniquely defined by specifying where the vertices of \Gamma_2 go. If n_2 = |V_2| and n_1 = |V_1| then this is a list of length n_2 consisting of elements taken from the n_1 vertices in V_1.

Let’s look at an example.

Example: Let \Gamma_2 denote the cube graph in {\mathbb{R}}^3 and let \Gamma_1 denote the “cube graph” (actually the unit square) in {\mathbb{R}}^2.

This is the 3-diml cube graph

This is the 3-diml cube graph \Gamma_2 in Sagemath

The cycle graph on 4 vertices

The cycle graph \Gamma_1 on 4 vertices (also called the cube graph in 2-dims, created using Sagemath.

We define a map f:\Gamma_2\to \Gamma_1 by

f = [[‘000’, ‘001’, ‘010’, ‘011’, ‘100’, ‘101’, ‘110’, ‘111’], [“00”, “00”, “01”, “01”, “10”, “10”, “11”, “11”]].

Definition: For any vertex v of a graph \Gamma, we define the star St_\Gamma(v) to be a subgraph of \Gamma induced by the edges incident to v. A map f : \Gamma_2 \to \Gamma_1 is called harmonic if for all vertices v' \in V(\Gamma_2), the quantity

|\phi^{-1}(e) \cap St_{\Gamma_2}(v')|

is independent of the choice of edge e in St_{\Gamma_1}(\phi(v')).

 
Here is Python code in Sagemath which tests if a function is harmonic:

def is_harmonic_graph_morphism(Gamma1, Gamma2, f, verbose = False):
    """
    Returns True if f defines a graph-theoretic mapping
    from Gamma2 to Gamma1 that is harmonic, and False otherwise. 

    Suppose Gamma2 has n vertices. A morphism 
              f: Gamma2 -> Gamma1
    is represented by a pair of lists [L2, L1],
    where L2 is the list of all n vertices of Gamma2,
    and L1 is the list of length n of the vertices
    in Gamma1 that form the corresponding image under
    the map f.

    EXAMPLES:
        sage: Gamma2 = graphs.CubeGraph(2)
        sage: Gamma1 = Gamma2.subgraph(vertices = ['00', '01'], edges = [('00', '01')])
        sage: f = [['00', '01', '10', '11'], ['00', '01', '00', '01']]
        sage: is_harmonic_graph_morphism(Gamma1, Gamma2, f)
        True
        sage: Gamma2 = graphs.CubeGraph(3)
        sage: Gamma1 = graphs.TetrahedralGraph()
        sage: f = [['000', '001', '010', '011', '100', '101', '110', '111'], [0, 1, 2, 3, 3, 2, 1, 0]]
        sage: is_harmonic_graph_morphism(Gamma1, Gamma2, f)
        True
        sage: Gamma2 = graphs.CubeGraph(3)
        sage: Gamma1 = graphs.CubeGraph(2)
        sage: f = [['000', '001', '010', '011', '100', '101', '110', '111'], ["00", "00", "01", "01", "10", "10", "11", "11"]]
        sage: is_harmonic_graph_morphism(Gamma1, Gamma2, f)
        True
        sage: is_harmonic_graph_morphism(Gamma1, Gamma2, f, verbose=True)
        This [, ]] passes the check: ['000', [1, 1]]
        This [, ]] passes the check: ['001', [1, 1]]
        This [, ]] passes the check: ['010', [1, 1]]
        This [, ]] passes the check: ['011', [1, 1]]
        This [, ]] passes the check: ['100', [1, 1]]
        This [, ]] passes the check: ['101', [1, 1]]
        This [, ]] passes the check: ['110', [1, 1]]
        This [, ]] passes the check: ['111', [1, 1]]
        True
        sage: Gamma2 = graphs.TetrahedralGraph()
        sage: Gamma1 = graphs.CycleGraph(3)
        sage: f = [[0,1,2,3],[0,1,2,0]]
        sage: is_harmonic_graph_morphism(Gamma1, Gamma2, f)
        False
        sage: is_harmonic_graph_morphism(Gamma1, Gamma2, f, verbose=True)
        This [, ]] passes the check: [0, [1, 1]]
        This [, ]] fails the check: [1, [2, 1]]
        This [, ]] fails the check: [2, [2, 1]]
        False

    """
    V1 = Gamma1.vertices()
    n1 = len(V1)
    V2 = Gamma2.vertices()
    n2 = len(V2)
    E1 = Gamma1.edges()
    m1 = len(E1)
    E2 = Gamma2.edges()
    m2 = len(E2)
    edges_in_common = []
    for v2 in V2:
        w = image_of_vertex_under_graph_morphism(Gamma1, Gamma2, f, v2)
        str1 = star_subgraph(Gamma1, w)
        Ew = str1.edges()
        str2 = star_subgraph(Gamma2, v2)
        Ev2 = str2.edges()
        sizes = []
        for e in Ew:
            finv_e = preimage_of_edge_under_graph_morphism(Gamma1, Gamma2, f, e)
            L = [x for x in finv_e if x in Ev2]
            sizes.append(len(L))
            #print v2,e,L
        edges_in_common.append([v2, sizes])
    ans = True
    for x in edges_in_common:
        sizes = x[1]
        S = Set(sizes)
        if S.cardinality()>1:
            ans = False
            if verbose and ans==False:
                print "This [, ]] fails the check:", x
        if verbose and ans==True:
            print "This [, ]] passes the check:", x
    return ans
            

For further details (e.g., code to

star_subgraph

, etc), just ask in the comments.

A curious conjecture about self-reciprocal polynomials

Let p be a polynomial
p(z) = a_0 + a_1z+\dots + a_nz^n\ \ \ \ \ \ a_i\in {\bf C},
and let p^* denote the reciprocal polynomial
p^*(z) = a_n + a_{n-1}z+\dots + a_0z^n=z^np(1/z).
We say p is self-reciprocal if p=p^*. For example,
1+2z+3z^2+2z^3+z^4
and
1+2z+3z^2+3z^3+2z^4+z^5
are self-reciprocal. Suppose
p(z) = a_0 + a_1z+\dots + a_dz^d+a_{d+1}z^{d+1}+a_dz^{d}+\dots +a_{1}z^{2d+1}+a_0z^{2d+2},\ \ \ \ \ \ a_i\in {\bf C},
or
p(z) = a_0 + a_1z+\dots + a_dz^d+a_{d+1}z^{d+1}+a_{d+1}z^{d+2}+a_dz^{d+3}+\dots +a_{1}z^{2d+2}+a_0z^{2d+3},\ \ \ \ \ \ a_i\in {\bf C},

The question is this: for which increasing sequences a_0<a_1<\dots a_{d+1} do the polynomial roots p(z)=0 lie on the unit circle |z|=1?

Some examples:

symmetric-increasing-coeff-plot1
This represents, when d=1 and a_0=1 and a_1=1.1 the largest a_{d+1} which has this roots property is as in the plot.

symmetric-increasing-coeff-plot2
This represents, when d=1 and a_0=1 and a_1=1.2 the largest a_{d+1} which has this roots property is as in the plot.

symmetric-increasing-coeff-plot3
This represents, when d=1 and a_0=1 and a_1=1.3 the largest a_{d+1} which has this roots property is as in the plot.

symmetric-increasing-coeff-plot4
This represents, when d=1 and a_0=1 and a_1=1.4 the largest a_{d+1} which has this roots property is as in the plot.

symmetric-increasing-coeff-plot5
This represents, when d=1 and a_0=1 and a_1=1.5 the largest a_{d+1} which has this roots property is as in the plot.

Conjecture 1: Let s:{\bf Z}_{>0}\to {\bf R}_{>0} be a ”slowly increasing” function.

  1. Odd degree case.
    If g(z)= a_0 + a_1z + \dots + a_dz^d, where a_i=s(i), then the roots of p(z)=g(z)+z^{d+1}g^*(z) all lie on the unit circle.
  2. Even degree case.
    The roots of
    p(z)=a_0 + a_1z + \dots + a_{d-1}z^{d-1} + a_{d}z^{d} + a_{d-1}z^{d+1} + \dots + a_{1}z^{2d-1}+a_0z^{2d}
    all lie on the unit circle.

The next conjecture gives an idea as to how fast a “slowly increasing” function can grow.

Conjecture 2:* Consider the even degree case only. The polynomial
p(z)=a_0 + a_1z + \dots + a_{d-1}z^{d-1} + a_{d}z^{d} + a_{d-1}z^{d+1} + \dots + a_{1}z^{2d-1}+a_0z^{2d}  ,
with a_0=1 and all a_i>0, is symmetric increasing if and only if it can be written as a product of quadratics of the form x^2-2\cos(\theta)x+1, where all but one of the factors satisfy 2\pi/4\leq \theta\leq 4\pi/3. One of the factors can be of the form x^2+\alpha x+1, for some \alpha \geq 0.

* It was pointed out to me by Els Withers that this conjecture is false.

More odd examples of p-ary bent functions

In an earlier post I discussed bent functions f:GF(3)^2\to GF(3). In this post, I’d like to give some more examples, based on a recent paper with Caroline Melles, Charles Celerier, David Phillips, and Steven Walsh, based on computations using Sage/pythpn programs I wrote with Charles Celerier.

We start with any function f:GF(p)^n\to GF(p). The Cayley graph of f is defined to be the edge-weighted digraph

\Gamma_f = (GF(p)^n, E_f ),
whose vertex set is V=V(\Gamma_f)=GF(p)^n and the set of edges is defined by

E_f =\{(u,v) \in GF(p)^n\ |\ f(u-v)\not= 0\},
where the edge (u,v)\in E_f has weight f(u-v). However, if f is even then we can (and do) regard \Gamma_f as an edge-weighted (undirected) graph.

We assume, unless stated otherwise, that f is even.

For each u\in V, define

  • N(u)=N_{\Gamma_f}(u) to be the set of all neighbors of u in \Gamma_f,
  • N(u,a)=N_{\Gamma_f}(u,a) to be the set of all neighbors v of u in \Gamma_f for which the edge (u,v)\in E_f has weight a (for each a\in GF(p)^\times = GF(p)-\{0\}),
  • N(u,0)=N_{\Gamma_f}(u,0) to be the set of all non-neighbors v of u in \Gamma_f (i.e., we have (u,v)\notin E_f),
  • the support of f is
    {\rm supp}(f)=\{v\in V\ |\ f(v)\not=0\}

Let \Gamma be a connected edge-weighted graph which is regular as a simple (unweighted) graph. The graph \Gamma is called strongly regular with parameters v, k=(k_a)_{a\in W}, \lambda=(\lambda_a)_{a\in W^3}, \mu=(\mu_a)_{a\in W^2}, denoted SRG_{W}(v,k,\lambda,\mu), if it consists of v vertices such that, for each a=(a_1,a_2)\in W^2

|N(u_1,a_1) \cap N(u_2,a_2)| =  \left\{  \begin{array}{ll}  k_{a}, & u_1=u_2,\\  \lambda_{a_1,a_2,a_3}, & u_1\in N(u_2,a_3),\ u_1\not= u_2,\\  \mu_{a}, &u_1\notin N(u_2),\ u_1\not= u_2,\\  \end{array}  \right.
where k, \lambda, \mu are as above. Here, W= GF(p) is the set of weights, including 0 (recall an “edge” has weight 0 if the vertices are not neighbors).

This example is intended to illustrate the bent function b_8 listed in the table below
\begin{array}{c|ccccccccc}  GF(3)^2 & (0, 0) & (1, 0) & (2, 0) & (0, 1) & (1, 1) & (2, 1) & (0,  2) & (1, 2) & (2, 2) \\ \hline  b_8 & 0  & 2  & 2  & 0  & 0  & 1  & 0  & 1  & 0 \\  \end{array}

Consider the finite field
GF(9) = GF(3)[x]/(x^2+1) = \{0,1,2,x,x+1,x+2,2x,2x+1,2x+2\}.
The set of non-zero quadratic residues is given by
D = \{1,2,x,2x\}.
Let \Gamma be the graph whose vertices are GF(9) and whose edges e=(a,b) are those pairs for which a-b\in D.

The graph looks like the Cayley graph for b_8 in the Figure below

Bent function b_8 on GF(3)^2

Bent function b_8 on GF(3)^2

except

8\to 0, 0\to 2x+2, 1\to 2x+1, 2\to 2x,
3\to x+2, 4\to x+1, 5\to x, 6\to 2,  7\to 1, 8\to 0.
This is a strongly regular graph with parameters (9,4,1,2).

\begin{array}{c|ccccccccc}  v       & 0       & 1       & 2       & 3       & 4       & 5       & 6       & 7 & 8 \\ \hline  N(v,0)  & 3,4,6,8 & 4,5,6,7 & 3,5,7,8 & 0,2,6,7 & 0,1,7,8 & 1,2,6,8 & 0,1,3,5 & 1,2,3,4 & 0,2,4,5 \\     N(v,1) & 5,7 & 3,8 & 4,6 & 1,8 & 2,6 & 0,7 & 2,4 & 0,5 & 1,3 \\  N(v,2) & 1,2 & 0,2 & 0,1 & 4,5 & 3,5 & 3,4 & 7,8 & 6,8 & 6,7 \\   \end{array}

The axioms of an edge-weighted strongly regular graph can be directly verified using this table.

Let S be a finite set and let R_0, R_1, \dots, R_s denote binary relations on S (subsets of S\times S). The dual of a relation R is the set

R^* = \{(x,y)\in S\times S\ |\ (y,x)\in R\}.
Assume R_0=\Delta_S= \{ (x,x)\in S\times S\ |\ x\in S\}. We say (S,R_0,R_1,\dots,R_s) is an s-class association scheme on S if the following properties hold.

  • We have a disjoint union

    S\times S = R_0\cup R_1\cup \dots \cup R_s,
    with R_i\cap R_j=\emptyset for all $i\not= j$.

  • For each i there is a j such that R_i^*=R_j (and if R_i^*=R_i for all i then we say the association scheme is symmetric).
  • For all i,j and all (x,y)\in S\times S, define

    p_{ij}(x,y) = |\{z\in S\ |\ (x,z)\in R_i, (z,y)\in R_j\}|.
    For each k, and for all x,y\in R_k, the integer p_{ij}(x,y) is a constant, denoted p_{ij}^k.

These constants p_{ij}^k are called the intersection numbers of the association scheme.

For this example of b_8, we compute the adjacency matrix associated to the members R_1 and R_2 of the association scheme (G,R_0,R_1,R_2,R_3), where G = GF(3)^2,

R_i = \{(g,h)\in  G\times G\ |\ gh^{-1} \in D_i\},\ \ \ \ \ i=1,2,
and D_i = f^{-1}(i).

Consider the following Sage computation:

sage: attach "/home/wdj/sagefiles/hadamard_transform2b.sage"
sage: FF = GF(3)
sage: V = FF^2
sage: Vlist = V.list()
sage: flist = [0,2,2,0,0,1,0,1,0]
sage: f = lambda x: GF(3)(flist[Vlist.index(x)])
sage: F = matrix(ZZ, [[f(x-y) for x in V] for y in V])
sage: F  ## weighted adjacency matrix
[0 2 2 0 0 1 0 1 0]
[2 0 2 1 0 0 0 0 1]
[2 2 0 0 1 0 1 0 0]
[0 1 0 0 2 2 0 0 1]
[0 0 1 2 0 2 1 0 0]
[1 0 0 2 2 0 0 1 0]
[0 0 1 0 1 0 0 2 2]
[1 0 0 0 0 1 2 0 2]
[0 1 0 1 0 0 2 2 0]
sage: eval1 = lambda x: int((x==1))
sage: eval2 = lambda x: int((x==2))
sage: F1 = matrix(ZZ, [[eval1(f(x-y)) for x in V] for y in V])
sage: F1
[0 0 0 0 0 1 0 1 0]
[0 0 0 1 0 0 0 0 1]
[0 0 0 0 1 0 1 0 0]
[0 1 0 0 0 0 0 0 1]
[0 0 1 0 0 0 1 0 0]
[1 0 0 0 0 0 0 1 0]
[0 0 1 0 1 0 0 0 0]
[1 0 0 0 0 1 0 0 0]
[0 1 0 1 0 0 0 0 0]
sage: F2 = matrix(ZZ, [[eval2(f(x-y)) for x in V] for y in V])
sage: F2
[0 1 1 0 0 0 0 0 0]
[1 0 1 0 0 0 0 0 0]
[1 1 0 0 0 0 0 0 0]
[0 0 0 0 1 1 0 0 0]
[0 0 0 1 0 1 0 0 0]
[0 0 0 1 1 0 0 0 0]
[0 0 0 0 0 0 0 1 1]
[0 0 0 0 0 0 1 0 1]
[0 0 0 0 0 0 1 1 0]
sage: F1*F2-F2*F1 == 0
True
sage: delta = lambda x: int((x[0]==x[1]))
sage: F3 = matrix(ZZ, [[(eval0(f(x-y))+delta([x,y]))%2 for x in V] for y in V])
sage: F3
[0 0 0 1 1 0 1 0 1]
[0 0 0 0 1 1 1 1 0]
[0 0 0 1 0 1 0 1 1]
[1 0 1 0 0 0 1 1 0]
[1 1 0 0 0 0 0 1 1]
[0 1 1 0 0 0 1 0 1]
[1 1 0 1 0 1 0 0 0]
[0 1 1 1 1 0 0 0 0]
[1 0 1 0 1 1 0 0 0]
sage: F3*F2-F2*F3==0
True
sage: F3*F1-F1*F3==0
True
sage: F0 = matrix(ZZ, [[delta([x,y]) for x in V] for y in V])
sage: F0
[1 0 0 0 0 0 0 0 0]
[0 1 0 0 0 0 0 0 0]
[0 0 1 0 0 0 0 0 0]
[0 0 0 1 0 0 0 0 0]
[0 0 0 0 1 0 0 0 0]
[0 0 0 0 0 1 0 0 0]
[0 0 0 0 0 0 1 0 0]
[0 0 0 0 0 0 0 1 0]
[0 0 0 0 0 0 0 0 1]
sage: F1*F3 == 2*F2 + F3
True

The Sage computation above tells us that the adjacency matrix of R_1 is

A_1 =   \left(\begin{array}{rrrrrrrrr}  0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\  0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 \\  0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 \\  0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\  0 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 0 \\  1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\  0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 \\  1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\  0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0  \end{array}\right),
the adjacency matrix of R_2 is

A_2 =   \left(\begin{array}{rrrrrrrrr}  0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\  1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\  1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\  0 & 0 & 0 & 0 & 1 & 1 & 0 & 0 & 0 \\  0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 \\  0 & 0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 \\  0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \\  0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 \\  0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0  \end{array}\right),
and the adjacency matrix of R_3 is

A_3 =   \left(\begin{array}{rrrrrrrrr}  0 & 0 & 0 & 1 & 1 & 0 & 1 & 0 & 1 \\  0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 0 \\  0 & 0 & 0 & 1 & 0 & 1 & 0 & 1 & 1 \\  1 & 0 & 1 & 0 & 0 & 0 & 1 & 1 & 0 \\  1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \\  0 & 1 & 1 & 0 & 0 & 0 & 1 & 0 & 1 \\  1 & 1 & 0 & 1 & 0 & 1 & 0 & 0 & 0 \\  0 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 \\  1 & 0 & 1 & 0 & 1 & 1 & 0 & 0 & 0  \end{array}\right)
Of course, the adjacency matrix of R_0 is the identity matrix. In the above computation, Sage has also verified that they commute and satisfy

A_1A_3 = 2A_2+A_3
in the adjacency ring of the association scheme.

Conjecture:
Let f:GF(p)^n\to GF(p) be a bent function, with p>2. If the level curves of f give rise to a weighted partial difference set then f is weakly regular, and the corresponding (unweighted) partial difference set is of (positive or negative) Latin square type.

For more details, see the paper [CJMPW] with Caroline Melles, Charles Celerier, David Phillips, and Steven Walsh.