//
// LiDIA - a library for computational number theory
//   Copyright (c) 1994, 1995 by the LiDIA Group
//
// File        : fac_vec.c
// Author      : Victor Shoup, Thomas Pfahler (TPf)
// Last change : TPf, Feb 29, 1996, initial version
//             

#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:Fp_polynomial.h>
#include <LiDIA:Fp_polynomial_util.h>
#include <LiDIA:udigit.h>
#else
#include <LiDIA/Fp_polynomial_fft.h>
#include <LiDIA/Fp_polynomial_util.h>
#include <LiDIA/udigit.h>
#endif


void swap(int_factor& i1, int_factor& i2)
{
    debug_handler( "int_factor", "swap ( int_factor&, int_factor& )" );
	
    lidia_size_t t_lidia_size_t;
    int t_int;
    double t_double;

    t_lidia_size_t = i1.q;
    i1.q = i2.q;
    i2.q = t_lidia_size_t;

    t_int = i1.a;
    i1.a = i2.a;
    i2.a = t_int;

    t_int = i1.b;
    i1.b = i2.b;
    i2.b = t_int;

    t_double = i1.len;
    i1.len = i2.len;
    i2.len = t_double;
}


fac_vec::fac_vec(lidia_size_t n) :
    fvec(0),
    num_factors(0)
{
    debug_handler( "fac_vec", "fac_vec( lidia_size_t )" );
    
    compute_factorization(n);
}


void fac_vec::compute_factorization(lidia_size_t n)
{
	debug_handler( "fac_vec", "compute_factorization ( lidia_size_t )" );
	lidia_size_t q;

	delete[] fvec; 
	lidia_size_t m = next_power_of_two(n);
	fvec = new int_factor[m];
	if (!fvec)
		lidia_error_handler( "fac_vec", "compute_factorization ( lidia_size_t )::out of memory" );

	num_factors = 0;
	q = 2;

	/*   computing factorization of n   */
	while (n != 1)
	{
		if (n%q == 0)
		{
			fvec[num_factors].q = q;
			n = n/q;
			fvec[num_factors].a = 1;
			while (n%q == 0)
			{
				n = n/q;
				(fvec[num_factors].a)++;
			}

			num_factors++;
		}

		q++;
	}

	/*   setting 'len'   */
	lidia_size_t i;
	for (i = 0; i < num_factors; i++)
	    fvec[i].len = fvec[i].a * log((double) fvec[i].q);
	    
        sort();
}


void fac_vec::sort()
{
	debug_handler( "fac_vec", "sort ( void )" );
	int i, j;

	for (i = 1; i <= num_factors - 1; i++)
		for (j = 0; j <= num_factors - i - 1; j++)
			if (fvec[j].len > fvec[j+1].len)
				swap(fvec[j], fvec[j+1]);
}


void fac_vec::clear(int lo, int hi)
{
	debug_handler( "fac_vec", "assign_zero_to_b( int, int )" );
	for (int i = lo; i <= hi; i++)
		fvec[i].b = 0;
}


lidia_size_t fac_vec::prod(int lo, int hi) const
{
	debug_handler( "fac_vec", "prod( int, int )" );

	lidia_size_t i, res;

	res = 1;
	for (i = lo; i <= hi; i++)
		res = res * udigit_power(fvec[i].q, fvec[i].a);

	return res;
}


