-
-
Save fredrik-johansson/4c58e476f9ffa4c5a7ce218c52df0002 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Generic Flint-style rings using void pointers + context objects. | |
todo: write -> print | |
Principles/goals/benefits: | |
* Small code size, fast compilation. | |
* Possible to pack data efficiently (down to 1 byte / element). | |
* Plain C, similar interface to existing Flint code. | |
* Data layouts backwards compatible with most existing Flint types. | |
* Support all unusual cases in Flint/Arb/Calcium uniformly (error handling, | |
inexact rings, noncomputable rings, context objects), with a unified | |
interface. | |
* Support fast stack based allocation of local variables and vectors. | |
* Fully in-place operations. | |
* Allow fast (a few cycles) runtime construction of context objects. | |
* Possibility to use generic default methods or provide optimized versions | |
(e.g. for vector operations). | |
Cons: | |
* Several cycles overhead for each dynamic function lookup and function call. | |
On top of this, most compiler optimizations become impossible. | |
However, overriding the default vector functions should largely make up | |
for overheads. | |
* Less compiler protection against type errors. | |
* Some function call signatures need to change in ways that make | |
the interface less convenient (for uniformity). | |
*/ | |
#include <string.h> | |
#include "flint/flint.h" | |
#include "flint/nmod_vec.h" | |
#include "flint/ulong_extras.h" | |
#include "flint/profiler.h" | |
/* Copied from Calcium: stream interface allows simple file or string IO. */ | |
typedef struct | |
{ | |
FILE * fp; | |
char * s; | |
slong len; | |
slong alloc; | |
} | |
gr_stream_struct; | |
typedef gr_stream_struct gr_stream_t[1]; | |
void gr_stream_init_file(gr_stream_t out, FILE * fp) | |
{ | |
out->fp = fp; | |
out->s = NULL; | |
} | |
void gr_stream_init_str(gr_stream_t out) | |
{ | |
out->fp = NULL; | |
out->s = flint_malloc(16); | |
out->s[0] = '\0'; | |
out->len = 0; | |
out->alloc = 16; | |
} | |
void gr_stream_write(gr_stream_t out, const char * s) | |
{ | |
if (out->fp != NULL) | |
{ | |
fprintf(out->fp, "%s", s); | |
} | |
else | |
{ | |
slong len, alloc; | |
len = strlen(s); | |
alloc = out->len + len + 1; | |
if (alloc > out->alloc) | |
{ | |
alloc = FLINT_MAX(alloc, out->alloc * 2); | |
out->s = realloc(out->s, alloc); | |
out->alloc = alloc; | |
} | |
memcpy(out->s + out->len, s, len + 1); | |
out->len += len; | |
} | |
} | |
void | |
gr_stream_write_si(gr_stream_t out, slong x) | |
{ | |
if (out->fp != NULL) | |
{ | |
flint_fprintf(out->fp, "%wd", x); | |
} | |
else | |
{ | |
char tmp[22]; | |
if (sizeof(slong) == sizeof(long)) | |
sprintf(tmp, "%ld", x); | |
else | |
flint_sprintf(tmp, "%wd", x); | |
gr_stream_write(out, tmp); | |
} | |
} | |
void | |
gr_stream_write_free(gr_stream_t out, char * s) | |
{ | |
gr_stream_write(out, s); | |
flint_free(s); | |
} | |
/* | |
All functions implement error handling and return a status code. | |
GR_SUCCESS - The operation finished as expected. | |
GR_DOMAIN - Invalid input for this operation (e.g. division by zero, | |
wrong matrix shape). | |
GR_UNABLE - The operation could not be performed for implementation reasons | |
(e.g. overflow, missing algorithm). The input may or may not be | |
valid. | |
GR_WRONG - Test failure (used only in test code). | |
For uniformity, all functions return a status code. | |
Flags can be OR'ed to avoid complex control flow. | |
*/ | |
#define GR_SUCCESS 0 | |
#define GR_DOMAIN 1 | |
#define GR_UNABLE 2 | |
#define GR_WRONG 4 | |
typedef void * gr_ptr; | |
typedef const void * gr_srcptr; | |
typedef void * gr_ctx_ptr; | |
typedef int ((*gr_func_out)(gr_ptr, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_si)(gr_ptr, slong, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_out)(gr_ptr, gr_ptr, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_out_si)(gr_ptr, gr_ptr, slong, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_in)(gr_ptr, gr_srcptr, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_in_in)(gr_ptr, gr_srcptr, gr_srcptr, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_in_si)(gr_ptr, gr_srcptr, slong, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_si_in)(gr_ptr, gr_srcptr, slong, gr_srcptr, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_in_in_si)(gr_ptr, gr_srcptr, gr_srcptr, slong, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_in_si_in)(gr_ptr, gr_srcptr, slong, gr_srcptr, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_in_si_si)(gr_ptr, gr_srcptr, slong, slong, gr_ctx_ptr)); | |
typedef int ((*gr_func_outbool_in)(int *, gr_srcptr, gr_ctx_ptr)); | |
typedef int ((*gr_func_outbool_in_si)(int *, gr_srcptr, slong, gr_ctx_ptr)); | |
typedef int ((*gr_func_outbool_in_in)(int *, gr_srcptr, gr_srcptr, gr_ctx_ptr)); | |
typedef int ((*gr_func_outbool_in_in_si)(int *, gr_srcptr, gr_srcptr, slong, gr_ctx_ptr)); | |
typedef int ((*gr_func_out_in_bool_in_in_si)(gr_ptr, gr_srcptr, int, gr_srcptr, gr_srcptr, slong, gr_ctx_ptr)); | |
typedef int ((*gr_func_stream_in)(gr_stream_t, gr_srcptr, gr_ctx_ptr)); | |
typedef int ((*gr_func_randtest)(gr_ptr, flint_rand_t state, const void * options, gr_ctx_ptr)); | |
int gr_not_implemented(void) { return GR_UNABLE; } | |
/* Standard methods which need to be implemented for any ring. */ | |
/* What else is needed: fmpz, si methods? Random generation? Hashing? */ | |
typedef struct | |
{ | |
gr_func_out init; | |
gr_func_out clear; | |
gr_func_out_out swap; | |
gr_func_randtest randtest; | |
gr_func_stream_in write; | |
gr_func_out zero; | |
gr_func_out one; | |
gr_func_outbool_in is_zero; | |
gr_func_outbool_in is_one; | |
gr_func_outbool_in_in equal; | |
gr_func_out_in set; | |
gr_func_out_si set_si; | |
gr_func_out_in neg; | |
gr_func_out_in_in add; | |
gr_func_out_in_si add_si; | |
gr_func_out_in_in sub; | |
gr_func_out_in_in mul; | |
gr_func_out_in_si mul_si; | |
gr_func_out_in_in div; | |
gr_func_out_in_in divexact; | |
gr_func_out_in_si divexact_si; | |
gr_func_outbool_in is_invertible; | |
gr_func_out_in inv; | |
} | |
gr_methods; | |
/* Vector methods. The idea is that these will have generic defaults | |
which can be overridden for performance. */ | |
typedef struct | |
{ | |
gr_func_out_si init; | |
gr_func_out_si clear; | |
gr_func_out_out_si swap; | |
gr_func_out_si zero; | |
gr_func_out_in_si set; | |
gr_func_out_in_si neg; | |
gr_func_out_in_in_si add; | |
gr_func_out_in_in_si sub; | |
gr_func_out_in_si_in scalar_addmul; | |
gr_func_out_in_si_in scalar_submul; | |
gr_func_out_in_si_si scalar_addmul_si; | |
gr_func_out_in_si_si scalar_submul_si; | |
gr_func_outbool_in_in_si equal; | |
gr_func_outbool_in_si is_zero; | |
gr_func_out_in_bool_in_in_si dot; | |
gr_func_out_in_bool_in_in_si dot_rev; | |
} | |
gr_vec_methods; | |
/* | |
We could add more method tables, which may be initialized to generic | |
implementations by default: | |
compound_methods | |
cmp_methods | |
... | |
*/ | |
/* Flags. These are not cumulative. (?) */ | |
#define GR_COMMUTATIVE_RING UWORD(1) | |
#define GR_INTEGRAL_DOMAIN UWORD(2) | |
#define GR_FIELD UWORD(4) | |
typedef struct | |
{ | |
ulong flags; | |
ssize_t sizeof_elem; | |
void * elem_ctx; | |
gr_methods * methods; | |
gr_vec_methods * vec_methods; | |
char * debug_string; | |
} | |
gr_ctx_struct; | |
typedef gr_ctx_struct gr_ctx_t[1]; | |
/* Macros for allocating temporary variables on the stack. */ | |
#define GR_TMP_START TMP_INIT; TMP_START; | |
#define GR_TMP_ALLOC TMP_ALLOC | |
#define GR_TMP_END TMP_END | |
/* todo: use vector init functions when provided */ | |
#define GR_TMP_INIT_VEC(vec, len, ctx) \ | |
do { \ | |
gr_func_out _gr_init_func = (ctx)->methods->init; \ | |
ssize_t _gr_elem_size = (ctx)->sizeof_elem; \ | |
(vec) = (gr_ptr) GR_TMP_ALLOC((len) * _gr_elem_size); \ | |
_gr_vec_init((vec), (len), (ctx)); \ | |
} while (0) | |
#define GR_TMP_CLEAR_VEC(vec, len, ctx) \ | |
do { \ | |
gr_func_out _gr_init_func = (ctx)->methods->init; \ | |
ssize_t _gr_elem_size = (ctx)->sizeof_elem; \ | |
_gr_vec_clear((vec), (len), (ctx)); \ | |
} while (0) | |
#define GR_TMP_INIT1(x1, ctx) \ | |
do { \ | |
gr_func_out _gr_init_func = (ctx)->methods->init; \ | |
ssize_t _gr_elem_size = (ctx)->sizeof_elem; \ | |
x1 = (gr_ptr) GR_TMP_ALLOC(1 * _gr_elem_size); \ | |
_gr_init_func(x1, (ctx)->elem_ctx); \ | |
} while (0) | |
#define GR_TMP_INIT2(x1, x2, ctx) \ | |
do { \ | |
gr_func_out _gr_init_func = (ctx)->methods->init; \ | |
ssize_t _gr_elem_size = (ctx)->sizeof_elem; \ | |
x1 = (gr_ptr) GR_TMP_ALLOC(2 * _gr_elem_size); \ | |
x2 = (gr_ptr) ((char *) x1 + _gr_elem_size); \ | |
_gr_init_func(x1, (ctx)->elem_ctx); \ | |
_gr_init_func(x2, (ctx)->elem_ctx); \ | |
} while (0) | |
#define GR_TMP_INIT3(x1, x2, x3, ctx) \ | |
do { \ | |
gr_func_out _gr_init_func = (ctx)->methods->init; \ | |
ssize_t _gr_elem_size = (ctx)->sizeof_elem; \ | |
x1 = (gr_ptr) GR_TMP_ALLOC(3 * _gr_elem_size); \ | |
x2 = (gr_ptr) ((char *) x1 + _gr_elem_size); \ | |
x3 = (gr_ptr) ((char *) x2 + _gr_elem_size); \ | |
_gr_init_func(x1, (ctx)->elem_ctx); \ | |
_gr_init_func(x2, (ctx)->elem_ctx); \ | |
_gr_init_func(x3, (ctx)->elem_ctx); \ | |
} while (0) | |
#define GR_TMP_INIT4(x1, x2, x3, x4, ctx) \ | |
do { \ | |
gr_func_out _gr_init_func = (ctx)->methods->init; \ | |
ssize_t _gr_elem_size = (ctx)->sizeof_elem; \ | |
x1 = (gr_ptr) GR_TMP_ALLOC(4 * _gr_elem_size); \ | |
x2 = (gr_ptr) ((char *) x1 + _gr_elem_size); \ | |
x3 = (gr_ptr) ((char *) x2 + _gr_elem_size); \ | |
x4 = (gr_ptr) ((char *) x3 + _gr_elem_size); \ | |
_gr_init_func(x1, (ctx)->elem_ctx); \ | |
_gr_init_func(x2, (ctx)->elem_ctx); \ | |
_gr_init_func(x3, (ctx)->elem_ctx); \ | |
_gr_init_func(x4, (ctx)->elem_ctx); \ | |
} while (0) | |
#define GR_TMP_INIT5(x1, x2, x3, x4, x5, ctx) \ | |
do { \ | |
gr_func_out _gr_init_func = (ctx)->methods->init; \ | |
ssize_t _gr_elem_size = (ctx)->sizeof_elem; \ | |
x1 = (gr_ptr) GR_TMP_ALLOC(5 * _gr_elem_size); \ | |
x2 = (gr_ptr) ((char *) x1 + _gr_elem_size); \ | |
x3 = (gr_ptr) ((char *) x2 + _gr_elem_size); \ | |
x4 = (gr_ptr) ((char *) x3 + _gr_elem_size); \ | |
x5 = (gr_ptr) ((char *) x4 + _gr_elem_size); \ | |
_gr_init_func(x1, (ctx)->elem_ctx); \ | |
_gr_init_func(x2, (ctx)->elem_ctx); \ | |
_gr_init_func(x3, (ctx)->elem_ctx); \ | |
_gr_init_func(x4, (ctx)->elem_ctx); \ | |
_gr_init_func(x5, (ctx)->elem_ctx); \ | |
} while (0) | |
#define GR_TMP_CLEAR1(x1, ctx) \ | |
do { \ | |
gr_func_out _gr_clear_func = (ctx)->methods->clear; \ | |
_gr_clear_func(x1, (ctx)->elem_ctx); \ | |
} while (0) | |
#define GR_TMP_CLEAR2(x1, x2, ctx) \ | |
do { \ | |
gr_func_out _gr_clear_func = (ctx)->methods->clear; \ | |
_gr_clear_func(x1, (ctx)->elem_ctx); \ | |
_gr_clear_func(x2, (ctx)->elem_ctx); \ | |
} while (0) | |
#define GR_TMP_CLEAR3(x1, x2, x3, ctx) \ | |
do { \ | |
gr_func_out _gr_clear_func = (ctx)->methods->clear; \ | |
_gr_clear_func(x1, (ctx)->elem_ctx); \ | |
_gr_clear_func(x2, (ctx)->elem_ctx); \ | |
_gr_clear_func(x3, (ctx)->elem_ctx); \ | |
} while (0) | |
#define GR_TMP_CLEAR4(x1, x2, x3, x4, ctx) \ | |
do { \ | |
gr_func_out _gr_clear_func = (ctx)->methods->clear; \ | |
_gr_clear_func(x1, (ctx)->elem_ctx); \ | |
_gr_clear_func(x2, (ctx)->elem_ctx); \ | |
_gr_clear_func(x3, (ctx)->elem_ctx); \ | |
_gr_clear_func(x4, (ctx)->elem_ctx); \ | |
} while (0) | |
#define GR_TMP_CLEAR5(x1, x2, x3, x4, x5, ctx) \ | |
do { \ | |
gr_func_out _gr_clear_func = (ctx)->methods->clear; \ | |
_gr_clear_func(x1, (ctx)->elem_ctx); \ | |
_gr_clear_func(x2, (ctx)->elem_ctx); \ | |
_gr_clear_func(x3, (ctx)->elem_ctx); \ | |
_gr_clear_func(x4, (ctx)->elem_ctx); \ | |
_gr_clear_func(x5, (ctx)->elem_ctx); \ | |
} while (0) | |
/* Inline wrappers for default methods. */ | |
int | |
gr_init(gr_ptr res, gr_ctx_t ctx) | |
{ | |
return ctx->methods->init(res, ctx->elem_ctx); | |
} | |
int | |
gr_clear(gr_ptr res, gr_ctx_t ctx) | |
{ | |
return ctx->methods->clear(res, ctx->elem_ctx); | |
} | |
int | |
gr_swap(gr_ptr x, gr_ptr y, gr_ctx_t ctx) | |
{ | |
return ctx->methods->swap(x, y, ctx->elem_ctx); | |
} | |
int | |
gr_randtest(gr_ptr x, flint_rand_t state, const void * options, gr_ctx_t ctx) | |
{ | |
return ctx->methods->randtest(x, state, options, ctx->elem_ctx); | |
} | |
int | |
gr_write(gr_stream_t out, gr_srcptr x, gr_ctx_t ctx) | |
{ | |
return ctx->methods->write(out, x, ctx->elem_ctx); | |
} | |
int | |
gr_zero(gr_ptr res, gr_ctx_t ctx) | |
{ | |
return ctx->methods->zero(res, ctx->elem_ctx); | |
} | |
int | |
gr_one(gr_ptr res, gr_ctx_t ctx) | |
{ | |
return ctx->methods->one(res, ctx->elem_ctx); | |
} | |
int | |
gr_set_si(gr_ptr res, slong x, gr_ctx_t ctx) | |
{ | |
return ctx->methods->set_si(res, x, ctx->elem_ctx); | |
} | |
int | |
gr_is_zero(int * res, gr_srcptr x, gr_ctx_t ctx) | |
{ | |
return ctx->methods->is_zero(res, x, ctx->elem_ctx); | |
} | |
int | |
gr_is_one(int * res, gr_srcptr x, gr_ctx_t ctx) | |
{ | |
return ctx->methods->is_one(res, x, ctx->elem_ctx); | |
} | |
int | |
gr_equal(int * res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) | |
{ | |
return ctx->methods->equal(res, x, y, ctx->elem_ctx); | |
} | |
int | |
gr_set(gr_ptr res, gr_srcptr x, gr_ctx_t ctx) | |
{ | |
return ctx->methods->set(res, x, ctx->elem_ctx); | |
} | |
int | |
gr_neg(gr_ptr res, gr_srcptr x, gr_ctx_t ctx) | |
{ | |
return ctx->methods->neg(res, x, ctx->elem_ctx); | |
} | |
int | |
gr_add(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) | |
{ | |
return ctx->methods->add(res, x, y, ctx->elem_ctx); | |
} | |
int | |
gr_add_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx) | |
{ | |
return ctx->methods->add_si(res, x, y, ctx->elem_ctx); | |
} | |
int | |
gr_sub(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) | |
{ | |
return ctx->methods->sub(res, x, y, ctx->elem_ctx); | |
} | |
int | |
gr_mul(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) | |
{ | |
return ctx->methods->mul(res, x, y, ctx->elem_ctx); | |
} | |
int | |
gr_mul_si(gr_ptr res, gr_srcptr x, slong y, gr_ctx_t ctx) | |
{ | |
return ctx->methods->mul_si(res, x, y, ctx->elem_ctx); | |
} | |
int | |
gr_div(gr_ptr res, gr_srcptr x, gr_srcptr y, gr_ctx_t ctx) | |
{ | |
return ctx->methods->div(res, x, y, ctx->elem_ctx); | |
} | |
int | |
gr_inv(gr_ptr res, gr_srcptr x, gr_ctx_t ctx) | |
{ | |
return ctx->methods->inv(res, x, ctx->elem_ctx); | |
} | |
int | |
gr_is_invertible(int * res, gr_srcptr x, gr_ctx_t ctx) | |
{ | |
return ctx->methods->is_invertible(res, x, ctx->elem_ctx); | |
} | |
/* Generic vector functions */ | |
#define GR_ENTRY(vec, i, size) ((void *) (((char *) (vec)) + ((i) * (size)))) | |
int | |
gr_generic_vec_init(gr_ptr vec, slong len, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
for (i = 0; i < len; i++) | |
status |= gr_init(GR_ENTRY(vec, i, sz), ctx); | |
return status; | |
} | |
int | |
gr_generic_vec_clear(gr_ptr vec, slong len, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
for (i = 0; i < len; i++) | |
status |= gr_clear(GR_ENTRY(vec, i, sz), ctx); | |
return status; | |
} | |
int | |
gr_generic_vec_swap(gr_ptr vec1, gr_ptr vec2, slong len, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
for (i = 0; i < len; i++) | |
status |= gr_swap(GR_ENTRY(vec1, i, sz), GR_ENTRY(vec2, i, sz), ctx); | |
return status; | |
} | |
int | |
gr_generic_vec_zero(gr_ptr vec, slong len, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
for (i = 0; i < len; i++) | |
status |= gr_zero(GR_ENTRY(vec, i, sz), ctx); | |
return status; | |
} | |
int | |
gr_generic_vec_set(gr_ptr res, gr_srcptr src, slong len, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
for (i = 0; i < len; i++) | |
status |= gr_set(GR_ENTRY(res, i, sz), GR_ENTRY(src, i, sz), ctx); | |
return status; | |
} | |
int | |
gr_generic_vec_neg(gr_ptr res, gr_srcptr src, slong len, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
for (i = 0; i < len; i++) | |
status |= gr_neg(GR_ENTRY(res, i, sz), GR_ENTRY(src, i, sz), ctx); | |
return status; | |
} | |
int | |
gr_generic_vec_add(gr_ptr res, gr_srcptr src1, gr_srcptr src2, slong len, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
for (i = 0; i < len; i++) | |
status |= gr_add(GR_ENTRY(res, i, sz), GR_ENTRY(src1, i, sz), GR_ENTRY(src2, i, sz), ctx); | |
return status; | |
} | |
int | |
gr_generic_vec_sub(gr_ptr res, gr_srcptr src1, gr_srcptr src2, slong len, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
for (i = 0; i < len; i++) | |
status |= gr_sub(GR_ENTRY(res, i, sz), GR_ENTRY(src1, i, sz), GR_ENTRY(src2, i, sz), ctx); | |
return status; | |
} | |
int | |
gr_generic_vec_scalar_addmul(gr_ptr vec1, gr_srcptr vec2, slong len, gr_srcptr c, gr_ctx_t ctx) | |
{ | |
GR_TMP_START; | |
int status; | |
slong i, sz; | |
gr_ptr t; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
GR_TMP_INIT1(t, ctx); | |
for (i = 0; i < len; i++) | |
{ | |
status |= gr_mul(t, GR_ENTRY(vec2, i, sz), c, ctx); | |
status |= gr_add(GR_ENTRY(vec1, i, sz), GR_ENTRY(vec1, i, sz), t, ctx); | |
} | |
GR_TMP_CLEAR1(t, ctx); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_generic_vec_scalar_submul(gr_ptr vec1, gr_srcptr vec2, slong len, gr_srcptr c, gr_ctx_t ctx) | |
{ | |
GR_TMP_START; | |
int status; | |
slong i, sz; | |
gr_ptr t; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
GR_TMP_INIT1(t, ctx); | |
for (i = 0; i < len; i++) | |
{ | |
status |= gr_mul(t, GR_ENTRY(vec2, i, sz), c, ctx); | |
status |= gr_sub(GR_ENTRY(vec1, i, sz), GR_ENTRY(vec1, i, sz), t, ctx); | |
} | |
GR_TMP_CLEAR1(t, ctx); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_generic_vec_scalar_addmul_si(gr_ptr vec1, gr_srcptr vec2, slong len, slong c, gr_ctx_t ctx) | |
{ | |
GR_TMP_START; | |
int status; | |
slong i, sz; | |
gr_ptr t; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
GR_TMP_INIT1(t, ctx); | |
for (i = 0; i < len; i++) | |
{ | |
status |= gr_mul_si(t, GR_ENTRY(vec2, i, sz), c, ctx); | |
status |= gr_add(GR_ENTRY(vec1, i, sz), GR_ENTRY(vec1, i, sz), t, ctx); | |
} | |
GR_TMP_CLEAR1(t, ctx); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_generic_vec_scalar_submul_si(gr_ptr vec1, gr_srcptr vec2, slong len, slong c, gr_ctx_t ctx) | |
{ | |
GR_TMP_START; | |
int status; | |
slong i, sz; | |
gr_ptr t; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
GR_TMP_INIT1(t, ctx); | |
for (i = 0; i < len; i++) | |
{ | |
status |= gr_mul_si(t, GR_ENTRY(vec2, i, sz), c, ctx); | |
status |= gr_sub(GR_ENTRY(vec1, i, sz), GR_ENTRY(vec1, i, sz), t, ctx); | |
} | |
GR_TMP_CLEAR1(t, ctx); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_generic_vec_equal(int * res, gr_srcptr vec1, gr_srcptr vec2, slong len, gr_ctx_t ctx) | |
{ | |
int status, equal, this_equal; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
equal = 1; | |
for (i = 0; i < len; i++) | |
{ | |
status |= gr_equal(&this_equal, GR_ENTRY(vec1, i, sz), GR_ENTRY(vec2, i, sz), ctx); | |
equal = equal && this_equal; | |
} | |
res[0] = equal; | |
return status; | |
} | |
int | |
gr_generic_vec_is_zero(int * res, gr_srcptr vec, slong len, gr_ctx_t ctx) | |
{ | |
int status, equal, this_equal; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
equal = 1; | |
for (i = 0; i < len; i++) | |
{ | |
status |= gr_is_zero(&this_equal, GR_ENTRY(vec, i, sz), ctx); | |
equal = equal && this_equal; | |
} | |
res[0] = equal; | |
return status; | |
} | |
int | |
gr_generic_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, gr_srcptr vec1, gr_srcptr vec2, slong len, gr_ctx_t ctx) | |
{ | |
GR_TMP_START; | |
int status; | |
slong i, sz; | |
gr_ptr t; | |
if (len <= 0) | |
{ | |
if (initial == NULL) | |
return gr_zero(res, ctx); | |
else | |
return gr_set(res, initial, ctx); | |
} | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
GR_TMP_INIT1(t, ctx); | |
if (initial == NULL) | |
{ | |
status |= gr_mul(res, vec1, vec2, ctx); | |
} | |
else | |
{ | |
if (subtract) | |
status |= gr_neg(res, initial, ctx); | |
else | |
status |= gr_set(res, initial, ctx); | |
status |= gr_mul(t, vec1, vec2, ctx); | |
status |= gr_add(res, res, t, ctx); | |
} | |
for (i = 1; i < len; i++) | |
{ | |
status |= gr_mul(t, GR_ENTRY(vec1, i, sz), GR_ENTRY(vec2, i, sz), ctx); | |
status |= gr_add(res, res, t, ctx); | |
} | |
if (subtract) | |
status |= gr_neg(res, res, ctx); | |
GR_TMP_CLEAR1(t, ctx); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_generic_vec_dot_rev(gr_ptr res, gr_srcptr initial, int subtract, gr_srcptr vec1, gr_srcptr vec2, slong len, gr_ctx_t ctx) | |
{ | |
GR_TMP_START; | |
int status; | |
slong i, sz; | |
gr_ptr t; | |
if (len <= 0) | |
{ | |
if (initial == NULL) | |
return gr_zero(res, ctx); | |
else | |
return gr_set(res, initial, ctx); | |
} | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
GR_TMP_INIT1(t, ctx); | |
if (initial == NULL) | |
{ | |
status |= gr_mul(res, vec1, GR_ENTRY(vec2, len - 1, sz), ctx); | |
} | |
else | |
{ | |
if (subtract) | |
status |= gr_neg(res, initial, ctx); | |
else | |
status |= gr_set(res, initial, ctx); | |
status |= gr_mul(t, vec1, GR_ENTRY(vec2, len - 1, sz), ctx); | |
status |= gr_add(res, res, t, ctx); | |
} | |
for (i = 1; i < len; i++) | |
{ | |
status |= gr_mul(t, GR_ENTRY(vec1, i, sz), GR_ENTRY(vec2, len - 1 - i, sz), ctx); | |
status |= gr_add(res, res, t, ctx); | |
} | |
if (subtract) | |
status |= gr_neg(res, res, ctx); | |
GR_TMP_CLEAR1(t, ctx); | |
GR_TMP_END; | |
return status; | |
} | |
gr_vec_methods gr_vec_generic_methods = { | |
(gr_func_out_si) gr_generic_vec_init, | |
(gr_func_out_si) gr_generic_vec_clear, | |
(gr_func_out_out_si) gr_generic_vec_swap, | |
(gr_func_out_si) gr_generic_vec_zero, | |
(gr_func_out_in_si) gr_generic_vec_set, | |
(gr_func_out_in_si) gr_generic_vec_neg, | |
(gr_func_out_in_in_si) gr_generic_vec_add, | |
(gr_func_out_in_in_si) gr_generic_vec_sub, | |
(gr_func_out_in_si_in) gr_generic_vec_scalar_addmul, | |
(gr_func_out_in_si_in) gr_generic_vec_scalar_submul, | |
(gr_func_out_in_si_si) gr_generic_vec_scalar_addmul_si, | |
(gr_func_out_in_si_si) gr_generic_vec_scalar_submul_si, | |
(gr_func_outbool_in_in_si) gr_generic_vec_equal, | |
(gr_func_outbool_in_si) gr_generic_vec_is_zero, | |
(gr_func_out_in_bool_in_in_si) gr_generic_vec_dot, | |
(gr_func_out_in_bool_in_in_si) gr_generic_vec_dot_rev, | |
}; | |
int | |
_gr_vec_init(gr_ptr vec, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->init(vec, len, ctx); | |
} | |
int | |
_gr_vec_clear(gr_ptr vec, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->clear(vec, len, ctx); | |
} | |
int | |
_gr_vec_swap(gr_ptr vec1, gr_ptr vec2, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->swap(vec1, vec2, len, ctx); | |
} | |
int | |
_gr_vec_zero(gr_ptr vec, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->zero(vec, len, ctx); | |
} | |
int | |
_gr_vec_set(gr_ptr res, gr_srcptr src, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->set(res, src, len, ctx); | |
} | |
int | |
_gr_vec_neg(gr_ptr res, gr_srcptr src, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->neg(res, src, len, ctx); | |
} | |
int | |
_gr_vec_add(gr_ptr res, gr_srcptr src1, gr_srcptr src2, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->add(res, src1, src2, len, ctx); | |
} | |
int | |
_gr_vec_sub(gr_ptr res, gr_srcptr src1, gr_srcptr src2, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->sub(res, src1, src2, len, ctx); | |
} | |
int | |
_gr_vec_scalar_addmul(gr_ptr vec1, gr_srcptr vec2, slong len, gr_srcptr c, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->scalar_addmul(vec1, vec2, len, c, ctx); | |
} | |
int | |
_gr_vec_scalar_submul(gr_ptr vec1, gr_srcptr vec2, slong len, gr_srcptr c, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->scalar_submul(vec1, vec2, len, c, ctx); | |
} | |
int | |
_gr_vec_scalar_addmul_si(gr_ptr vec1, gr_srcptr vec2, slong len, slong c, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->scalar_addmul_si(vec1, vec2, len, c, ctx); | |
} | |
int | |
_gr_vec_scalar_submul_si(gr_ptr vec1, gr_srcptr vec2, slong len, slong c, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->scalar_submul_si(vec1, vec2, len, c, ctx); | |
} | |
int | |
_gr_vec_equal(int * res, gr_srcptr vec1, gr_srcptr vec2, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->equal(res, vec1, vec2, len, ctx); | |
} | |
int | |
_gr_vec_is_zero(int * res, gr_srcptr vec, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->is_zero(res, vec, len, ctx); | |
} | |
int | |
_gr_vec_dot(gr_ptr res, gr_srcptr initial, int subtract, gr_srcptr vec1, gr_srcptr vec2, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->dot(res, initial, subtract, vec1, vec2, len, ctx); | |
} | |
int | |
_gr_vec_dot_rev(gr_ptr res, gr_srcptr initial, int subtract, gr_srcptr vec1, gr_srcptr vec2, slong len, gr_ctx_t ctx) | |
{ | |
return ctx->vec_methods->dot_rev(res, initial, subtract, vec1, vec2, len, ctx); | |
} | |
int | |
_gr_vec_randtest(gr_ptr res, flint_rand_t state, slong len, void * options, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
for (i = 0; i < len; i++) | |
{ | |
status |= gr_randtest(GR_ENTRY(res, i, sz), state, options, ctx); | |
} | |
return status; | |
} | |
/* Some generic functions. */ | |
/* Assumes exp >= 2; res and tmp not not aliased with x. */ | |
static int | |
_gr_generic_pow_ui_binexp(gr_ptr res, gr_ptr tmp, gr_srcptr x, ulong exp, gr_ctx_t ctx) | |
{ | |
gr_ptr R, S, T; | |
int status; | |
int zeros; | |
ulong bit; | |
status = GR_SUCCESS; | |
/* Determine parity due to swaps */ | |
zeros = 0; | |
bit = exp; | |
while (bit > 1) | |
{ | |
zeros += !(bit & 1); | |
bit >>= 1; | |
} | |
if (zeros % 2) | |
{ | |
R = res; | |
S = tmp; | |
} | |
else | |
{ | |
R = tmp; | |
S = res; | |
} | |
bit = UWORD(1) << (FLINT_BIT_COUNT(exp) - 2); | |
status |= gr_mul(R, x, x, ctx); | |
if (bit & exp) | |
{ | |
status |= gr_mul(S, R, x, ctx); | |
T = R; | |
R = S; | |
S = T; | |
} | |
while (bit >>= 1) | |
{ | |
status |= gr_mul(S, R, R, ctx); | |
if (bit & exp) | |
{ | |
status |= gr_mul(R, S, x, ctx); | |
} | |
else | |
{ | |
T = R; | |
R = S; | |
S = T; | |
} | |
} | |
return status; | |
} | |
int | |
gr_generic_pow_ui(gr_ptr res, gr_srcptr x, ulong e, gr_ctx_t ctx) | |
{ | |
int status; | |
if (e == 0) | |
{ | |
return gr_one(res, ctx); | |
} | |
else if (e == 1) | |
{ | |
return gr_set(res, x, ctx); | |
} | |
else if (e == 2) | |
{ | |
return gr_mul(res, x, x, ctx); | |
} | |
else if (e == 4) | |
{ | |
status = gr_mul(res, x, x, ctx); | |
status |= gr_mul(res, res, res, ctx); | |
return status; | |
} | |
else | |
{ | |
gr_ptr t, u; | |
GR_TMP_START; | |
if (res == x) | |
{ | |
GR_TMP_INIT2(t, u, ctx); | |
gr_set(u, x, ctx); | |
status = _gr_generic_pow_ui_binexp(res, t, u, e, ctx); | |
GR_TMP_CLEAR2(t, u, ctx); | |
} | |
else | |
{ | |
GR_TMP_INIT1(t, ctx); | |
status = _gr_generic_pow_ui_binexp(res, t, x, e, ctx); | |
GR_TMP_CLEAR1(t, ctx); | |
} | |
GR_TMP_END; | |
return status; | |
} | |
} | |
int | |
gr_generic_pow_si(gr_ptr res, gr_srcptr x, slong e, gr_ctx_t ctx) | |
{ | |
if (e >= 0) | |
{ | |
return gr_generic_pow_ui(res, x, e, ctx); | |
} | |
else | |
{ | |
int status; | |
status = gr_inv(res, x, ctx); | |
if (status == GR_SUCCESS) | |
status = gr_generic_pow_ui(res, x, -e, ctx); | |
return status; | |
} | |
} | |
/* tbd */ | |
int | |
gr_pow_ui(gr_ptr res, gr_srcptr x, ulong e, gr_ctx_t ctx) | |
{ | |
return gr_generic_pow_ui(res, x, e, ctx); | |
} | |
int | |
gr_print(gr_srcptr x, gr_ctx_t ctx) | |
{ | |
gr_stream_t out; | |
gr_stream_init_file(out, stdout); | |
gr_write(out, x, ctx); | |
return GR_SUCCESS; | |
} | |
int | |
gr_println(gr_srcptr x, gr_ctx_t ctx) | |
{ | |
gr_stream_t out; | |
gr_stream_init_file(out, stdout); | |
gr_write(out, x, ctx); | |
gr_stream_write(out, "\n"); | |
return GR_SUCCESS; | |
} | |
/* Todo: generic vectors */ | |
typedef struct | |
{ | |
gr_ptr entries; | |
slong length; | |
slong alloc; | |
} | |
gr_vec_struct; | |
typedef gr_vec_struct gr_vec_t[1]; | |
/* Todo: generic matrices */ | |
typedef struct | |
{ | |
gr_ptr entries; | |
slong r; | |
slong c; | |
gr_ptr * rows; | |
} | |
gr_mat_struct; | |
typedef gr_mat_struct gr_mat_t[1]; | |
#define GR_MAT_ENTRY(mat,i,j,ctx) GR_ENTRY((mat)->rows[i], j, sz) | |
#define gr_mat_nrows(mat, ctx) ((mat)->r) | |
#define gr_mat_ncols(mat, ctx) ((mat)->c) | |
int | |
gr_mat_init(gr_mat_t mat, slong rows, slong cols, gr_ctx_t ctx) | |
{ | |
slong i, sz; | |
sz = ctx->sizeof_elem; | |
if (rows != 0) | |
mat->rows = flint_malloc(rows * sizeof(gr_ptr)); | |
else | |
mat->rows = NULL; | |
if (rows != 0 && cols != 0) | |
{ | |
mat->entries = (gr_ptr) flint_malloc(flint_mul_sizes(rows, cols) * sz); | |
_gr_vec_init(mat->entries, rows * cols, ctx); | |
for (i = 0; i < rows; i++) | |
mat->rows[i] = GR_ENTRY(mat->entries, i * cols, sz); | |
} | |
else | |
{ | |
mat->entries = NULL; | |
for (i = 0; i < rows; i++) | |
mat->rows[i] = NULL; | |
} | |
mat->r = rows; | |
mat->c = cols; | |
return GR_SUCCESS; | |
} | |
int | |
gr_mat_clear(gr_mat_t mat, gr_ctx_t ctx) | |
{ | |
if (mat->entries != NULL) | |
{ | |
_gr_vec_clear(mat->entries, mat->r * mat->c, ctx); | |
flint_free(mat->entries); | |
flint_free(mat->rows); | |
} | |
else if (mat->r != 0) | |
{ | |
flint_free(mat->rows); | |
} | |
return GR_SUCCESS; | |
} | |
int | |
gr_mat_randtest(gr_mat_t mat, flint_rand_t state, void * options, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, r, c; | |
r = gr_mat_nrows(mat, ctx); | |
c = gr_mat_ncols(mat, ctx); | |
status = GR_SUCCESS; | |
for (i = 0; i < r; i++) | |
{ | |
status |= _gr_vec_randtest(mat->rows[i], state, c, options, ctx); | |
} | |
return status; | |
} | |
int | |
gr_mat_equal(int * res, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx) | |
{ | |
int status, equal, this_equal; | |
slong i, r, c, sz; | |
sz = ctx->sizeof_elem; | |
status = GR_SUCCESS; | |
r = gr_mat_nrows(mat1, ctx); | |
c = gr_mat_ncols(mat1, ctx); | |
if (r != gr_mat_nrows(mat2, ctx) || | |
c != gr_mat_ncols(mat2, ctx)) | |
{ | |
res[0] = 0; | |
return GR_SUCCESS; | |
} | |
if (r == 0 || c == 0) | |
{ | |
res[0] = 1; | |
return GR_SUCCESS; | |
} | |
equal = 1; | |
for (i = 0; i < r; i++) | |
{ | |
status |= _gr_vec_equal(&this_equal, mat1->rows[i], mat2->rows[i], c, ctx); | |
equal = equal && this_equal; | |
} | |
res[0] = equal; | |
return status; | |
} | |
int | |
gr_mat_zero(gr_mat_t res, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, r, c; | |
r = gr_mat_nrows(res, ctx); | |
c = gr_mat_ncols(res, ctx); | |
status = GR_SUCCESS; | |
for (i = 0; i < r; i++) | |
{ | |
status |= _gr_vec_zero(res->rows[i], c, ctx); | |
} | |
return status; | |
} | |
int | |
gr_mat_set_si(gr_mat_t res, slong v, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, r, c, sz; | |
r = gr_mat_nrows(res, ctx); | |
c = gr_mat_ncols(res, ctx); | |
sz = ctx->sizeof_elem; | |
status = gr_mat_zero(res, ctx); | |
for (i = 0; i < FLINT_MIN(r, c); i++) | |
status |= gr_set_si(GR_MAT_ENTRY(res, i, i, sz), v, ctx); | |
return status; | |
} | |
int | |
gr_mat_one(gr_mat_t res, gr_ctx_t ctx) | |
{ | |
return gr_mat_set_si(res, 1, ctx); | |
} | |
int | |
gr_mat_set(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, r, c; | |
r = gr_mat_nrows(res, ctx); | |
c = gr_mat_ncols(res, ctx); | |
if (r != gr_mat_nrows(mat, ctx) || | |
c != gr_mat_ncols(mat, ctx)) | |
{ | |
return GR_DOMAIN; | |
} | |
status = GR_SUCCESS; | |
if (res != mat) | |
{ | |
for (i = 0; i < r; i++) | |
{ | |
status |= _gr_vec_set(res->rows[i], mat->rows[i], c, ctx); | |
} | |
} | |
return status; | |
} | |
int | |
gr_mat_neg(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, r, c; | |
r = gr_mat_nrows(res, ctx); | |
c = gr_mat_ncols(res, ctx); | |
if (r != gr_mat_nrows(mat, ctx) || | |
c != gr_mat_ncols(mat, ctx)) | |
{ | |
return GR_DOMAIN; | |
} | |
status = GR_SUCCESS; | |
for (i = 0; i < r; i++) | |
{ | |
status |= _gr_vec_neg(res->rows[i], mat->rows[i], c, ctx); | |
} | |
return status; | |
} | |
int | |
gr_mat_swap_entrywise(gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, r, c; | |
r = gr_mat_nrows(mat1, ctx); | |
c = gr_mat_ncols(mat1, ctx); | |
if (r != gr_mat_nrows(mat2, ctx) || | |
c != gr_mat_ncols(mat2, ctx)) | |
{ | |
return GR_DOMAIN; | |
} | |
status = GR_SUCCESS; | |
for (i = 0; i < r; i++) | |
{ | |
status |= _gr_vec_swap(mat1->rows[i], mat2->rows[i], c, ctx); | |
} | |
return status; | |
} | |
int | |
gr_mat_add(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, r, c; | |
r = gr_mat_nrows(res, ctx); | |
c = gr_mat_ncols(res, ctx); | |
if (r != gr_mat_nrows(mat1, ctx) || | |
c != gr_mat_ncols(mat1, ctx) || | |
r != gr_mat_nrows(mat2, ctx) || | |
c != gr_mat_ncols(mat2, ctx)) | |
{ | |
return GR_DOMAIN; | |
} | |
status = GR_SUCCESS; | |
for (i = 0; i < r; i++) | |
{ | |
status |= _gr_vec_add(res->rows[i], mat1->rows[i], mat2->rows[i], c, ctx); | |
} | |
return status; | |
} | |
int | |
gr_mat_sub(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx) | |
{ | |
int status; | |
slong i, r, c; | |
r = gr_mat_nrows(res, ctx); | |
c = gr_mat_ncols(res, ctx); | |
if (r != gr_mat_nrows(mat1, ctx) || | |
c != gr_mat_ncols(mat1, ctx) || | |
r != gr_mat_nrows(mat2, ctx) || | |
c != gr_mat_ncols(mat2, ctx)) | |
{ | |
return GR_DOMAIN; | |
} | |
status = GR_SUCCESS; | |
for (i = 0; i < r; i++) | |
{ | |
status |= _gr_vec_sub(res->rows[i], mat1->rows[i], mat2->rows[i], c, ctx); | |
} | |
return status; | |
} | |
// todo status | |
int | |
gr_mat_print(const gr_mat_t mat, gr_ctx_t ctx) | |
{ | |
int status; | |
slong r, c; | |
slong i, j; | |
slong sz; | |
sz = ctx->sizeof_elem; | |
r = gr_mat_nrows(mat, ctx); | |
c = gr_mat_ncols(mat, ctx); | |
status = GR_SUCCESS; | |
flint_printf("["); | |
for (i = 0; i < r; i++) | |
{ | |
flint_printf("["); | |
for (j = 0; j < c; j++) | |
{ | |
status |= gr_print(GR_MAT_ENTRY(mat, i, j, sz), ctx); | |
if (j < c - 1) | |
flint_printf(", "); | |
} | |
if (i < r - 1) | |
flint_printf("],\n"); | |
else | |
flint_printf("]"); | |
} | |
flint_printf("]\n"); | |
return status; | |
} | |
int | |
gr_mat_mul_classical(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx) | |
{ | |
slong ar, ac, br, bc, i, j, k, sz; | |
int status; | |
ar = gr_mat_nrows(A, ctx); | |
ac = gr_mat_ncols(A, ctx); | |
br = gr_mat_nrows(B, ctx); | |
bc = gr_mat_ncols(B, ctx); | |
if (ac != br || ar != gr_mat_nrows(C, ctx) || bc != gr_mat_ncols(C, ctx)) | |
return GR_DOMAIN; | |
if (br == 0) | |
{ | |
return gr_mat_zero(C, ctx); | |
} | |
status = GR_SUCCESS; | |
if (A == C || B == C) | |
{ | |
gr_mat_t T; | |
status |= gr_mat_init(T, ar, bc, ctx); | |
status |= gr_mat_mul_classical(T, A, B, ctx); | |
status |= gr_mat_swap_entrywise(T, C, ctx); | |
status |= gr_mat_clear(T, ctx); | |
return status; | |
} | |
sz = ctx->sizeof_elem; | |
if (br == 1) | |
{ | |
for (i = 0; i < ar; i++) | |
{ | |
for (j = 0; j < bc; j++) | |
{ | |
status |= gr_mul(GR_MAT_ENTRY(C, i, j, sz), | |
GR_MAT_ENTRY(A, i, 0, sz), | |
GR_MAT_ENTRY(B, 0, j, sz), ctx); | |
} | |
} | |
} | |
else | |
{ | |
gr_ptr tmp; | |
TMP_INIT; | |
TMP_START; | |
tmp = TMP_ALLOC(sz * br * bc); | |
for (i = 0; i < br; i++) | |
for (j = 0; j < bc; j++) | |
memcpy(GR_ENTRY(tmp, j * br + i, sz), GR_MAT_ENTRY(B, i, j, sz), sz); | |
for (i = 0; i < ar; i++) | |
{ | |
for (j = 0; j < bc; j++) | |
{ | |
status |= _gr_vec_dot(GR_MAT_ENTRY(C, i, j, sz), NULL, 0, | |
GR_MAT_ENTRY(A, i, 0, sz), GR_ENTRY(tmp, j * br, sz), br, ctx); | |
} | |
} | |
TMP_END; | |
} | |
return status; | |
} | |
/* Todo: generic polynomials */ | |
typedef struct | |
{ | |
gr_ptr coeffs; | |
slong length; | |
slong alloc; | |
} | |
gr_poly_struct; | |
typedef gr_poly_struct gr_poly_t[1]; | |
/* | |
A ring to test. | |
*/ | |
typedef unsigned char nmod8_struct; | |
typedef nmod8_struct nmod8_t[1]; | |
int | |
nmod8_init(nmod8_t x, nmod_t * ctx) | |
{ | |
x[0] = 0; | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_clear(nmod8_t x, nmod_t * ctx) | |
{ | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_swap(nmod8_t x, nmod8_t y, nmod_t * ctx) | |
{ | |
nmod8_t t; | |
*t = *x; | |
*x = *y; | |
*y = *t; | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_randtest(nmod8_t res, flint_rand_t state, const void * options, nmod_t * ctx) | |
{ | |
res[0] = n_randtest(state) % ctx->n; | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_write(gr_stream_t out, const nmod8_t x, nmod_t * ctx) | |
{ | |
gr_stream_write_si(out, x[0]); | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_zero(nmod8_t x, nmod_t * ctx) | |
{ | |
x[0] = 0; | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_one(nmod8_t x, nmod_t * ctx) | |
{ | |
x[0] = (ctx->n != 0); | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_set_si(nmod8_t res, slong v, nmod_t * ctx) | |
{ | |
ulong t; | |
t = FLINT_ABS(v); | |
NMOD_RED(t, t, *ctx); | |
if (v < 0) | |
t = nmod_neg(t, *ctx); | |
res[0] = t; | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_is_zero(int * res, const nmod8_t x, nmod_t * ctx) | |
{ | |
res[0] = (x[0] == 0); | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_is_one(int * res, const nmod8_t x, nmod_t * ctx) | |
{ | |
res[0] = (x[0] == (ctx->n != 1)); | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_equal(int * res, const nmod8_t x, const nmod8_t y, nmod_t * ctx) | |
{ | |
res[0] = (x[0] == y[0]); | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_set(nmod8_t res, const nmod8_t x, nmod_t * ctx) | |
{ | |
res[0] = x[0]; | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_neg(nmod8_t res, const nmod8_t x, nmod_t * ctx) | |
{ | |
res[0] = nmod_neg(x[0], *ctx); | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_add(nmod8_t res, const nmod8_t x, const nmod8_t y, nmod_t * ctx) | |
{ | |
res[0] = nmod_add(x[0], y[0], *ctx); | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_add_si(nmod8_t res, const nmod8_t x, slong y, nmod_t * ctx) | |
{ | |
nmod8_t t; | |
nmod8_set_si(t, y, ctx); | |
return nmod8_add(res, x, t, ctx); | |
} | |
int | |
nmod8_sub(nmod8_t res, const nmod8_t x, const nmod8_t y, nmod_t * ctx) | |
{ | |
res[0] = nmod_sub(x[0], y[0], *ctx); | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_mul(nmod8_t res, const nmod8_t x, const nmod8_t y, nmod_t * ctx) | |
{ | |
res[0] = nmod_mul(x[0], y[0], *ctx); | |
return GR_SUCCESS; | |
} | |
int | |
nmod8_mul_si(nmod8_t res, const nmod8_t x, slong y, nmod_t * ctx) | |
{ | |
nmod8_t t; | |
nmod8_set_si(t, y, ctx); | |
return nmod8_mul(res, x, t, ctx); | |
} | |
int | |
nmod8_inv(nmod8_t res, const nmod8_t x, nmod_t * ctx) | |
{ | |
ulong r, g; | |
g = n_gcdinv(&r, x[0], ctx->n); | |
if (g == 1) | |
{ | |
res[0] = r; | |
return GR_SUCCESS; | |
} | |
else | |
{ | |
res[0] = 0; | |
return GR_DOMAIN; | |
} | |
} | |
int | |
nmod8_div(nmod8_t res, const nmod8_t x, const nmod8_t y, nmod_t * ctx) | |
{ | |
nmod8_t t; | |
int status; | |
status = nmod8_inv(t, y, ctx); | |
nmod8_mul(res, x, t, ctx); | |
return status; | |
} | |
int | |
nmod8_div_si(nmod8_t res, const nmod8_t x, slong y, nmod_t * ctx) | |
{ | |
nmod8_t t; | |
nmod8_set_si(t, y, ctx); | |
return nmod8_div(res, x, t, ctx); | |
} | |
int | |
nmod8_is_invertible(int * res, const nmod8_t x, nmod_t * ctx) | |
{ | |
ulong r, g; | |
g = n_gcdinv(&r, x[0], ctx->n); | |
res[0] = (g == 1); | |
return GR_SUCCESS; | |
} | |
gr_methods nmod8_methods = { | |
(gr_func_out) nmod8_init, | |
(gr_func_out) nmod8_clear, | |
(gr_func_out_out) nmod8_swap, | |
(gr_func_randtest) nmod8_randtest, | |
(gr_func_stream_in) nmod8_write, | |
(gr_func_out) nmod8_zero, | |
(gr_func_out) nmod8_one, | |
(gr_func_outbool_in) nmod8_is_zero, | |
(gr_func_outbool_in) nmod8_is_one, | |
(gr_func_outbool_in_in) nmod8_equal, | |
(gr_func_out_in) nmod8_set, | |
(gr_func_out_si) nmod8_set_si, | |
(gr_func_out_in) nmod8_neg, | |
(gr_func_out_in_in) nmod8_add, | |
(gr_func_out_in_si) nmod8_add_si, | |
(gr_func_out_in_in) nmod8_sub, | |
(gr_func_out_in_in) nmod8_mul, | |
(gr_func_out_in_si) nmod8_mul_si, | |
(gr_func_out_in_in) nmod8_div, | |
(gr_func_out_in_in) nmod8_div, | |
(gr_func_out_in_si) nmod8_div_si, | |
(gr_func_outbool_in) nmod8_is_invertible, | |
(gr_func_out_in) nmod8_inv, | |
}; | |
void | |
gr_ctx_init_nmod8(gr_ctx_t ctx, unsigned char n) | |
{ | |
ctx->flags = GR_COMMUTATIVE_RING; | |
ctx->sizeof_elem = sizeof(nmod8_struct); | |
ctx->elem_ctx = flint_malloc(sizeof(nmod_t)); /* This could be something more interesting */ | |
nmod_init(ctx->elem_ctx, n); | |
ctx->methods = &nmod8_methods; | |
ctx->vec_methods = &gr_vec_generic_methods; | |
ctx->debug_string = "nmod8 ring"; | |
} | |
void | |
gr_ctx_clear_nmod8(gr_ctx_t ctx) | |
{ | |
flint_free(ctx->elem_ctx); | |
} | |
/* Matrix ring to test */ | |
typedef struct | |
{ | |
gr_ctx_struct * base_ring; | |
slong n; | |
} | |
matrix_ctx_t; | |
int | |
matrix_init(gr_mat_t res, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_init(res, ctx->n, ctx->n, ctx->base_ring); | |
} | |
int | |
matrix_clear(gr_mat_t res, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_clear(res, ctx->base_ring); | |
} | |
/* TODO UNIFY */ | |
int | |
matrix_write(gr_stream_t out, gr_mat_t res, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_print(res, ctx->base_ring); | |
} | |
int | |
matrix_randtest(gr_mat_t res, flint_rand_t state, void * options, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_randtest(res, state, options, ctx->base_ring); | |
} | |
int | |
matrix_equal(int * equal, const gr_mat_t mat1, const gr_mat_t mat2, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_equal(equal, mat1, mat2, ctx->base_ring); | |
} | |
int | |
matrix_set(gr_mat_t res, const gr_mat_t mat, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_set(res, mat, ctx->base_ring); | |
} | |
int | |
matrix_zero(gr_mat_t res, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_zero(res, ctx->base_ring); | |
} | |
int | |
matrix_one(gr_mat_t res, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_one(res, ctx->base_ring); | |
} | |
int | |
matrix_add(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_add(res, mat1, mat2, ctx->base_ring); | |
} | |
int | |
matrix_mul(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, matrix_ctx_t * ctx) | |
{ | |
return gr_mat_mul_classical(res, mat1, mat2, ctx->base_ring); | |
} | |
#define matrix_swap gr_not_implemented | |
#define matrix_is_zero gr_not_implemented | |
#define matrix_is_one gr_not_implemented | |
#define matrix_set_si gr_not_implemented | |
#define matrix_neg gr_not_implemented | |
#define matrix_sub gr_not_implemented | |
gr_methods matrix_methods = { | |
(gr_func_out) matrix_init, | |
(gr_func_out) matrix_clear, | |
(gr_func_out_out) matrix_swap, | |
(gr_func_randtest) matrix_randtest, | |
(gr_func_stream_in) matrix_write, | |
(gr_func_out) matrix_zero, | |
(gr_func_out) matrix_one, | |
(gr_func_outbool_in) matrix_is_zero, | |
(gr_func_outbool_in) matrix_is_one, | |
(gr_func_outbool_in_in) matrix_equal, | |
(gr_func_out_in) matrix_set, | |
(gr_func_out_si) matrix_set_si, | |
(gr_func_out_in) matrix_neg, | |
(gr_func_out_in_in) matrix_add, | |
(gr_func_out_in_si) gr_not_implemented, | |
(gr_func_out_in_in) matrix_sub, | |
(gr_func_out_in_in) matrix_mul, | |
(gr_func_out_in_si) gr_not_implemented, | |
(gr_func_out_in_in) gr_not_implemented, | |
(gr_func_out_in_in) gr_not_implemented, | |
(gr_func_out_in_si) gr_not_implemented, | |
(gr_func_outbool_in) gr_not_implemented, | |
(gr_func_out_in) gr_not_implemented, | |
}; | |
/* rename: gr_ctx_init_gr_mat */ | |
void | |
gr_ctx_init_matrix(gr_ctx_t ctx, gr_ctx_t base_ring, slong n) | |
{ | |
ctx->flags = 0; | |
ctx->sizeof_elem = sizeof(gr_mat_struct); | |
ctx->elem_ctx = flint_malloc(sizeof(matrix_ctx_t)); | |
((matrix_ctx_t *) ctx->elem_ctx)->base_ring = (gr_ctx_struct *) base_ring; | |
((matrix_ctx_t *) ctx->elem_ctx)->n = n; | |
ctx->methods = &matrix_methods; | |
ctx->vec_methods = &gr_vec_generic_methods; | |
ctx->debug_string = "matrix ring"; | |
} | |
void | |
gr_ctx_clear_matrix(gr_ctx_t ctx) | |
{ | |
flint_free(ctx->elem_ctx); | |
} | |
#define TIMEIT_PRINT2(__timer, __reps) \ | |
flint_printf("cpu/wall(s): %g %g", \ | |
__timer->cpu*0.001/__reps, __timer->wall*0.001 / __reps); | |
#define TIMEIT_REPEAT(__timer, __reps) \ | |
do \ | |
{ \ | |
slong __timeit_k; \ | |
__reps = 1; \ | |
while (1) \ | |
{ \ | |
timeit_start(__timer); \ | |
for (__timeit_k = 0; __timeit_k < __reps; __timeit_k++) \ | |
{ | |
#define TIMEIT_END_REPEAT(__timer, __reps) \ | |
} \ | |
timeit_stop(__timer); \ | |
if (__timer->cpu >= 100) \ | |
break; \ | |
__reps *= 10; \ | |
} \ | |
} while (0); | |
#define TIMEIT_START \ | |
do { \ | |
timeit_t __timer; slong __reps; \ | |
TIMEIT_REPEAT(__timer, __reps) | |
#define TIMEIT_STOP \ | |
TIMEIT_END_REPEAT(__timer, __reps) \ | |
TIMEIT_PRINT(__timer, __reps) \ | |
} while (0); | |
#define TIMEIT_ONCE_START \ | |
do \ | |
{ \ | |
timeit_t __timer; \ | |
timeit_start(__timer); \ | |
do { \ | |
#define TIMEIT_ONCE_STOP \ | |
} while (0); \ | |
timeit_stop(__timer); \ | |
TIMEIT_PRINT(__timer, 1) \ | |
} while (0); \ | |
typedef int ((*gr_test_function)(gr_ctx_t, flint_rand_t, int)); | |
int | |
gr_test_add_associativity(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal; | |
GR_TMP_START; | |
gr_ptr x, y, z; | |
gr_ptr xy, yz, xy_z, x_yz; | |
GR_TMP_INIT3(x, y, z, R); | |
GR_TMP_INIT4(xy, yz, xy_z, x_yz, R); | |
gr_randtest(x, state, NULL, R); | |
gr_randtest(y, state, NULL, R); | |
gr_randtest(z, state, NULL, R); | |
gr_randtest(xy, state, NULL, R); | |
gr_randtest(yz, state, NULL, R); | |
status = GR_SUCCESS; | |
status |= gr_add(xy, x, y, R); | |
status |= gr_add(yz, y, z, R); | |
status |= gr_add(xy_z, xy, z, R); | |
status |= gr_add(x_yz, x, yz, R); | |
status |= gr_equal(&equal, xy_z, x_yz, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
printf("\n"); | |
printf("x = \n"); gr_println(x, R); | |
printf("y = \n"); gr_println(y, R); | |
printf("z = \n"); gr_println(z, R); | |
printf("x + y = \n"); gr_println(xy, R); | |
printf("y + z = \n"); gr_println(yz, R); | |
printf("(x + y) + z = \n"); gr_println(xy_z, R); | |
printf("x + (y + z) = \n"); gr_println(x_yz, R); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR3(x, y, z, R); | |
GR_TMP_CLEAR4(xy, yz, xy_z, x_yz, R); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_test_add_commutativity(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal; | |
GR_TMP_START; | |
gr_ptr x, y, xy, yx; | |
GR_TMP_INIT4(x, y, xy, yx, R); | |
gr_randtest(x, state, NULL, R); | |
gr_randtest(y, state, NULL, R); | |
status = GR_SUCCESS; | |
status |= gr_add(xy, x, y, R); | |
status |= gr_add(yx, y, x, R); | |
status |= gr_equal(&equal, xy, yx, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
printf("\n"); | |
printf("x = \n"); gr_println(x, R); | |
printf("y = \n"); gr_println(y, R); | |
printf("y + y = \n"); gr_println(xy, R); | |
printf("y + x = \n"); gr_println(yx, R); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR4(x, y, xy, yx, R); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_test_add_aliasing(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal, alias; | |
GR_TMP_START; | |
gr_ptr x, y, xy1, xy2; | |
GR_TMP_INIT4(x, y, xy1, xy2, R); | |
gr_randtest(x, state, NULL, R); | |
gr_randtest(y, state, NULL, R); | |
status = GR_SUCCESS; | |
status |= gr_add(xy1, x, y, R); | |
alias = n_randint(state, 4); | |
switch (alias) | |
{ | |
case 0: | |
status |= gr_add(xy1, x, y, R); | |
gr_set(xy2, x, R); | |
status |= gr_add(xy2, xy2, y, R); | |
break; | |
case 1: | |
status |= gr_add(xy1, x, y, R); | |
gr_set(xy2, y, R); | |
status |= gr_add(xy2, x, y, R); | |
break; | |
case 2: | |
gr_set(y, x, R); | |
status |= gr_add(xy1, x, y, R); | |
status |= gr_add(xy2, x, x, R); | |
break; | |
default: | |
gr_set(y, x, R); | |
gr_set(xy2, x, R); | |
status |= gr_add(xy1, x, y, R); | |
status |= gr_add(xy2, xy2, xy2, R); | |
} | |
status |= gr_equal(&equal, xy1, xy2, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
printf("\n"); | |
printf("alias: %d\n", alias); | |
printf("x = "); gr_println(x, R); | |
printf("y = "); gr_println(y, R); | |
printf("y + y (1) = "); gr_println(xy1, R); | |
printf("x + y (2) = "); gr_println(xy2, R); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR4(x, y, xy1, xy2, R); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_test_inv_involution(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal; | |
GR_TMP_START; | |
gr_ptr x, x_inv, x_inv_inv; | |
GR_TMP_INIT3(x, x_inv, x_inv_inv, R); | |
gr_randtest(x, state, NULL, R); | |
gr_randtest(x_inv, state, NULL, R); | |
gr_randtest(x_inv_inv, state, NULL, R); | |
status = GR_SUCCESS; | |
status |= gr_inv(x_inv, x, R); | |
status |= gr_inv(x_inv_inv, x_inv, R); | |
status |= gr_equal(&equal, x, x_inv_inv, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
printf("\n"); | |
printf("x = \n"); gr_println(x, R); | |
printf("x ^ -1 = \n"); gr_println(x_inv, R); | |
printf("(x ^ -1) ^ -1 = \n"); gr_println(x_inv_inv, R); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR3(x, x_inv, x_inv_inv, R); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_test_inv_multiplication(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal1, equal2; | |
GR_TMP_START; | |
gr_ptr x, x_inv, x_inv_x, x_x_inv; | |
GR_TMP_INIT4(x, x_inv, x_inv_x, x_x_inv, R); | |
gr_randtest(x, state, NULL, R); | |
gr_randtest(x_inv, state, NULL, R); | |
gr_randtest(x_inv_x, state, NULL, R); | |
gr_randtest(x_x_inv, state, NULL, R); | |
status = GR_SUCCESS; | |
status |= gr_inv(x_inv, x, R); | |
status |= gr_mul(x_inv_x, x_inv, x, R); | |
status |= gr_mul(x_x_inv, x, x_inv, R); | |
status |= gr_is_one(&equal1, x_inv_x, R); | |
status |= gr_is_one(&equal2, x_x_inv, R); | |
if (status == GR_SUCCESS && (!equal1 || !equal2)) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
printf("\n"); | |
printf("x = \n"); gr_println(x, R); | |
printf("x ^ -1 = \n"); gr_println(x_inv, R); | |
printf("(x ^ -1) * x = \n"); gr_println(x_inv_x, R); | |
printf("x * (x ^ -1) = \n"); gr_println(x_x_inv, R); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR4(x, x_inv, x_inv_x, x_x_inv, R); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_test_pow_ui_exponent_addition(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal; | |
GR_TMP_START; | |
ulong a, b; | |
gr_ptr x, xa, xb, xab, xaxb; | |
GR_TMP_INIT5(x, xa, xb, xab, xaxb, R); | |
gr_randtest(x, state, NULL, R); | |
gr_randtest(xa, state, NULL, R); | |
gr_randtest(xb, state, NULL, R); | |
gr_randtest(xab, state, NULL, R); | |
gr_randtest(xaxb, state, NULL, R); | |
do { | |
a = n_randtest(state); | |
b = n_randtest(state); | |
} while (a + b < a); | |
status = GR_SUCCESS; | |
status |= gr_pow_ui(xa, x, a, R); | |
status |= gr_pow_ui(xb, x, b, R); | |
status |= gr_pow_ui(xab, x, a + b, R); | |
status |= gr_mul(xaxb, xa, xb, R); | |
status |= gr_equal(&equal, xab, xaxb, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
printf("\n"); | |
printf("x = \n"); gr_println(x, R); | |
flint_printf("a = %wu\n", a); | |
flint_printf("b = %wu\n", b); | |
printf("x ^ a = \n"); gr_println(xa, R); | |
printf("x ^ b = \n"); gr_println(xb, R); | |
printf("x ^ (a + b) = \n"); gr_println(xab, R); | |
printf("(x ^ a) * (x ^ b) = \n"); gr_println(xaxb, R); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR5(x, xa, xb, xab, xaxb, R); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_test_pow_ui_base_scalar_multiplication(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal; | |
GR_TMP_START; | |
ulong a; | |
slong y; | |
gr_ptr x, xa, ya, xya, xaya; | |
GR_TMP_INIT3(x, xa, ya, R); | |
GR_TMP_INIT2(xya, xaya, R); | |
gr_randtest(x, state, NULL, R); | |
gr_randtest(xa, state, NULL, R); | |
gr_randtest(ya, state, NULL, R); | |
y = n_randtest(state); | |
a = n_randtest(state); | |
status = GR_SUCCESS; | |
status |= gr_pow_ui(xa, x, a, R); | |
status |= gr_set_si(ya, y, R); | |
status |= gr_pow_ui(ya, ya, a, R); | |
status |= gr_set_si(xya, y, R); | |
status |= gr_mul(xya, x, xya, R); /* todo mul_si */ | |
status |= gr_pow_ui(xya, xya, a, R); | |
status |= gr_mul(xaya, xa, ya, R); | |
status |= gr_equal(&equal, xya, xaya, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
printf("\n"); | |
printf("x = \n"); gr_println(x, R); | |
flint_printf("y = %wd\n", y); | |
flint_printf("a = %wu\n", a); | |
printf("x ^ a = \n"); gr_println(xa, R); | |
printf("y ^ a = \n"); gr_println(ya, R); | |
printf("(x * y) ^ a = \n"); gr_println(xya, R); | |
printf("(x ^ a) * (y ^ a) = \n"); gr_println(xaya, R); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR3(x, xa, ya, R); | |
GR_TMP_CLEAR2(xya, xaya, R); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_test_pow_ui_base_multiplication(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal; | |
GR_TMP_START; | |
ulong a; | |
gr_ptr x, y, xa, ya, xya, xaya; | |
GR_TMP_INIT4(x, y, xa, ya, R); | |
GR_TMP_INIT2(xya, xaya, R); | |
gr_randtest(x, state, NULL, R); | |
gr_randtest(y, state, NULL, R); | |
gr_randtest(xa, state, NULL, R); | |
gr_randtest(ya, state, NULL, R); | |
a = n_randtest(state); | |
status = GR_SUCCESS; | |
status |= gr_pow_ui(xa, x, a, R); | |
status |= gr_pow_ui(ya, y, a, R); | |
status |= gr_mul(xya, x, y, R); | |
status |= gr_pow_ui(xya, xya, a, R); | |
status |= gr_mul(xaya, xa, ya, R); | |
status |= gr_equal(&equal, xya, xaya, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
printf("\n"); | |
printf("x = \n"); gr_println(x, R); | |
printf("y = \n"); gr_println(y, R); | |
flint_printf("a = %wu\n", a); | |
printf("x ^ a = \n"); gr_println(xa, R); | |
printf("y ^ a = \n"); gr_println(ya, R); | |
printf("(x * y) ^ a = \n"); gr_println(xya, R); | |
printf("(x ^ a) * (y ^ a) = \n"); gr_println(xaya, R); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR4(x, y, xa, ya, R); | |
GR_TMP_CLEAR2(xya, xaya, R); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_test_pow_ui_aliasing(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal; | |
GR_TMP_START; | |
ulong a; | |
gr_ptr x, xa1, xa2; | |
GR_TMP_INIT3(x, xa1, xa2, R); | |
gr_randtest(x, state, NULL, R); | |
gr_randtest(xa1, state, NULL, R); | |
a = n_randtest(state); | |
status = GR_SUCCESS; | |
status |= gr_pow_ui(xa1, x, a, R); | |
status |= gr_set(xa2, x, R); | |
status |= gr_pow_ui(xa2, xa2, a, R); | |
status |= gr_equal(&equal, xa1, xa2, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
printf("\n"); | |
printf("x = \n"); gr_println(x, R); | |
flint_printf("a = %wu\n", a); | |
printf("x ^ a (1) = \n"); gr_println(xa1, R); | |
printf("x ^ a (2) = \n"); gr_println(xa2, R); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR3(x, xa1, xa2, R); | |
GR_TMP_END; | |
return status; | |
} | |
int | |
gr_test_vec_add(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, aliasing, equal; | |
slong len; | |
GR_TMP_START; | |
gr_ptr x, y, xy1, xy2; | |
len = n_randint(state, 10); | |
GR_TMP_INIT_VEC(x, len, R); | |
GR_TMP_INIT_VEC(y, len, R); | |
GR_TMP_INIT_VEC(xy1, len, R); | |
GR_TMP_INIT_VEC(xy2, len, R); | |
_gr_vec_randtest(x, state, len, NULL, R); | |
_gr_vec_randtest(y, state, len, NULL, R); | |
_gr_vec_randtest(xy1, state, len, NULL, R); | |
_gr_vec_randtest(xy2, state, len, NULL, R); | |
status = GR_SUCCESS; | |
aliasing = n_randint(state, 4); | |
switch (aliasing) | |
{ | |
case 0: | |
status |= _gr_vec_set(xy1, x, len, R); | |
status |= _gr_vec_add(xy1, xy1, y, len, R); | |
break; | |
case 1: | |
status |= _gr_vec_set(xy1, y, len, R); | |
status |= _gr_vec_add(xy1, x, xy1, len, R); | |
break; | |
case 2: | |
status |= _gr_vec_set(y, x, len, R); | |
status |= _gr_vec_set(xy1, x, len, R); | |
status |= _gr_vec_add(xy1, xy1, xy1, len, R); | |
break; | |
default: | |
status |= _gr_vec_add(xy1, x, y, len, R); | |
} | |
status |= gr_generic_vec_add(xy2, x, y, len, R); | |
status |= _gr_vec_equal(&equal, xy1, xy2, len, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
/* todo: vec print */ | |
printf("\n"); | |
printf("aliasing: %d\n", aliasing); | |
printf("\n"); | |
} | |
GR_TMP_CLEAR_VEC(x, len, R); | |
GR_TMP_CLEAR_VEC(y, len, R); | |
GR_TMP_CLEAR_VEC(xy1, len, R); | |
GR_TMP_CLEAR_VEC(xy2, len, R); | |
GR_TMP_END; | |
return status; | |
} | |
/* (AB)C = A(BC) */ | |
int | |
gr_test_mat_mul_classical_associativity(gr_ctx_t R, flint_rand_t state, int verbose) | |
{ | |
int status, equal; | |
gr_mat_t A, B, C, AB, BC, AB_C, A_BC; | |
slong m, n, p, q; | |
m = n_randint(state, 5); | |
n = n_randint(state, 5); | |
p = n_randint(state, 5); | |
q = n_randint(state, 5); | |
gr_mat_init(A, m, n, R); | |
gr_mat_init(B, n, p, R); | |
gr_mat_init(C, p, q, R); | |
gr_mat_init(AB, m, p, R); | |
gr_mat_init(BC, n, q, R); | |
gr_mat_init(AB_C, m, q, R); | |
gr_mat_init(A_BC, m, q, R); | |
gr_mat_randtest(A, state, NULL, R); | |
gr_mat_randtest(B, state, NULL, R); | |
gr_mat_randtest(C, state, NULL, R); | |
gr_mat_randtest(AB, state, NULL, R); | |
gr_mat_randtest(BC, state, NULL, R); | |
gr_mat_randtest(AB_C, state, NULL, R); | |
gr_mat_randtest(A_BC, state, NULL, R); | |
status |= gr_mat_mul_classical(AB, A, B, R); | |
status |= gr_mat_mul_classical(BC, B, C, R); | |
status |= gr_mat_mul_classical(AB_C, AB, C, R); | |
status |= gr_mat_mul_classical(A_BC, A, BC, R); | |
status |= gr_mat_equal(&equal, AB_C, A_BC, R); | |
if (status == GR_SUCCESS && !equal) | |
{ | |
status = GR_WRONG; | |
} | |
if (verbose || status == GR_WRONG) | |
{ | |
/* todo: vec print */ | |
printf("\n"); | |
printf("A = \n"); gr_mat_print(A, R); printf("\n"); | |
printf("B = \n"); gr_mat_print(B, R); printf("\n"); | |
printf("C = \n"); gr_mat_print(C, R); printf("\n"); | |
printf("AB = \n"); gr_mat_print(AB, R); printf("\n"); | |
printf("BC = \n"); gr_mat_print(BC, R); printf("\n"); | |
printf("AB * C = \n"); gr_mat_print(AB_C, R); printf("\n"); | |
printf("A * BC = \n"); gr_mat_print(A_BC, R); printf("\n"); | |
printf("\n"); | |
} | |
gr_mat_clear(A, R); | |
gr_mat_clear(B, R); | |
gr_mat_clear(C, R); | |
gr_mat_clear(AB, R); | |
gr_mat_clear(BC, R); | |
gr_mat_clear(A_BC, R); | |
gr_mat_clear(AB_C, R); | |
return status; | |
} | |
void | |
gr_test_iter(gr_ctx_t R, flint_rand_t state, const char * descr, gr_test_function func, slong iters) | |
{ | |
slong iter, count_success, count_unable, count_domain; | |
int status; | |
timeit_t timer; | |
count_success = 0; | |
count_unable = 0; | |
count_domain = 0; | |
printf("%s ... ", descr); | |
fflush(stdout); | |
timeit_start(timer); | |
for (iter = 0; iter < iters; iter++) | |
{ | |
// flint_printf("iter %ld\n", iter); | |
status = func(R, state, 0); | |
if (status == GR_SUCCESS) | |
count_success++; | |
if (status & GR_UNABLE) | |
count_unable++; | |
if (status & GR_DOMAIN) | |
count_domain++; | |
if (status & GR_WRONG) | |
{ | |
flint_printf("\nFAIL\n"); | |
abort(); | |
} | |
} | |
timeit_stop(timer); | |
flint_printf("PASS (%wd successful, %wd domain, %wd unable, 0 wrong, %.3g cpu, %.3g wall)\n", | |
count_success, count_domain, count_unable, timer->cpu*0.001, timer->wall*0.001); | |
} | |
void | |
gr_test_ring(gr_ctx_t R, slong iters) | |
{ | |
flint_rand_t state; | |
flint_randinit(state); | |
gr_test_iter(R, state, "add: associativity", gr_test_add_associativity, iters); | |
gr_test_iter(R, state, "add: commutativity", gr_test_add_commutativity, iters); | |
gr_test_iter(R, state, "add: aliasing", gr_test_add_aliasing, iters); | |
gr_test_iter(R, state, "inv: multiplication", gr_test_inv_multiplication, iters); | |
gr_test_iter(R, state, "inv: involution", gr_test_inv_involution, iters); | |
gr_test_iter(R, state, "pow_ui: exponent addition", gr_test_pow_ui_exponent_addition, iters); | |
gr_test_iter(R, state, "pow_ui: base scalar multiplication", gr_test_pow_ui_base_scalar_multiplication, iters); | |
if ((R-> flags & GR_COMMUTATIVE_RING) == GR_COMMUTATIVE_RING) | |
gr_test_iter(R, state, "pow_ui: base multiplication", gr_test_pow_ui_base_multiplication, iters); | |
gr_test_iter(R, state, "pow_ui: aliasing", gr_test_pow_ui_exponent_addition, iters); | |
gr_test_iter(R, state, "vec_add", gr_test_vec_add, iters); | |
gr_test_iter(R, state, "mat_mul_classical: associativity", gr_test_mat_mul_classical_associativity, iters); | |
flint_randclear(state); | |
} | |
int main() | |
{ | |
GR_TMP_START; | |
gr_ctx_t Zn; | |
gr_ptr x, y, z; | |
nmod_t nm; | |
ulong t; | |
gr_ctx_init_nmod8(Zn, 107); | |
gr_ctx_t MZn; | |
gr_ctx_init_matrix(MZn, Zn, 30); | |
gr_test_ring(MZn, 10); | |
/* | |
{ | |
flint_rand_t state; | |
flint_randinit(state); | |
gr_ptr a, b, c; | |
GR_TMP_START; | |
GR_TMP_INIT5(x, y, z, a, b, MZn); | |
GR_TMP_INIT1(c, MZn); | |
gr_randtest(x, state, NULL, MZn); | |
gr_randtest(y, state, NULL, MZn); | |
gr_randtest(a, state, NULL, MZn); | |
gr_randtest(b, state, NULL, MZn); | |
gr_add(z, x, y, MZn); | |
gr_mul(z, x, y, MZn); | |
gr_mul(c, a, b, MZn); | |
GR_TMP_CLEAR5(x, y, z, a, b, MZn); | |
GR_TMP_CLEAR1(c, MZn); | |
GR_TMP_END; | |
} | |
*/ | |
gr_ctx_clear_matrix(MZn); | |
gr_ctx_clear_nmod8(Zn); | |
return 0; | |
{ | |
gr_ptr A = flint_malloc(MZn->sizeof_elem); | |
gr_init(A, MZn); | |
gr_println(A, MZn); | |
gr_clear(A, MZn); | |
} | |
return 0; | |
gr_test_ring(Zn, 100000); | |
gr_mat_t A, B, C; | |
gr_mat_init(A, 13, 14, Zn); | |
gr_mat_init(B, 14, 17, Zn); | |
gr_mat_init(C, 13, 17, Zn); | |
flint_rand_t state; | |
flint_randinit(state); | |
gr_mat_randtest(A, state, NULL, Zn); | |
gr_mat_randtest(B, state, NULL, Zn); | |
gr_mat_randtest(C, state, NULL, Zn); | |
gr_mat_print(A, Zn); | |
gr_mat_print(B, Zn); | |
gr_mat_print(C, Zn); | |
TIMEIT_START | |
gr_mat_mul_classical(C, A, B, Zn); | |
TIMEIT_STOP | |
gr_mat_print(C, Zn); | |
printf("\n"); | |
GR_TMP_INIT2(x, y, Zn); | |
gr_set_si(x, 2, Zn); | |
nmod_init(&nm, 253); | |
TIMEIT_START | |
t = nmod_pow_ui(2, 123456, nm); | |
TIMEIT_STOP | |
TIMEIT_START | |
gr_generic_pow_ui(y, x, 123456, Zn); | |
TIMEIT_STOP | |
flint_printf("%wu ", t); | |
gr_println(y, Zn); | |
GR_TMP_CLEAR2(x, y, Zn); | |
gr_ctx_clear_nmod8(Zn); | |
GR_TMP_END; | |
flint_cleanup(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment