static void dsum_p( fmpz_t rop, const fmpz *dinv, const fmpz *mu, long M, const long *C, long lenC, const fmpz_t a, long ui, long vi, long n, long d, long p, long N) { long m, r, idx; fmpz_t apm1, apow, f, g, P, PN; fmpz_init(apm1); fmpz_init(apow); fmpz_init(f); fmpz_init(g); fmpz_init_set_ui(P, p); fmpz_init(PN); fmpz_pow_ui(PN, P, N); fmpz_zero(rop); r = 0; m = (p * (ui + 1) - (vi + 1)) / d; if (m <= M) /* Step {r = 0} */ { idx = _bsearch(C, 0, lenC, m % p); fmpz_powm_ui(apm1, a, p - 1, PN); fmpz_one(apow); fmpz_one(f); fmpz_mod(rop, mu + idx + lenC * (m / p), PN); } for (r = 1, m += p; m <= M; r++, m += p) { idx = _bsearch(C, 0, lenC, m % p); fmpz_mul(apow, apow, apm1); fmpz_mod(apow, apow, PN); fmpz_mul_ui(f, f, ui + 1 + (r - 1) * d); fmpz_mod(f, f, PN); fmpz_mul(g, f, dinv + r); fmpz_mul(g, g, apow); fmpz_mul(g, g, mu + idx + lenC * (m / p)); fmpz_mod(g, g, PN); fmpz_add(rop, rop, g); } fmpz_mod(rop, rop, PN); fmpz_clear(apm1); fmpz_clear(apow); fmpz_clear(f); fmpz_clear(g); fmpz_clear(P); fmpz_clear(PN); }
/** * Searches an index * * @param index The index to search * @param func The function to use when searching. It must be monotonic, * It should return 0 if the value matches, -1 if the value is too small * and 1 if the value is too big, * @param func_data Data passed as the second argument to func * @return A GList where list->data is the data found matching */ GList *_index_search (s4_index_t *index, index_function_t func, void *func_data) { int i,j; GHashTable *found; GList *ret = NULL; if (func == NULL) func = (index_function_t)_val_cmp; i = _bsearch (index, func, func_data); if (i >= index->size || func (index->data[i].val, func_data)) { return NULL; } found = g_hash_table_new (NULL, NULL); for (; i >= 0 && !func (index->data[i].val, func_data); i--); i++; for (; i < index->size && !func (index->data[i].val, func_data); i++) { for (j = 0; j < index->data[i].size; j++) { if (g_hash_table_lookup (found, index->data[i].data[j].data) == NULL) { g_hash_table_insert (found, index->data[i].data[j].data, (void*)1); ret = g_list_prepend (ret, index->data[i].data[j].data); } } } g_hash_table_destroy (found); return ret; }
/** * Removes a value-data pair from the index * * @param index The index to remove from * @param val The value to remove * @param data The data to remove * @return 0 if the value-data pair is not found, 1 otherwise */ int _index_delete (s4_index_t *index, const s4_val_t *val, void *data) { int i,j; i = _bsearch (index, (index_function_t)_val_cmp, (void*)val); if (i >= index->size || _val_cmp (val, index->data[i].val)) { return 0; } j = _data_search (index->data + i, data); if (j >= index->size || data != index->data[i].data) { return 0; } if (--index->data[i].data[j].count <= 0) { memmove (index->data[i].data + j, index->data[i].data + j + 1, (index->data[i].size - j - 1) * sizeof (index_data_t)); index->data[i].size--; } if (index->data[i].size <= 0) { free (index->data[i].data); memmove (index->data + i, index->data + i + i, (index->size - i - 1) * sizeof (index_t)); index->size--; } return 1; }
/** * Inserts a new value-data pair into the index * * @param index The index to insert into * @param val The value to associate the data with * @param new_data The data * @return 1 */ int _index_insert (s4_index_t *index, const s4_val_t *val, void *new_data) { int i,j; i = _bsearch (index, (index_function_t)_val_cmp, (void*)val); if (i >= index->size || _val_cmp (val, index->data[i].val)) { if (index->size >= index->alloc) { index->alloc *= 2; index->data = realloc (index->data, sizeof (index_t) * index->alloc); } memmove (index->data + i + 1, index->data + i, (index->size - i) * sizeof (index_t)); index->data[i].val = val; index->data[i].size = 0; index->data[i].alloc = 1; index->data[i].data = malloc (sizeof (index_data_t) * index->data[i].alloc); index->size++; } j = _data_search (index->data + i, new_data); if (j >= index->data[i].size || new_data != index->data[i].data[j].data) { if (index->data[i].size >= index->data[i].alloc) { index->data[i].alloc *= 2; index->data[i].data = realloc (index->data[i].data, sizeof (index_data_t) * index->data[i].alloc); } memmove (index->data[i].data + j + 1, index->data[i].data + j, (index->data[i].size - j) * sizeof (index_data_t)); index->data[i].data[j].data = new_data; index->data[i].data[j].count = 1; index->data[i].size++; } else { index->data[i].data[j].count++; } return 1; }
static void precompute_nu(fmpz *nu, long *v, long M, const long *C, long lenC, long p, long N) { const long R = M / p; const long N2 = N + (M / (p - 1)); fmpz_t P, PN2, t; padic_inv_t S; double pinv; long i, j; fmpz_init_set_ui(P, p); fmpz_init(PN2); fmpz_pow_ui(PN2, P, N2); fmpz_init(t); /* Step 1. Compute $i! mod p^{N_2}$ where $N_2 \geq N + \max \ord_p (i!)$ Step 2. Invert the unit part of $i!$ modulo $p^N$ */ fmpz_one(nu + 0); for (i = 1; i <= R; i++) { fmpz_mul_ui(nu + i, nu + (i - 1), i); fmpz_mod(nu + i, nu + i, PN2); } /* Let j denote the greatest index s.t. nu[j] has been computed */ for (j = R, i = R + 1; i <= M; i++) { if (_bsearch(C, 0, lenC, i % p) != -1) { fmpz_mod_rfac_uiui(t, j + 1, i - j, PN2); fmpz_mul(nu + i, nu + j, t); fmpz_mod(nu + i, nu + i, PN2); j = i; } } _padic_inv_precompute(S, P, N); pinv = n_precompute_inverse(p); v[0] = 0; for (i = 1; i <= R; i++) { v[i] = - _fmpz_remove(nu + i, P, pinv); _padic_inv_precomp(nu + i, nu + i, S); } for (i = R + 1; i <= M; i++) { if (_bsearch(C, 0, lenC, i % p) != -1) { v[i] = - _fmpz_remove(nu + i, P, pinv); _padic_inv_precomp(nu + i, nu + i, S); } } fmpz_clear(P); fmpz_clear(PN2); fmpz_clear(t); _padic_inv_clear(S); }