# Input: a,b,c in Q(t1,t2,..,tk). # # Output: nonzero [x,y,z] for which a*x^2+b*y^2+c*z^2 = 0 if # such x,y,z exist in Q(t1,t2,..,tk) and FAIL otherwise. # # Author: Mark van Hoeij, Oct 2004. # Conic := proc(a,b,c) local v,d,i,t,l,s,d2,co,ansatz,c1,j,k,eq; # Some preprocessing: # v := [a,b,c]; if a=0 then [1,0,0] elif b=0 then [0,1,0] elif c=0 then [0,0,1] elif not type(v, list(ratpoly(rational))) then FAIL # Only Q(t1..tk) is implemented. elif args[-1]<>0 then d, v := ReduceConic(ReduceList(v)); v := procname(op(v),0); if v = FAIL then return v fi; ReduceList([seq(v[i]/d[i], i=1..3)]) elif indets(v)={} then # Solve a conic over Q (requires factoring integers) `algcurves/pyth_LLL`(op(v)) else t := SelectVar(v); d := map(degree,v,t); l := map(lcoeff,v,t); s := d[1]+d[2]+d[3]; d := [seq(s-d[i], i=1..3)]; d2 := d mod 2; # The degrees for the ansatz: d := [seq(ceil(i/2)-max(op(d2)), i=d)]; ansatz := [seq(add(co[i,j]*t^j, j=0..d[i]), i=1..3)]; eq := {}; # If the degrees are congruent mod 2, then we need some equations # coming from a conic with fewer variables: if d2 = [0,0,0] then s := procname(op(l)); if s = FAIL then return s fi; # Equate leading coefficients of ansatz to entries of s. # Here c1 is a new variable to make the system homogeneous. eq := {seq(co[i,d[i]] - s[i]*c1, i=1..3)} fi; # Compute equations for each factor of a*b*c. for k to 3 do i,j := op({1,2,3} minus {k}); for l in factors(primpart(v[k],t))[2] do s := msqrt(v[i],v[j],l[1],t); if s = FAIL then return s fi; s := ansatz[i]*s[1]+ansatz[j]*s[2]; eq := {op(eq),coeffs(collect(rem(s,l[1],t),t),t)} od od; # Solve linear equations, substitute the solution into ansatz. s := SolveTools:-Linear(eq, indets(eq) minus indets(v)); eval(ansatz, s); fi end: # Compute the square root of -a/b modulo p(t) and return # a list with the numerator and denominator of this sqrt. # msqrt := proc(a,b,p,t) local x,R,v; if degree(b,t) > degree(a,t) then v := procname(b,a,p,t); return `if`(v=FAIL,v,[v[2],v[1]]) fi; R := RootOf(p,t); v := subs(t = R, primpart(b*x^2+a,x)); if degree(p,t)=1 then v := factors(v) else # If the number of vars is > 1 then the modular gcd code # for function fields will really help speed things up here v := subs(R=t, evala(Factors(v, {R}))) fi; v := select(has,v[2],x)[1][1]; if degree(v,x)=2 then # Square root is non-rational: return FAIL fi; [coeff(v,x,0), coeff(v,x,1)] end: # Clear denominators and remove common factors of a list. # ReduceList := proc(v) local t,i,f; f := primpart(add(v[i]*t^i,i=1..nops(v)),t); [seq(coeff(f,t,i),i=1..nops(v))] end: # Select a good variable appearing in v. # SelectVar := proc(v) local vars,i,m,mn,mv; vars := indets(v); if vars = {} then error fi; for i in vars do m := max(op(map(degree,v,i))); if not assigned(mn) or m1 then w[i] := normal(w[i]/g); w[j] := normal(w[j]/g); w[k] := w[k]*g; t[k] := t[k]/g fi od; [t[1],t[2],t[3]], [w[1],w[2],w[3]] end: