#Implementation of some algorithms by that new guy, C F Gauss. #His 'reduction' amounts to finding a matrix C with C Q C^t being the #symmetric matrix representing his 'reduced' quadratic form. #All our reduction procedures will return the corresponding C rather #than simply the reduced matrix C Q C^t, which is then easily found anyway. #So general procedure is: given Q, find C1, make Q1, induct C0, return C0 C1. #He then applies this to solving Legendre's equation: he calculates a change #of basis in this way so that the quadratic form ax^2+by^2+cz^2 become just #(-abc)(X^2+YZ), two solutions of which are clearly [X,Y,Z]=[0,1,0] and [0,0,1] #which are then translated back to xyz-coordinates. #How good is this solution? Ingenious, absolutely, but terrible in practice. #Two impediments: #1. 3D-lattice reduction requires reducing 2D lattices with _indefinite_ forms. # Gauss's algorithm is NOT polynomial-time; I see no way around that, either. #2. An initial call to "Lemma279" greatly increases the magnitude of the # numbers involved. Probably this part can be fixed without much ingenuity. #Warning: his matrices "S" seem to be my C^t, not C. And I may not have his #definition of 'reduced' quite matched. If I were really to #use this stuff, I would return [C,CQC^t] instead of just C. Also I'd #switch to matrix input rather than list input. I think. ############################################################################## with(linalg): I2:=matrix(2,2,[1,0,0,1]): I3:=matrix(3,3,[1,0,0,0,1,0,0,0,1]): J2:=matrix(2,2,[0,1,1,0]): #Maple's isolve() does not return the same answer all the time, # thus affecting predictability of answers! So instead I use # euc2:=proc(a,b) local k,x: if abs(a)0 and b0 then ans:=minn(a,b,c): else ans:=minz(a,b,c) fi: RETURN(ans): end: #A checker: # checkbin:=proc(C,Q) print(multiply(multiply(C,matrix(2,2,[Q[1],Q[2],Q[2],Q[3]])),transpose(C)));end: #should show nice,small symmetric matrix # #Or just see the reduced form: red:=proc(a,b,c) checkbin(binmin(a,b,c),[a,b,c]): end: ################################ #We follow Gauss' discussion of ternary quadratic forms, Art 266 et seq. #He represents the quadratic form given by a symmetric matrix Q by #the sextuple [Q11,Q22,Q33,Q23,Q13,Q12]. Note his 'determinant' is -det(Q). #art 267: adjo:=proc(a,a1,a2,b,b1,b2) [b^2-a1*a2,b1^2-a*a2,b2^2-a*a1,a*b-b1*b2,a1*b1-b*b2,a2*b2-b*b1] end: #The adjoint matrix of Q is again symmetric #Now we consider reductions of ternary forms # #art 272: He proposes to alternate the reduction of binary quadratic forms #on the subspaces span(e1,e2) and span(e2,e3). min1:=proc(a,b,c,d,e,f) local ans,a1,b1,c1,d1,e1,f1,M1,M2,Q,Q2: lprint(`1:`,a,b,c,d,e,f,a*b*c+2*d*e*f-a*d^2-b*e^2-c*f^2); ans:=binmin(a,f,b): if ans=I2 then RETURN(I3) fi: M1:=matrix(3,3,[ans[1,1],ans[1,2],0,ans[2,1],ans[2,2],0,0,0,1]): Q:=matrix(3,3,[a,f,e,f,b,d,e,d,c]): Q2:=multiply(multiply(M1,Q),transpose(M1)): a1:=Q2[1,1]:b1:=Q2[2,2]:c1:=Q2[3,3]:d1:=Q2[2,3]:e1:=Q2[3,1]:f1:=Q2[1,2]: if [a,b,c,d,e,f]=[a1,b1,c1,d1,e1,f1] then RETURN(I3) fi: M2:=min2(a1,b1,c1,d1,e1,f1): RETURN(multiply(M2,M1)): end: min2:=proc(a,b,c,d,e,f) local ans,a1,b1,c1,d1,e1,f1,M1,M2,Q,Q2,d0: lprint(`2:`,a,b,c,d,e,f,a*b*c+2*d*e*f-a*d^2-b*e^2-c*f^2); ans:=binmin(f^2-a*b,a*d-e*f,e^2-a*c): if ans=I2 then RETURN(I3) fi: d0:=ans[1,1]*ans[2,2]-ans[1,2]*ans[2,1]:#=+-1 M1:=matrix(3,3,[d0,0,0,0,ans[1,1],-ans[1,2],0,-ans[2,1],ans[2,2]]):#inverse transf. Q:=matrix(3,3,[a,f,e,f,b,d,e,d,c]): Q2:=multiply(multiply(M1,Q),transpose(M1)): a1:=Q2[1,1]:b1:=Q2[2,2]:c1:=Q2[3,3]:d1:=Q2[2,3]:e1:=Q2[3,1]:f1:=Q2[1,2]: M2:=matrix(3,3,min1(a1,b1,c1,d1,e1,f1)): RETURN(multiply(M2,M1)): end: #Further reductions from Art 274. # minx:=proc(a,b,c,d,e,f) local r,s,t,A,k,n,m,N: lprint(`3:`,a,b,c,d,e,f): A:=adjo(a,b,c,d,e,f): if a*A[3]=0 and a+A[3]<>0 then print(`See Art. 274: have a A2=0 but not both zero`): RETURN([0,0,0]): fi: if a=0 and A[3]=0 then k:=gcd(b,e):n:=d mod k: if n>k/2 then n:=n-k: fi: euc2(b,e):t:="[1]:r:=""[2]:t:=t*(n-d)/k:r:=r*(n-d)/k: m:=(c+2*d*t+a*t^2) mod 2*e: if m>abs(e) then m:=m-2*abs(e) fi: s:=(m-(c+2*d*t+a*t^2))/2/e: else r:=round(-f/a): t:=round(A[4]/A[3]):N:=A[4]-A[3]*t: s:=round((A[5]-N*r)/A[3]): fi: RETURN([r,s,t]): end: #We polish off unimodular forms with Art. 277 # minu:=proc(a,b,c,d,e,f) local dd: if d=0 and e=0 and f=0 then #form is diagonal; switch to +-(x^2+2yz) if indef. if a=b and b=c then RETURN(I3) fi: #that's for definite unimodular forms. dd:=-a*b*c: if a=b then RETURN(matrix(3,3,[1,1,1,dd,0,dd,0,-1,-1])); elif b=c then RETURN(matrix(3,3,[1,1,1,dd,0,dd,-1,-1,0])) else RETURN(matrix(3,3,[1,1,1,dd,dd,0,0,-1,-1])):fi: fi: #Next are the cases of column-permutations of Gauss's "(+-1, 0, 0; +-1, 0, 0)" if [b,c,e,f]=[0,0,0,0] then RETURN(matrix(3,3,[1,0,0,0,1,0,0,0,d])) fi: if [a,c,d,f]=[0,0,0,0] then RETURN(matrix(3,3,[0,1,0,0,0,1,e,0,0])) fi: if [a,b,d,e]=[0,0,0,0] then RETURN(matrix(3,3,[0,0,1,1,0,0,0,f,0])) fi: #Now the "(0,+-1,+-1; 0,+-1,0)" 's if [a,d,f]=[0,0,0] then RETURN(matrix(3,3,[-c*e,1,0,-e*(c+b)/2,b*c,1,e,0,0])):fi: if [b,d,e]=[0,0,0] then RETURN(matrix(3,3,[0,-a*f,1,1,-f*(a+c)/2,c*a,0,f,0])):fi: if [c,e,f]=[0,0,0] then RETURN(matrix(3,3,[1,0,-b*d,a*b,1,-d*(b+a)/2,0,0,d])):fi: lprint(a,b,c,d,e,f,`unimodular reduction failure!`): end: #So we just call this: # ternmin:=proc(a,b,c,d,e,f) local M1,M2,M3,Q,Q2,Q3,a1,b1,c1,d1,e1,f1: M1:=min1(a,b,c,d,e,f): if M1=I3 then M1:=min2(a,b,c,d,e,f): fi: Q:=matrix(3,3,[a,f,e,f,b,d,e,d,c]): Q2:=multiply(multiply(M1,Q),transpose(M1)): a1:=Q2[1,1]:b1:=Q2[2,2]:c1:=Q2[3,3]:d1:=Q2[2,3]:e1:=Q2[3,1]:f1:=Q2[1,2]: minx(a1,b1,c1,d1,e1,f1): M2:=matrix(3,3,[1,0,0,"[1],1,0,"[2],"[3],1]): if abs(a*b*c+2*d*e*f-a*d^2-b*e^2-c*f^2)=1 then Q3:=multiply(multiply(M2,Q2),transpose(M2)): a1:=Q3[1,1]:b1:=Q3[2,2]:c1:=Q3[3,3]:d1:=Q3[2,3]:e1:=Q3[3,1]:f1:=Q3[1,2]: M3:=minu(a1,b1,c1,d1,e1,f1): RETURN(multiply(M3,multiply(M2,M1))): else RETURN(multiply(M2,M1)): fi: end: #A double-check: # #with(linalg): checktern:=proc(CC,Q) local AA,BB: BB:=matrix(3,3,[Q[1],Q[6],Q[5],Q[6],Q[2],Q[4],Q[5],Q[4],Q[3]]): print(det(CC)); #get 1 (or -1?) AA:=multiply(multiply(CC,BB),transpose(CC)); print(AA): #get simple symmetric matrix [AA[1,1],AA[2,2],AA[3,3],AA[2,3],AA[3,1],AA[1,2]]: end: #usage: checktern(",Q); right after a ternmin(). ################################ #Now we solve Legendre's equation #First some prep: (Art. 279) euc3:=proc(a,b,c) local k,x: if abs(a)