/*********************************************************************12(c) Copyright 2006-2010 Salman Baig and Chris Hall34This file is part of ELLFF56ELLFF is free software: you can redistribute it and/or modify7it under the terms of the GNU General Public License as published by8the Free Software Foundation, either version 3 of the License, or9(at your option) any later version.1011ELLFF is distributed in the hope that it will be useful,12but WITHOUT ANY WARRANTY; without even the implied warranty of13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14GNU General Public License for more details.1516You should have received a copy of the GNU General Public License17along with this program. If not, see <http://www.gnu.org/licenses/>.1819*********************************************************************/2021#include <assert.h>22#include <fstream>23#include <iostream>24#include <sstream>25using std::ostringstream;26#include <NTL/lzz_p.h>27#include <NTL/lzz_pE.h>28#include <NTL/lzz_pX.h>29#include <NTL/ZZ.h>3031#include "helper.h"32#include "lzz_pEExtra.h"3334NTL_CLIENT3536static long gcd(long a, long b)37{38if (b < 0) return gcd(a, -b);39if (a < b) return gcd(b, a);40if (b == 0) return a;41return gcd(b, a%b);4243}4445// suppose d divides q-1 and let chi : F_q^* --> Z/d be the46// composition of x|-->x^{(q-1)/d} and a chosen isomorphism47// F_q^*/F_q^{*d} --> Z/d;48// let z1,z2 be independent generic elements49// satisfying z1^d=z2^d=1. we calculate the 'abstract'50// Jacobi sum51//52// J(d,q) = sum_{x!=0,1} z1^{chi(x)}*z2^{chi(1-x)}53//54// we return the result as a (d x d) array of ZZ's55// (i.e. ZZ[d][d]).56//57// - we canonically choose the isomorphism used to construct58// chi59// - a different choice of chi leads to J(d,q) with z1,z260// replaced by z1^e,z2^e, for some e in (Z/d)^*.61// - by choosing dth roots of unity z1,z2, we get an actual62// Jacobi sum6364void jacobi_sum(ZZ ***sum, long d)65{66long q, e;67q = to_long(zz_pE::cardinality());6869assert((q-1) % d == 0);70e = (q-1)/d;7172// find an element x so x^{(q-1)/d} generates mu_d73zz_pE x, y, z;74x = 1;75while (true) {76int r;77r = inc(x);78assert(r == NO_CARRY);7980power(y, x, e);81power(z, y, d);82assert(z == 1);8384int i;85z = y;86for (i = 1; z != 1; i++)87z *= y;88assert(d % i == 0);8990if (i < d)91continue;9293break;94}9596// enumerate elements of mu_d97unsigned long ul_mu[d];9899y = 1;100power(z, x, e);101for (int i = 0; i < d; i++) {102assert((i == 0 && y == 1) || (i != 0 && y != 1));103ul_mu[i] = to_ulong(y);104y *= z;105}106107// calculate log of Artin character y|-->y^{(q-1)/d_}108unsigned long ul_y;109int log[q];110111x = 1;112do {113power(y, x, e);114power(z, y, d);115assert(z == 1);116117ul_y = to_ulong(y);118119int i;120for (i = 0; i < d; i++)121if (ul_mu[i] == ul_y)122break;123assert(i < d);124125log[to_ulong(x)] = i;126} while (inc(x) == NO_CARRY);127128for (int i = 0; i < d; i++)129for (int j = 0; j < d; j++)130sum[i][j][0] = 0;131132// compute Jacobi sum as element in Z[z]/(z^d-1)133unsigned long u1, u2;134long l1, l2;135x = 0;136do {137// if (true) {138// add(y, x, 1);139// mul(z, y, -1);140// } else {141sub(y, x, 1);142mul(z, y, -1);143// }144145if (x == 0 || z == 0)146continue;147148u1 = to_ulong(x);149u2 = to_ulong(z);150151l1 = log[u1];152l2 = log[u2];153sum[l1][l2][0]++;154} while (inc(x) == NO_CARRY);155}156157#ifdef MAIN158int main(int argc, char **argv)159{160long p, m, e1, e2, d, s, i;161ofstream output;162163if (argc != 6) {164cerr << "Usage: " << argv[0] << " p m e1 e2 d\n";165return -1;166}167168p = atol(argv[1]);169m = atol(argv[2]);170e1 = atol(argv[3]);171e2 = atol(argv[4]);172d = atol(argv[5]);173174assert(d % p != 0);175176init_NTL_ff(p, m, 1, 1, 1);177178ZZ sum[d];179180jacobi_sum(sum, e1, e2, d);181182for (int i = 0; i < d; i++) {183if (i)184cout << ", ";185cout << sum[i];186}187cout << endl;188189return 0;190}191192#endif193194195