Next: , Previous: , Up: Top   [Contents][Index]


6 Zx — The Polynomial Ring Z[x]

CALIB provides the Zx domain, representing the ring Z[x], the univariate polynomials having integer coefficients. The “values” of this domain are represented by the following object:

struct calib_Zx_obj {
	int	degree;		/* Degree of polynomial			 */
	int	size;		/* Size of coeff[] array (degree < size) */
	mpz_ptr	coeff;		/* Coefficients of polynomial.		 */
};

These objects are subject to init() and clear() operations. All such objects must be initialized prior to use by any other CALIB operation. Memory leaks result if they are not cleared when done.

The following additional object is used to represent linked-lists of factors produced by various Zx factorization algorithms:

struct calib_Zx_factor {
	int				multiplicity;
	struct calib_Zx_obj *		factor;
	struct calib_Zx_factor *	next;
};

No data is needed to instantiate the Zx domain. (There is only one such object, and cannot be freed.) Nonetheless, the Zx domain object is the only way to access the operations provided by this domain.

One may access CALIB’s Zx domain as follows:

	#include "calib/Zx.h"
	...
        const struct calib_Zx_dom *	Zx;
	struct calib_Zx_obj		poly1, poly2;
	...
	Zx = calib_get_Zx_dom ();
	...
	Zx -> init (&poly1);
	Zx -> init (&poly2);
	...
	Zx -> mul (&poly1, &poly1, &poly2);
	...
	Zx -> clear (&poly2);
	Zx -> clear (&poly1);

The CALIB Zx domain supports the following settings:


/*
 * Which factorization algorithm to use (for square-free polynomials).
 */

enum calib_Zx_factor_method {
	CALIB_ZX_FACTOR_METHOD_ZASSENHAUS,
	CALIB_ZX_FACTOR_METHOD_VAN_HOEIJ,
};

/*
 * Which method to use for lifting modular factors.
 */

enum calib_Zx_lift_method {
	CALIB_ZX_LIFT_METHOD_LINEAR,
	CALIB_ZX_LIFT_METHOD_QUADRATIC,
};

/*
 * Which method to use for gcd (gcd, a, b).  (The gcd_n() function always
 * uses modular.)
 */

enum calib_Zx_gcd_method {
	CALIB_ZX_GCD_METHOD_MODULAR,
	CALIB_ZX_GCD_METHOD_PRS
};

/*
 * The "settings" object for the Zx domain.
 */

struct calib_Zx_settings {
	/* Factorization method for square-free Zx polynomials. */
	enum calib_Zx_factor_method	factor_method;

	/* Method for lifting modular factors. */
	enum calib_Zx_lift_method	lift_method;

	/* Method to use for two-operand gcd(). */
	enum calib_Zx_gcd_method	gcd_method;

	/* If number of remaining modular factors does not exceed this,	*/
	/* then use exhaustive enumeration instead of Van Hoeij.	*/
	int				VH_max_enumerate;

	/* Enable trace output from Z[x] factorization algorithm.	*/
	/* Zero is none.  Higher values give more output.		*/
	int				factor_trace_level;

	/* Van Hoeij uses resultant-based trace root bound? */
	calib_bool			VH_use_resultant_trace_root_bound;

	/* Validate lifted modular factors? */
	calib_bool			validate_lifted_modular_factors;
};

/*
 * All ssettings for Zx domain are global.
 */

extern struct calib_Zx_settings		calib_Zx_settings;

The struct calib_Zx_dom object contains the following members (pointers to functions) that provide operations of the domain:

Zx::init():

	void	(*init) (struct calib_Zx_obj *		x);

Initialize the given Zx polynomial x, where:

xis the polynomial to initialize.

Zx::init_si():

	void	(*init_si) (struct calib_Zx_obj *	x,
			    calib_si_t			op);

Initialize the given Zx polynomial x to the given constant value op, where:

xis the polynomial to initialize; and
opis the constant value to which the polynomial is set.

Zx::alloc():

	void	(*alloc) (struct calib_Zx_obj *	rop,
			  int			degree);

Force the given (already initialized) polynomial rop to have buffer space sufficient to hold a polynomial of at least the given degree, where:

ropis the polynomial whose allocation is to be adjusted; and
degreeis the guaranteed minimum degree polynomial that rop will be able to hold (without further buffer allocation) upon successful completion of this operation.

Zx::clear():

	void	(*clear) (struct calib_Zx_obj *	x);

Clear out the given polynomial x (freeing all memory it might hold and returning it to the constant value of zero), where:

xis the polynomial to be cleared.

Zx::set():

	void	(*set) (struct calib_Zx_obj *		rop,
			const struct calib_Zx_obj *	op);

Set rop to op in Zx, where:

ropis the polynomial receiving the result;
opis the polynomial to copy.

Zx::set_si():

	void	(*set_si) (struct calib_Zx_obj *	rop,
			   calib_si_t			op);

Set rop to op in Zx, where:

ropis the polynomial receiving the result;
opis the integer value to set.

Zx::set_z():

	void	(*set_z) (struct calib_Zx_obj *		rop,
			  mpz_srcptr			op);

Set rop to op in Zx, where:

ropis the polynomial receiving the result; and
opis the GMP integer value to set.

Zx::set_var_power():

	void	(*set_var_power)
			 (struct calib_Zx_obj *	rop,
			  int			power);

Set rop to x ** power in Zx, where:

ropis the polynomial receiving the result;
poweris the power to set (must be non-negative).

Zx::add():

	void	(*add) (struct calib_Zx_obj *           rop,
			const struct calib_Zx_obj *	op1,
			const struct calib_Zx_obj *	op2);

Set rop to op1 + op2 in Zx, where:

ropis the polynomial receiving the result;
op1is the first operand; and
op2is the second operand.

Zx::sub():

	void	(*sub) (struct calib_Zx_obj *           rop,
			const struct calib_Zx_obj *	op1,
			const struct calib_Zx_obj *	op2);

Set rop to op1 - op2 in Zx, where:

ropis the polynomial receiving the result;
op1is the first operand; and
op2is the second operand.

Zx::neg():

	void	(*neg) (struct calib_Zx_obj *           rop,
			const struct calib_Zx_obj *	op);

Set rop to - op in Zx, where:

ropis the polynomial receiving the result;
opis the operand to negate.

Zx::mul():

	void	(*mul) (struct calib_Zx_obj *           rop,
			const struct calib_Zx_obj *	op1,
			const struct calib_Zx_obj *	op2);

Set rop to op1 * op2 in Zx, where:

ropis the polynomial receiving the result;
op1is the first operand; and
op2is the second operand.

Zx::mul_z():

	void	(*mul_z) (struct calib_Zx_obj *         rop,
			  const struct calib_Zx_obj *	op1,
			  mpz_srcptr			op2);

Set rop to op1 * op2 in Zx, where:

ropis the polynomial receiving the result;
op1is the first (polynomial) operand; and
op2is the second (GMP integer) operand.

Zx::ipow():

	void	(*ipow) (struct calib_Zx_obj *		rop,
			 const struct calib_Zx_obj *	op,
			 int				power);

Set rop to op ** power in Zx, where: where:

ropis the polynomial receiving the result;
opis the polynomial to exponentiate; and
poweris the power to take (must be >= 0).

Zx::dup():

	struct calib_Zx_obj *
		(*dup) (const struct calib_Zx_obj *	op);

Return a dynamically-allocated Zx polynomial that is a copy of op, where:

opis the polynomial to be duplicated.

Zx::free():

	void	(*free) (struct calib_Zx_obj *	poly);

Free the given dynamically-allocated polynomial poly, where:

polyis the polynomial to be freed.

This is equivalent to performing Zx -> clear (poly);, followed by free (poly);.

Zx::eval():

	void	(*eval) (mpz_ptr			rop,
			 const struct calib_Zx_obj *	poly,
			 mpz_srcptr			value);

Evaluate polynomial poly at the given value, storing the result in rop, where:

ropis the GMP integer receiving the result;
polyis the polynomial to be evaluated; and
valueis the value at which to evaluate the polynomial.

Zx::div():

	void	(*div) (struct calib_Zx_obj *		quotient,
			struct calib_Zx_obj *		remainder,
			mpz_ptr				d,
			const struct calib_Zx_obj *	a,
			const struct calib_Zx_obj *	b);

Polynomial pseudo-division in Z[x], where:

quotientreceives the quotient polynomial (may be NULL);
remainderreceives the remainder polynomial (may be NULL);
dreceives the “denominator” value (may be NULL);
ais the dividend polynomial; and
bis the divisor polynomial (must not be zero).

Pseudo-division has the following properties:

Zx::exactly_divides():

	calib_bool
		(*exactly_divides)
			(struct calib_Zx_obj *		quotient,
			 const struct calib_Zx_obj *	a,
			 const struct calib_Zx_obj *	b);

Return 1 if-and-only-if a is exactly divisible by b (setting quotient such that a = b * quotient); returns 0 otherwise (without modifying quotient), where:

quotientreceives the quotient polynomial (may be NULL);
ais the dividend polynomial; and
bis the divisor polynomial (may not be zero).

Zx::div_z_exact():

	void	(*div_z_exact)
			(struct calib_Zx_obj *		rop,
			 const struct calib_Zx_obj *	op1,
			 mpz_srcptr			op2);

Set rop to op1 / op2 in Zx, where:

resultreceives result polynomial;
polyis the dividend polynomial; and
zis the GMP integer by which to divide poly.

It is a fatal error if the division is not exact.

Zx::gcd():

	void	(*gcd) (struct calib_Zx_obj *		gcd,
			const struct calib_Zx_obj *	a,
			const struct calib_Zx_obj *	b);

Compute the greatest common divisor (GCD) of a and b, storing the result in gcd, where:

gcdreceives the resulting GCD polynomial;
ais the first operand polynomial; and
bis the second operand polynomial.

Zx::gcd_n():

	void	(*gcd_n) (struct calib_Zx_obj *		gcd,
			  struct calib_Zx_obj **	cofact,
			  int				npoly,
			  const struct calib_Zx_obj * const *
							poly_ptrs);

Compute the greatest common divisor (GCD) polynomial that simultaneously divides n given polynomials, where:

gcdreceives the resulting GCD polynomial;
cofactis an array of n pointers to polynomials receiving the cofactor corresponding to each given input polynomial (may be NULL);
npolyis the number n of input polynomials provided; and
poly_ptrsis an array of n pointers to input polynomials whose GCD is to be computed.

This can be vastly more efficient that decomposing this into n-1 consecutive calls to the gcd function.

Zx::extgcd():

	void	(*extgcd) (struct calib_Zx_obj *	gcd,
			   struct calib_Zx_obj *	xa,
			   struct calib_Zx_obj *	xb,
			   const struct calib_Zx_obj *	a,
			   const struct calib_Zx_obj *	b);

The extended Euclidean algorithm. Compute polynomials gcd, xa and xb such that gcd = a * xa + b * xb, where:

gcdreceives the resulting GCD polynomial;
xareceives the multiplier polynomial for a;
xbreceives the multiplier polynomial for b;
ais the first operand polynomial; and
bis the second operand polynomial.

The result satisfies the following properties:

  1. degree(xa) < degree(b)
  2. degree(xb) < degree(a)

Zx::prim_part():

	void	(*prim_part)
			(mpz_ptr			content,
			 struct calib_Zx_obj *		ppart,
			 const struct calib_Zx_obj *	op);

Compute the content and primitive part ppart of the given polynomial op, where:

contenta GMP integer receiving the content of op;
ppartreceives primitive part of op; and
opthe polynomial to be decomposed into content and primitive parts.

Zx::resultant():

	void	(*resultant)
			(mpz_ptr			result,
			 const struct calib_Zx_obj *	a,
			 const struct calib_Zx_obj *	b);

Compute the resultant of polynomials a and b (an integer value), storing the result in result, where:

resultis the resultant of given polynomials;
ais the first operand; and
bis the second operand.

Zx::discriminant():

	void	(*discriminant)
			(mpz_ptr			result
			 const struct calib_Zx_obj *	poly);

Compute the discriminant of polynomial poly (an integer value), storing the result in result, where:

resultis the discriminant of the given polynomial;
polyis the polynomial whose discriminant is to be computed.

Zx::derivative():

	void	(*derivative)
			(struct calib_Zx_obj *		rop,
			 const struct calib_Zx_obj *	op);

Set rop to be the derivative of Zx polynomial op, where:

ropis the derivative of the given polynomial; and
opis the polynomial whose derivative is to be computed.

Zx::cvZpx():

	struct calib_Zx_obj *
		(*cvZpx) (const struct calib_Zpx_obj *	op);

Return a dynamically-allocated polynomial in Z[x] that corresponds to the given polynomial op in Zp[x] (the Z coefficients chosen to have smallest absolute value that are equivalent to the corresponding Zp coefficient), where:

opis the Zpx polynomial to convert into signed Zx form.

Zx::factor():

	struct calib_Zx_factor *
		(*factor) (const struct calib_Zx_obj *	poly);

Factor the given polynomial poly into its irreducible factors, returning a linked list of these factors, where:

polyis the Zx polynomial to be factored.

Note: If a suitable implementation of the Lenstra-Lenstra-Lovász (LLL) lattice-basis reduction algorithm is provided, this function uses the Van Hoeij algorithm that runs in polynomial time. (FPLLL is the only currently supported LLL implementation.) Otherwise the Zassenhaus algorithm is used that can require exponential time on certain classes of polynomials.

Zx::factor_square_free():

	struct calib_Zx_factor *
		(*factor_square_free)
			(const struct calib_Zx_obj *	poly);

Given a polynomial poly that must be both primitive and square-free (all factors occur exactly once), factor poly into its irreducible factors, returning a linked-list of these factors, where:

polyis the primitive, square-free Zx polynomial to be factored.

Note: See the above note regarding LLL and Van Hoeij algorithms.

Zx::finish_sqf():

	struct calib_Zx_factor *
		(*finish_sqf)
			(const struct calib_Zx_factor *	sqfactors);

Given a list of primitive, square-free polynomial factors, “finish” the factorization by factoring each such factor into irreducible polynomials, returning a linked-list of these factors, where:

sqfactorsis a linked-list of primitive, square-free Zx polynomial factors for which factorization into irreducibles is desired.

Note: See the above note regarding LLL and Van Hoeij algorithms.

Zx::free_factors():

	void	(*free_factors)
			(struct calib_Zx_factor *	factors);

Free up the given list of Zx factors, where:

factorsis a linked-list factors to be freed.

Zx::zerop():

	calib_bool
		(*zerop) (const struct calib_Zx_obj *	op);

Return 1 if-and-only-if the given Zx polynomial is identically zero and 0 otherwise, where:

opis the Zx polynomial to test for zero.

Zx::onep():

	calib_bool
		(*onep) (const struct calib_Zx_obj *	op);

Return 1 if-and-only-if the given Zx polynomial is identically one and 0 otherwise, where:

opis the Zx polynomial to test for one.

Zx::set_genrep():

	void	(*set_genrep) (struct calib_Zx_obj *		rop,
			       const struct calib_genrep *	op,
			       const char *			var);

Convert the given genrep op into Zx form, interpreting var to be the name of the variable used by the Zx polynomial, storing the result into rop, where:

ropreceives the resulting Zx polynomial;
opis the genrep to convert into Zx polynomial form; and
varis the variable name (appearing within genrep op) that is to be interpreted as the polynomial variable in Zx.

Zx::to_genrep():

	struct calib_genrep *
		(*to_genrep) (const struct calib_Zx_obj *	op,
			      const char *			var);

Return a dynamically-allocated genrep corresponding to the given Zx polynomial op, using var as the name of the polynomial variable within the returned genrep, where:

opis the Zx polynomial to convert into genrep form; and
varis the variable name to use in the genrep for the polynomial variable of Zx.

Zx::factors_to_genrep():

	struct calib_genrep *
		(*factors_to_genrep)
			(const struct calib_Zx_factor *	factors,
			 const char *			var);

Return a dynamically-allocated genrep corresponding to the given list of Zx factors, using var as the name of the polynomial variable within the returned genrep, where:

factorsis the list of Zx polynomial factors to convert into genrep form; and
varis the variable name to use in the genrep for the polynomial variable of Zx.

Zx::print_maxima():

	void	(*print_maxima)
			(const struct calib_Zx_obj *	op);

Print the given Zx polynomial op to stdout using syntax that can be directly read by Maxima, where:

opis the Zx polynomial to be printed.

Next: , Previous: , Up: Top   [Contents][Index]