/*
Copyright (C) 2006, 2011, 2016 William Hart
Copyright (C) 2015 Nitin Kumar
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
#ifndef QSIEVE_H
#define QSIEVE_H
#include
#include
#include
#include
#include
#include "flint.h"
#include "fmpz.h"
#include "ulong_extras.h"
#include "fmpz_vec.h"
#include "fmpz_factor.h"
#include "thread_support.h"
#ifdef __cplusplus
extern "C" {
#endif
#define QS_DEBUG 0 /* level of debug information printed, 0 = none */
#define BITS_ADJUST 25 /* add to sieve entries to compensate approximations */
#define BLOCK_SIZE (4*65536) /* size of sieving cache block */
typedef struct prime_t
{
mp_limb_t pinv; /* precomputed inverse */
int p; /* prime */
char size;
} prime_t;
typedef struct fac_t /* struct for factors of relations */
{
slong ind;
slong exp;
} fac_t;
typedef struct la_col_t /* matrix column */
{
slong * data; /* The list of occupied rows in this column */
slong weight; /* Number of nonzero entries in this column */
slong orig; /* Original relation number */
} la_col_t;
typedef struct hash_t /* entry in hash table */
{
mp_limb_t prime; /* value of prime */
mp_limb_t next; /* next prime which have same hash value as 'prime' */
mp_limb_t count; /* number of occurrence of 'prime' */
} hash_t;
typedef struct relation_t /* format for relation */
{
mp_limb_t lp; /* large prime, is 1, if relation is full */
slong num_factors; /* number of factors, excluding small factor */
slong small_primes; /* number of small factors */
slong * small; /* exponent of small factors */
fac_t * factor; /* factor of relation */
fmpz_t Y; /* square root of sieve value for relation */
} relation_t;
typedef struct qs_poly_s
{
fmpz_t B; /* current B coeff of poly */
int * soln1; /* first start position in sieve per prime */
int * soln2; /* second start position in sieve per prime */
int * posn1; /* temp space for sieving */
int * posn2; /* temp space for sieving */
slong * small; /* exponents of small prime factors in relations */
fac_t * factor; /* factors for a relation */
slong num_factors; /* number of factors found in a relation */
} qs_poly_s;
typedef qs_poly_s qs_poly_t[1];
typedef struct qs_s
{
volatile slong index_j;
#if FLINT_USES_PTHREAD
pthread_mutex_t mutex;
#endif
thread_pool_handle * handles;
slong num_handles;
fmpz_t n; /* Number to factor */
flint_bitcnt_t bits; /* Number of bits of n */
ulong ks_primes; /* number of Knuth-Schroeppel primes */
mp_limb_t k; /* Multiplier */
fmpz_t kn; /* kn as a multiprecision integer */
slong num_primes; /* number of factor base primes including k and 2 */
prime_t * factor_base; /* data about factor base primes */
int * sqrts; /* square roots of kn mod factor base primes */
slong small_primes; /* number of primes to not sieve with */
slong second_prime; /* index of first prime bigger than block size */
slong sieve_size; /* size of sieve to use */
unsigned char sieve_bits; /* sieve threshold */
unsigned char sieve_fill; /* for biasing sieve values */
/***************************************************************************
POLYNOMIAL DATA
**************************************************************************/
fmpz_t A; /* current value of coeff A of poly Ax^2 + Bx + C */
fmpz_t B; /* B value of poly */
mp_limb_t * A_ind; /* indices of factor base primes dividing A */
fmpz_t * A_divp; /* A_divp[i] = (A/p_i),
where the p_i are the prime factors of A */
mp_limb_t * B0_terms; /* B0_terms[i] = min(gamma_i, p - gamma_i) where
gamma_i = (sqrt(kn)*(A_divp[i])^(-1)) mod p_i,
where the p_i are the prime factors of A */
fmpz_t * B_terms; /* B_terms[i] = A_divp[i]*B0_terms[i] (multprec) */
mp_limb_t * A_inv; /* A_inv[k] = A^(-1) mod p_k, for FB prime p_k */
mp_limb_t ** A_inv2B; /* A_inv2B[i][k] = 2 * B_terms[i] * A^(-1) mod p_k
for FB prime p_k */
int * soln1; /* soln1[k] = first poly root mod FB prime p_k */
int * soln2; /* soln2[k] = second poly root mod FB prime p_k */
fmpz_t target_A; /* approximate target value for A coeff of poly */
fmpz_t upp_bound; /* upper bound on desired A = 2*target_A */
fmpz_t low_bound; /* lower bound on desired A = target_A/2 */
slong s; /* number of prime factors of A */
slong low; /* minimum offset in factor base,
for possible factors of A */
slong high; /* maximum offset in factor base,
for possible factors of A */
slong span; /* total number of possible factors for A */
/*
parameters for calculating next subset of possible factors of A, giving
a lexicographic ordering of all such tuples
*/
slong h; /* tuple entry we just set, numbered from 1 at end of tuple */
slong m; /* last value we just set a tuple entry to */
slong A_ind_diff; /* diff. between indices of (s-1) and (s-2)-th A-factor */
mp_limb_t * curr_subset; /* current tuple */
mp_limb_t * first_subset; /* first tuple, in case of restart */
mp_limb_t j; /* index of s-th factor of first A, if s > 3 */
#if QS_DEBUG
slong poly_count; /* keep track of the number of polynomials used */
#endif
qs_poly_s * poly; /* poly data per thread */
/***************************************************************************
RELATION DATA
***************************************************************************/
FILE * siqs; /* pointer to file for storing relations */
char * fname; /* name of file used for relations */
slong full_relation; /* number of full relations */
slong num_cycles; /* number of possible full relations from partials */
slong vertices; /* number of different primes in partials */
slong components; /* equal to 1 */
slong edges; /* total number of partials */
slong table_size; /* size of table */
hash_t * table; /* store 'prime' occurring in partial */
mp_limb_t * hash_table; /* to keep track of location of primes in 'table' */
slong extra_rels; /* number of extra relations beyond num_primes */
slong max_factors; /* maximum number of factors a relation can have */
fmpz * Y_arr; /* array of Y's corresponding to relations */
slong * curr_rel; /* current relation in array of relations */
slong * relation; /* relation array */
slong buffer_size; /* size of buffer of relations */
slong num_relations; /* number of relations so far */
ulong small_factor; /* small factor found when merging relations */
/***************************************************************************
LINEAR ALGEBRA DATA
***************************************************************************/
la_col_t * matrix; /* the main matrix over GF(2) in sparse format */
la_col_t ** qsort_arr; /* array of columns ready to be sorted */
slong columns; /* number of columns in matrix so far */
/***************************************************************************
SQUARE ROOT DATA
***************************************************************************/
slong * prime_count; /* counts of the exponents of primes appearing in the square */
} qs_s;
typedef qs_s qs_t[1];
/*
Tuning parameters { bits, ks_primes, fb_primes, small_primes, sieve_size}
for qsieve_factor_threaded where:
* bits is the number of bits of n
* ks_primes is the max number of primes to try in Knuth-Schroeppel function
* fb_primes is the number of factor base primes to use (including k and 2)
* small_primes is the number of small primes to not factor with (including k and 2)
* sieve_size is the size of the sieve to use
* sieve_bits - sieve_fill
*/
#if 0 /* TODO have the tuning values taken from here if multithreaded */
static const mp_limb_t qsieve_tune[][6] =
{
{10, 50, 100, 5, 2 * 2000, 30}, /* */
{20, 50, 120, 6, 2 * 2500, 30}, /* */
{30, 50, 150, 6, 2 * 2000, 31}, /* */
{40, 50, 150, 8, 2 * 3000, 32}, /* 12 digits */
{50, 50, 150, 8, 2 * 3000, 34}, /* 15 digits */
{60, 50, 150, 9, 2 * 3500, 36}, /* 18 digits */
{70, 100, 200, 9, 2 * 4000, 42}, /* 21 digits */
{80, 100, 200, 9, 2 * 6000, 44}, /* 24 digits */
{90, 100, 200, 9, 2 * 6000, 50}, /* */
{100, 100, 300, 9, 2 * 7000, 54}, /* */
{110, 100, 500, 9, 2 * 25000, 62}, /* 31 digits */
{120, 100, 800, 9, 2 * 30000, 64}, /* */
{130, 100, 1000, 9, 2 * 30000, 64}, /* 41 digits */
{140, 100, 1200, 9, 2 * 30000, 66}, /* */
{150, 100, 1500, 10, 2 * 32000, 68}, /* 45 digit */
{160, 150, 1800, 11, 2 * 32000, 70}, /* */
{170, 150, 2000, 12, 2 * 32000, 72}, /* 50 digits */
{180, 150, 2500, 12, 2 * 32000, 73}, /* */
{190, 150, 2800, 12, 2 * 32000, 76}, /* */
{200, 200, 4000, 12, 2 * 32000, 80}, /* 60 digits */
{210, 100, 3600, 12, 2 * 32000, 83}, /* */
{220, 300, 6000, 15, 2 * 65536, 87}, /* */
{230, 350, 8500, 17, 3 * 65536, 90}, /* 70 digits */
{240, 400, 10000, 19, 4 * 65536, 93}, /* */
{250, 500, 15000, 19, 4 * 65536, 97}, /* 75 digits */
{260, 600, 25000, 25, 4 * 65536, 100}, /* 80 digits */
{270, 800, 35000, 27, 5 * 65536, 104} /* */
};
#else /* currently tuned for four threads */
static const mp_limb_t qsieve_tune[][6] =
{
{10, 50, 90, 5, 2 * 1500, 18}, /* */
{20, 50, 90, 6, 2 * 1600, 18}, /* */
{30, 50, 100, 6, 2 * 1800, 19}, /* */
{40, 50, 100, 8, 2 * 2000, 20}, /* 13 digits */
{50, 50, 100, 8, 2 * 2500, 22}, /* 16 digits */
{60, 50, 100, 9, 2 * 3000, 24}, /* 19 digits */
{70, 100, 250, 9, 2 * 6000, 25}, /* 22 digits */
{80, 100, 250, 9, 2 * 8000, 26}, /* 25 digits */
{90, 100, 250, 9, 2 * 9000, 30}, /* 28 digits */
{100, 100, 250, 9, 2 * 10000, 34}, /* 31 digits */
{110, 100, 250, 9, 2 * 30000, 38}, /* 34 digits */
{120, 100, 700, 9, 2 * 40000, 49}, /* 37 digits */
{130, 100, 800, 9, 2 * 50000, 59}, /* 40 digits */
{140, 100, 1200, 9, 2 * 65536, 66}, /* 43 digits */
{150, 100, 1500, 10, 2 * 65536, 70}, /* 46 digit */
{160, 150, 2000, 11, 4 * 65536, 73}, /* 49 digit */
{170, 150, 2000, 12, 4 * 65536, 75}, /* 52 digits */
{180, 150, 3000, 12, 4 * 65536, 76}, /* 55 digits */
{190, 150, 3000, 13, 4 * 65536, 78}, /* 58 digit */
{200, 200, 4500, 14, 4 * 65536, 81}, /* 61 digits */
{210, 100, 8000, 14, 12 * 65536, 84}, /* 64 digits */
{220, 300, 10000, 15, 12 * 65536, 88}, /* 67 digits */
{230, 400, 20000, 17, 20 * 65536, 90}, /* 70 digits */
{240, 450, 20000, 19, 20 * 65536, 93}, /* 73 digis */
{250, 500, 22000, 22, 24 * 65536, 97}, /* 76 digits */
{260, 600, 25000, 25, 24 * 65536, 100}, /* 79 digits */
{270, 800, 35000, 27, 28 * 65536, 102}, /* 82 digits */
{280, 900, 40000, 29, 28 * 65536, 104}, /* 85 digits */
{290, 1000, 60000, 29, 32 * 65536, 106}, /* 88 digits */
{300, 1100, 140000, 30, 32 * 65536, 108} /* 91 digits */
};
#endif
/* number of entries in the tuning table */
#define QS_TUNE_SIZE (sizeof(qsieve_tune)/(6*sizeof(mp_limb_t)))
FLINT_DLL void qsieve_init(qs_t qs_inf, const fmpz_t n);
FLINT_DLL mp_limb_t qsieve_knuth_schroeppel(qs_t qs_inf);
FLINT_DLL void qsieve_clear(qs_t qs_inf);
FLINT_DLL void qsieve_factor(fmpz_factor_t factors, const fmpz_t n);
FLINT_DLL prime_t * compute_factor_base(mp_limb_t * small_factor, qs_t qs_inf,
slong num_primes);
FLINT_DLL mp_limb_t qsieve_primes_init(qs_t qs_inf);
FLINT_DLL mp_limb_t qsieve_primes_increment(qs_t qs_inf, mp_limb_t delta);
FLINT_DLL mp_limb_t qsieve_poly_init(qs_t qs_inf);
FLINT_DLL int qsieve_init_A(qs_t qs_inf);
FLINT_DLL void qsieve_reinit_A(qs_t qs_inf);
FLINT_DLL int qsieve_next_A(qs_t qs_inf);
FLINT_DLL void qsieve_init_poly_first(qs_t qs_inf);
FLINT_DLL void qsieve_init_poly_next(qs_t qs_inf, slong i);
FLINT_DLL void qsieve_compute_C(fmpz_t C, qs_t qs_inf, qs_poly_t poly);
FLINT_DLL void qsieve_poly_copy(qs_poly_t poly, qs_t qs_inf);
FLINT_DLL void qsieve_poly_clear(qs_t qs_inf);
FLINT_DLL void qsieve_do_sieving(qs_t qs_inf, unsigned char * sieve, qs_poly_t poly);
FLINT_DLL void qsieve_do_sieving2(qs_t qs_inf, unsigned char * sieve, qs_poly_t poly);
FLINT_DLL slong qsieve_evaluate_candidate(qs_t qs_inf, ulong i, unsigned char * sieve, qs_poly_t poly);
FLINT_DLL slong qsieve_evaluate_sieve(qs_t qs_inf, unsigned char * sieve, qs_poly_t poly);
FLINT_DLL slong qsieve_collect_relations(qs_t qs_inf, unsigned char * sieve);
FLINT_DLL void qsieve_linalg_init(qs_t qs_inf);
FLINT_DLL void qsieve_linalg_realloc(qs_t qs_inf);
FLINT_DLL void qsieve_linalg_clear(qs_t qs_inf);
FLINT_DLL int qsieve_relations_cmp(const void * a, const void * b);
FLINT_DLL slong qsieve_merge_relations(qs_t qs_inf);
FLINT_DLL void qsieve_write_to_file(qs_t qs_inf, mp_limb_t prime,
fmpz_t Y, qs_poly_t poly);
FLINT_DLL hash_t * qsieve_get_table_entry(qs_t qs_inf, mp_limb_t prime);
FLINT_DLL void qsieve_add_to_hashtable(qs_t qs_inf, mp_limb_t prime);
FLINT_DLL relation_t qsieve_parse_relation(qs_t qs_inf, char * str);
FLINT_DLL relation_t qsieve_merge_relation(qs_t qs_inf, relation_t a, relation_t b);
FLINT_DLL int qsieve_compare_relation(const void * a, const void * b);
FLINT_DLL int qsieve_remove_duplicates(relation_t * rel_list, slong num_relations);
FLINT_DLL void qsieve_insert_relation(qs_t qs_inf, relation_t * rel_list,
slong num_relations);
FLINT_DLL int qsieve_process_relation(qs_t qs_inf);
static __inline__ void insert_col_entry(la_col_t * col, slong entry)
{
if (((col->weight >> 4) << 4) == col->weight) /* need more space */
{
if (col->weight != 0) col->data =
(slong *) flint_realloc(col->data, (col->weight + 16)*sizeof(slong));
else col->data = (slong *) flint_malloc(16*sizeof(slong));
}
col->data[col->weight] = entry;
col->weight++;
}
static __inline__ void swap_cols(la_col_t * col2, la_col_t * col1)
{
la_col_t temp;
temp.weight = col1->weight;
temp.data = col1->data;
temp.orig = col1->orig;
col1->weight = col2->weight;
col1->data = col2->data;
col1->orig = col2->orig;
col2->weight = temp.weight;
col2->data = temp.data;
col2->orig = temp.orig;
}
static __inline__ void clear_col(la_col_t * col)
{
col->weight = 0;
}
static __inline__ void free_col(la_col_t * col)
{
if (col->weight) flint_free(col->data);
}
FLINT_DLL uint64_t get_null_entry(uint64_t * nullrows, slong i, slong l);
FLINT_DLL void reduce_matrix(qs_t qs_inf, slong *nrows, slong *ncols, la_col_t *cols);
FLINT_DLL uint64_t * block_lanczos(flint_rand_t state, slong nrows,
slong dense_rows, slong ncols, la_col_t *B);
FLINT_DLL void qsieve_square_root(fmpz_t X, fmpz_t Y, qs_t qs_inf,
uint64_t * nullrows, slong ncols, slong l, fmpz_t N);
#ifdef __cplusplus
}
#endif
#endif