def dft(self, chi = lambda x: x): """ A discrete Fourier transform "over `\QQ`" using exact `N`-th roots of unity. EXAMPLES:: 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 architecture 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 architecture 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] sage: 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). .. TODO:: Read the parent of the elements of S; if `\QQ` or `\CC` leave as is; if AbelianGroup, use abelian_group_dual; if some other implemented Group (permutation, matrix), call .characters() and test if the index list is the set of conjugacy classes. """ J = self.index_object() ## index set of length N N = len(J) S = self.list() F = self.base_ring() ## elements must be coercible into QQ(zeta_N) if not(J[0] in ZZ): G = J[0].parent() ## if J is not a range it is a group G if J[0] in ZZ and F.base_ring().fraction_field()==QQ: ## assumes J is range(N) zeta = CyclotomicField(N).gen() FT = [sum([S[i]*chi(zeta**(i*j)) for i in J]) for j in J] elif not(J[0] in ZZ) and G.is_abelian() and F == ZZ or (F.is_field() and F.base_ring()==QQ): if is_PermutationGroupElement(J[0]): ## J is a CyclicPermGp n = G.order() a = list(factor(n)) invs = [x[0]**x[1] for x in a] G = AbelianGroup(len(a),invs) ## assumes J is AbelianGroup(...) Gd = G.dual_group() FT = [sum([S[i]*chid(G.list()[i]) for i in range(N)]) for chid in Gd] elif not(J[0] in ZZ) and G.is_finite() and F == ZZ or (F.is_field() and F.base_ring()==QQ): ## assumes J is the list of conj class representatives of a ## PermuationGroup(...) or Matrixgroup(...) chi = G.character_table() FT = [sum([S[i]*chi[i,j] for i in range(N)]) for j in range(N)] else: raise ValueError("list elements must be in QQ(zeta_"+str(N)+")") return IndexedSequence(FT,J)