%mathpiper,def="GaussianFactors"

//Retract("GaussianFactors",*);


/* AddGaussianFactor: auxiliary function for Gaussian Factors.
L is a lists of factors of the Gaussian integer z and p is a Gaussian prime
that we want to add to the list. We first find the exponent e of p in the
decomposition of z (into Gaussian primes). If it is not zero, we add {p,e}
to the list */

AddGaussianFactor(L_IsList,z_IsGaussianInteger,p_IsGaussianInteger) <--
[
 Local(e);
 e :=0;
 While (IsGaussianInteger(z:= z/p)) e++;
 If (e != 0, DestructiveAppend(L,{p,e}));
];




/* 
GaussianFactors(n) : returns a list of factors of n, in a similar way to Factors(n).
If n is a rational integer, we factor n in the Gaussian integers, by first
factoring it in the rational integers, and after that factoring each of
its integer prime factors. 
*/

10 # GaussianFactors(n_IsInteger) <--
[
  // Chosing to factor this integer as a Gaussian Integer
  Local(ifactors,gfactors,p,alpha);
  ifactors := FactorizeInt(n);  // since we know it is an integer
  gfactors := {};
  ForEach(p,ifactors)
  [
     If (p[1]=2, [ DestructiveAppend(gfactors,{1+I,p[2]});
                   DestructiveAppend(gfactors,{1-I,p[2]}); ]);
     If (Modulo(p[1],4)=3, DestructiveAppend(gfactors,p));
     If (Modulo(p[1],4)=1, [ alpha := GaussianFactorPrime(p[1]);
                          DestructiveAppend(gfactors,{alpha,p[2]});
                          DestructiveAppend(gfactors,{Conjugate(alpha),p[2]});
                        ]);
  ];
gfactors;
];

/* 
If z is is a Gaussian integer, we find its possible Gassian prime factors,
by factoring its norm 
*/

20 # GaussianFactors(z_IsGaussianInteger) <--
[
 Local(n,nfactors,gfactors,p);
  gfactors :={};
  n := GaussianNorm(z);
  nfactors := Factors(n);
  ForEach(p,nfactors)
  [
   If (p[1]=2, [ AddGaussianFactor(gfactors,z,1+I);]);
   If (Modulo(p[1],4)=3, AddGaussianFactor(gfactors,z,p[1]));
   If (Modulo(p[1],4)=1, [ Local(alpha);
                        alpha := GaussianFactorPrime(p[1]);
                        AddGaussianFactor(gfactors,z,alpha);
                        AddGaussianFactor(gfactors,z,Conjugate(alpha));
                      ]);
 ];
 gfactors;
];

%/mathpiper

    %output,preserve="false"
      Result: True
.   %/output



%mathpiper_docs,name="GaussianFactors",categories="User Functions;Number Theory"
*CMD GaussianFactors --- factorization in Gaussian integers
*STD
*CALL
	GaussianFactors(z)

*PARMS

{z} -- Gaussian integer

*DESC

This function decomposes a Gaussian integer number {z} into a product of
Gaussian prime factors.
A Gaussian integer is a complex number with integer real and imaginary parts.
A Gaussian integer $z$ can be decomposed into Gaussian primes essentially in a
unique way (up to Gaussian units and associated prime factors), i.e. one
can write $z$ as
$$z = u*p[1]^n[1] * ... * p[s]^n[s]$$,
where $u$ is a Gaussian unit and $p[1]$, $p[2]$, ..., $p[s]$ are Gaussian primes. 

The factorization is returned as a list of pairs. The first member of
each pair is the factor (a Gaussian integer) and the second member denotes the power to
which this factor should be raised. So the factorization is returned as 
a list, e.g. {{{p1,n1}, {p2,n2}, ...}}.

*E.G.
In> GaussianFactors(5)
Result: {{Complex(2,1),1},{Complex(2,-1),1}};
In> GaussianFactors(3+I)
Result: {{Complex(1,1),1},{Complex(2,-1),1}};

*SEE Factors, IsGaussianPrime, IsGaussianUnit
%/mathpiper_docs