Skip to content

Commit

Permalink
inplement number field with all square roots
Browse files Browse the repository at this point in the history
define a unitary version of the SGA DFT

By ensuring every representation of G is unitary, the overall DFT can be made unitary by including \sqrt{d_\rho/|G|} in front of each Fourier coefficient. To make the rep'ns unitary, we make use of Weyl's unitary trick. Rather than using Gram-Schmidt orthonormalization, we opt to compute the "sum of squares" matrix P = \sum_{g \in G} \rho(g)\rho(g)*dg and set Q=\sqrt{P} where Q is the principal square root.

use self.group() instead of G

remove a def lines maintaining readability

include form option for "unitary"

remove whitespace

remove whitespace in doctest

remove all whitespace

Revert "remove all whitespace"

This reverts commit b6d289c.

remove all whitespace

one line before nested def

more whitespace

proper usage of order, cardinality, degree

for 1/|G|, should use G.cardinality
for n, one should use n = G.degree()

simplify the output which is in symbolic ring SR

compute a square root in the base ring of Q

note Q is the change-of-basis matrix making the representation unitary. when we extend to positive characteristic, we will need to ensure square roots are computable in that field

simplify conjugate_transpose_pos_char

remove .simplify_full() from doctest

need to be computing square roots in some ring. some problems may be occurring if the working over the symbolic ring

just use sqrt

manually use principal_square_root

need to ensure that the resulting matrix is defined over some field rather than just the SymbolicRing.

use self instead of "SGA"

remove blank line before def

remove whitespace

add blank line before def

just remove comments

self instead of SGA

just return with simplify_full() for now

working over a ring which contains all required square roots will take some time

slight difference in expected output

change polynomial ring notation to remove lint error

work over a number field

when working over \Q or extensions thereof, we need to ensure all required square roots are available. precompute a field extension of self.base_ring() containing all roots, which are the roots on the diagonal in the unitary change-of-basis matrix square root, as well as the unitary factors \sqrt{d_\rho/|G|}.
  • Loading branch information
jacksonwalters committed Jul 31, 2024
1 parent 79c047c commit 392a6b9
Showing 1 changed file with 59 additions and 0 deletions.
59 changes: 59 additions & 0 deletions src/sage/combinat/symmetric_group_algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -2068,8 +2068,67 @@ def dft(self, form=None, mult='l2r'):
return self._dft_seminormal(mult=mult)
if form == "modular":
return self._dft_modular()
if form == "unitary":
return self._dft_unitary()

Check warning on line 2072 in src/sage/combinat/symmetric_group_algebra.py

View check run for this annotation

Codecov / codecov/patch

src/sage/combinat/symmetric_group_algebra.py#L2071-L2072

Added lines #L2071 - L2072 were not covered by tests
raise ValueError("invalid form (= %s)" % form)

def _dft_unitary(self):
"""
Return the unitary form of the discrete Fourier transform for ``self``.
EXAMPLES::
sage: QS3 = SymmetricGroupAlgebra(QQ, 3)
sage: QS3._dft_unitary()
[-1/6*sqrt2*sqrt3 -1/6*sqrt2*sqrt3 -1/6*sqrt2*sqrt3 -1/6*sqrt2*sqrt3 -1/6*sqrt2*sqrt3 -1/6*sqrt2*sqrt3]
[ -1/3*sqrt3 0 1/2 1/6*sqrt3 1/6*sqrt3 -1/2]
[ 0 -1/3*sqrt3 1/6*sqrt3 1/2 -1/2 1/6*sqrt3]
[ 0 -1/3*sqrt3 1/6*sqrt3 -1/2 1/2 1/6*sqrt3]
[ -1/3*sqrt3 0 -1/2 1/6*sqrt3 1/6*sqrt3 1/2]
[-1/6*sqrt2*sqrt3 1/6*sqrt2*sqrt3 1/6*sqrt2*sqrt3 -1/6*sqrt2*sqrt3 -1/6*sqrt2*sqrt3 1/6*sqrt2*sqrt3]
"""
from sage.matrix.special import diagonal_matrix
from sage.misc.functional import sqrt
from sage.misc.flatten import flatten

def all_roots_field():
required_square_roots = []
for partition in Partitions(self.group().degree()):
specht_module = self.specht_module(partition)
rho = specht_module.representation_matrix
group_size = self.group().cardinality()
P = (1/group_size)*sum(rho(g)*rho(g).conjugate().transpose() for g in self.group())
d, L = P.eigenmatrix_left()
required_square_roots += [specht_module.dimension(),self.group().cardinality()] + d.diagonal()
required_square_roots = flatten([[QQ(q).numerator(),QQ(q).denominator()] if q in QQ else q for q in required_square_roots])
K = self.base_ring()
for n in set(required_square_roots):
R = PolynomialRing(K, 'x')
x = R.gen()
if (x**2 - n).is_irreducible():
gen_name = "sqrt"+str(n).replace("/","over")
K = K.extension(sqrt(n).minpoly(),names=gen_name)
return K

def unitary_change_of_basis(partition,K):
rho = self.specht_module(partition).representation_matrix
group_size = self.group().cardinality()
P = (1/group_size)*sum(rho(g)*rho(g).conjugate().transpose() for g in self.group())
d, L = P.eigenmatrix_left()
return L.inverse() * diagonal_matrix([sqrt(K(a)) for a in d.diagonal()]) * L

def hat(f,partition,K):
specht_module = self.specht_module(partition)
rho = specht_module.representation_matrix
Q = unitary_change_of_basis(partition,K)
unitary_factor = specht_module.dimension()/self.group().cardinality()
sqrt_unitary_factor = sqrt(K(unitary_factor))
return sqrt_unitary_factor*sum(f(g)*Q.inverse()*rho(g)*Q for g in self.group())

K = all_roots_field()
delta = lambda s: lambda t: 1 if t == s else 0
return matrix(K,[flatten([hat(delta(g),partition,K).list() for partition in Partitions(self.group().degree())]) for g in self.group()]).transpose()

def _dft_seminormal(self, mult='l2r'):
"""
Return the seminormal form of the discrete Fourier transform for ``self``.
Expand Down

0 comments on commit 392a6b9

Please sign in to comment.