
/* gcdex(f,g) yields a list [a,b,u] where
  u is the GCD of f and g, and 
  u = f*a+g*b;

    F and G should be univariate polynomials, or a main variable
should be supplied so that we are working in the polynomial ring over
the rational functions in the other variables, and thus in a
principal ideal domain, and the ideal generated by (f,g) is indeed
generated by the gcd of f and g.

  mytest(f,g,[var]):=block([ans:gcdex(f,g,var[1]),v],
                 if (var = [])  then var:listofvars([f,g]),
		 v:var[1],    
		 [ratsimp(ans.[f,g,-1]),
		  remainder(f,ans[3],v),
		  remainder(g,ans[3],v)]);  
    
*/      
gcdex(f,g,[var]):=block([q0,q1,ok:true,lis1,lis2,lis3,q,tem,result],
  if integerp(f) and integerp(g) then return( igcdex(f, g) ),
  if (var = [])  then var:listofvars([f,g]),
  if not (length(var) = 1) 
  then (if (f=0 and g=0) then return([0,0,0]),
    error("Specify one main variable or give univariate polynomials")
    ),
  var:var[1],
  f:rat(f),g:rat(g),		    
  q0:divide(f,g,var),   /* divide(f,g) ==> [q:quotient(f,g),remainder:f-g*q] */
  /* if f/g is 0 then we reverse them */
  if (q0[1]=0) then
  /* the deg f < deg g */
  (lis2:gcdex(g,f,var),return([lis2[2],lis2[1],lis2[3]])),
  if (q0[2]=0) then lis2:[0,1,g]
  else (
    q1:divide(g,q0[2],var), 	
    lis1:[1,-q0[1],q0[2]],			
    if (q1[2]=0) then lis2:lis1
    else (
      /* lisi are always perpendicular to [f,g,-1] */
      lis2:[-q1[1],1+q0[1]*q1[1], q1[2]],
      while(ok) do 
      ( q:divide(lis1[3],lis2[3],var),
        lis3:lis1-lis2*q[1],
        if(lis3[3] = 0) then ok:false
        else (lis1:lis2, 
          lis2:lis3/content(lis3[3],var)[1])
        ))),
  if freeof(var,lis2[3]) then lis2/lis2[3] else lis2);

igcdex(a,b) := block(
  [x:0, lx:1, y:1, ly:0, q, r],
  while b#0 do (
    [q,r]:divide(a,b),
    [a,b]:[b,r],
    [x,lx]:[lx-q*x,x],
    [y,ly]:[ly-q*y,y]),
  [lx,ly,a])$
