1 | // $Id: primitiv.lib,v 1.12 2000-12-19 14:41:45 anne Exp $ |
---|
2 | // last change: 12.08.99 |
---|
3 | /////////////////////////////////////////////////////////////////////////////// |
---|
4 | // This library is for Singular 1.2 or newer |
---|
5 | |
---|
6 | version="$Id: primitiv.lib,v 1.12 2000-12-19 14:41:45 anne Exp $"; |
---|
7 | category="Commutative Algebra"; |
---|
8 | info=" |
---|
9 | LIBRARY: primitiv.lib PROCEDURES FOR FINDING A PRIMITIVE ELEMENT |
---|
10 | AUTHOR: Martin Lamm, email: lamm@mathematik.uni-kl.de |
---|
11 | PROCEDURES: |
---|
12 | primitive(ideal i); find minimal polynomial for a primitive element |
---|
13 | primitive_extra(i); find primitive element for two generators |
---|
14 | splitring(f,R[,L]); define ring extension with name R and switch to it |
---|
15 | "; |
---|
16 | |
---|
17 | /////////////////////////////////////////////////////////////////////////////// |
---|
18 | LIB "random.lib"; |
---|
19 | /////////////////////////////////////////////////////////////////////////////// |
---|
20 | |
---|
21 | proc primitive(ideal i) |
---|
22 | "USAGE: primitive(i); i ideal of the following form: |
---|
23 | Let k be the ground field of your basering, a_1,...,a_n algebraic over k, @* |
---|
24 | m_1(x_1), m_2(x_1,x_2),...,m_n(x_1,...,x_n) polynomials in k such that @* |
---|
25 | m_j(a_1,...,a_(j-1),x_j) is minimal polynomial for a_j over k(a_1,...,a_(j-1)) |
---|
26 | for all j=1,...,n. |
---|
27 | Then i has to be generated by m_1,...,m_n. |
---|
28 | |
---|
29 | RETURN: ideal j in k[x_n] such that |
---|
30 | j[1] is minimal polynomial for a primitive element b of k(a_1,...,a_n)=k(b) |
---|
31 | over k |
---|
32 | j[2],...,j[n+1] polynomials in k[x_n] : j[i+1](b)=a_i for i=1,...,n |
---|
33 | NOTE: the number of variables in the basering has to be exactly the number n |
---|
34 | of given algebraic elements (and minimal polynomials). |
---|
35 | |
---|
36 | If k has few elements it can be that no one of the linear combinations |
---|
37 | of a_1,...,a_n is a primitive element. In this case `primitive' |
---|
38 | returns the zero ideal. If this occurs use primitive_extra instead. |
---|
39 | SEE ALSO: primitive_extra |
---|
40 | KEYWORDS: primitive element |
---|
41 | EXAMPLE: example primitive; shows an example |
---|
42 | " |
---|
43 | { |
---|
44 | def altring=basering; |
---|
45 | execute("ring deglexring=("+charstr(altring)+"),("+varstr(altring)+"),dp;"); |
---|
46 | ideal j; |
---|
47 | execute("ring lexring=("+charstr(altring)+"),("+varstr(altring)+"),lp;"); |
---|
48 | ideal i=fetch(altring,i); |
---|
49 | |
---|
50 | int k,schlecht,Fehlversuche,maxtry; |
---|
51 | int nva = nvars(basering); |
---|
52 | int p=char(basering); |
---|
53 | if (p==0) { |
---|
54 | p=100000; |
---|
55 | if (nva<3) { maxtry= 100000000; } |
---|
56 | else { maxtry=2147483647; } |
---|
57 | } |
---|
58 | else { |
---|
59 | if ((nva<4) || (p<60)) { |
---|
60 | maxtry=p^(nva-1); } |
---|
61 | else { |
---|
62 | maxtry=2147483647; // int overflow(^) vermeiden |
---|
63 | } |
---|
64 | } |
---|
65 | ideal jmap,j; |
---|
66 | map phi; |
---|
67 | option(redSB); |
---|
68 | |
---|
69 | //-------- Mache so lange Random-Koord.wechsel, bis letztes Poly ------------- |
---|
70 | //--------------- das Minpoly eines primitiven Elements ist : ---------------- |
---|
71 | for (Fehlversuche=0; Fehlversuche<maxtry; Fehlversuche++) { |
---|
72 | schlecht=0; |
---|
73 | if ((p<60) && (nva==2)) { // systematische Suche statt random |
---|
74 | jmap=ideal(var(1),var(2)+Fehlversuche*var(1)); |
---|
75 | } |
---|
76 | else { |
---|
77 | if (Fehlversuche==0) { jmap=maxideal(1);} |
---|
78 | else { |
---|
79 | if (Fehlversuche<5) { jmap=randomLast(10);} |
---|
80 | else { |
---|
81 | if (Fehlversuche<20) { jmap=randomLast(100);} |
---|
82 | else { jmap=randomLast(100000000);} |
---|
83 | }} // groessere Werte machen keinen Sinn |
---|
84 | } |
---|
85 | phi=lexring,jmap; |
---|
86 | j=phi(i); |
---|
87 | setring deglexring; |
---|
88 | //--------------- Berechne reduzierte Standardbasis mit fglm: ---------------- |
---|
89 | j=std(fetch(lexring,j)); |
---|
90 | setring lexring; |
---|
91 | j=fglm(deglexring,j); |
---|
92 | //-- teste, ob SB n Elemente enthaelt (falls ja, ob lead(Fi)=xi i=1... n-1): - |
---|
93 | if (size(j)==nva) { |
---|
94 | for (k=1; k<nva; k++) { |
---|
95 | j[k+1]=j[k+1]/leadcoef(j[k+1]); // normiere die Erzeuger |
---|
96 | if (lead(j[k+1]) != var(nva-k)) { schlecht=1;} |
---|
97 | } |
---|
98 | if (schlecht==0) { |
---|
99 | //--- Random-Koord.wechsel war gut: Berechne das zurueckzugebende Ideal: ----- |
---|
100 | ideal erg; |
---|
101 | for (k=1; k<nva; k++) { erg[k]=var(k)-j[nva-k+1]; } |
---|
102 | // =g_k(x_n) mit a_k=g_k(a_n) |
---|
103 | erg[nva]=var(nva); |
---|
104 | map chi=lexring,erg; |
---|
105 | ideal extra=maxideal(1);extra=phi(extra); |
---|
106 | // sonst: "argument of a map must have a name" |
---|
107 | erg=j[1],chi(extra); // j[1] = Minimalpolynom |
---|
108 | setring altring; |
---|
109 | return(fetch(lexring,erg)); |
---|
110 | } |
---|
111 | } |
---|
112 | dbprint("The random coordinate change was bad!"); |
---|
113 | } |
---|
114 | if (voice==2) { |
---|
115 | "// ** Warning: No primitive element could be found."; |
---|
116 | "// If the given ideal really describes the minimal polynomials of"; |
---|
117 | "// a series of algebraic elements (cf. `help primitive;') then"; |
---|
118 | "// try `primitive_extra'."; |
---|
119 | } |
---|
120 | setring altring; |
---|
121 | return(ideal(0)); |
---|
122 | } |
---|
123 | example |
---|
124 | { "EXAMPLE:"; echo = 2; |
---|
125 | ring exring=0,(x,y),dp; |
---|
126 | ideal i=x2+1,y2-x; // compute Q(i,i^(1/2))=:L |
---|
127 | ideal j=primitive(i); // -> we have L=Q(a): |
---|
128 | "minimal polynomial of a:",j[1]; // => a=(-1)^(1/4) |
---|
129 | "polynomial for i: ",j[2]; // => i=a^2 |
---|
130 | "polynomial for i^(1/2): ",j[3]; // => i^(1/2)=a |
---|
131 | // ==> the 2nd element was already primitive! |
---|
132 | j=primitive(ideal(x2-2,y2-3)); // compute Q(sqrt(2),sqrt(3)) |
---|
133 | "minimal polynomial:",j[1]; |
---|
134 | "polynomial p s.t. p(a)=sqrt(2):",j[2]; |
---|
135 | "polynomial r s.t. r(a)=sqrt(3):",j[3]; |
---|
136 | // ==> no element was primitive -- the calculation of a is based |
---|
137 | // on a random choice. |
---|
138 | } |
---|
139 | /////////////////////////////////////////////////////////////////////////////// |
---|
140 | |
---|
141 | proc primitive_extra(ideal i) |
---|
142 | "USAGE: primitive_extra(i); ideal i=f,g; with the following properties: @* |
---|
143 | Let k=Q or k=Z/pZ be the ground field of the basering, a,b algebraic over k, |
---|
144 | x the name of the first ring variable, y the name of the second, then: @* |
---|
145 | f is the minimal polynomial of a in k[x], g is a polynomial in k[x,y] s.t. |
---|
146 | g(a,y) is the minimal polynomial of b in k(a)[y] |
---|
147 | |
---|
148 | RETURN: ideal j in k[y] such that |
---|
149 | j[1] is minimal polynomial over k for a primitive element c of k(a,b)=k(c) @* |
---|
150 | j[2] is a polynomial s.t. j[2](c)=a |
---|
151 | |
---|
152 | NOTE: - While `primitive' may fail for finite fields, this proc tries all |
---|
153 | elements of k(a,b) and hence finds by assurance a primitive element. |
---|
154 | In order to do this (try all elements) field extensions like Z/pZ(a) |
---|
155 | are not allowed for the ground field k. |
---|
156 | - primitive_extra assumes that g is monic as polynomial in (k[x])[y] |
---|
157 | EXAMPLE: example primitive_extra; shows an example |
---|
158 | " |
---|
159 | { |
---|
160 | def altring=basering; |
---|
161 | int grad1,grad2=deg(i[1]),deg(jet(i[2],0,intvec(1,0))); |
---|
162 | int countx,countz; |
---|
163 | ring deglexring=char(altring),(x,y,z),dp; |
---|
164 | map transfer=altring,x,z; |
---|
165 | ideal i=transfer(i); |
---|
166 | if (size(i)!=2) { |
---|
167 | "//** Error -- either wrong number of given minimal polynomials"; |
---|
168 | "//** or wrong choice of ring variables (must use the first two)"; |
---|
169 | setring altring; |
---|
170 | return(ideal(0)); |
---|
171 | } |
---|
172 | matrix mat; |
---|
173 | ring lexring=char(altring),(x,y),lp; |
---|
174 | ideal j; |
---|
175 | ring deglex2ring=char(altring),(x,y),dp; |
---|
176 | ideal j; |
---|
177 | setring deglexring; |
---|
178 | ideal j; |
---|
179 | option(redSB); |
---|
180 | poly g=z; |
---|
181 | int found=0; |
---|
182 | |
---|
183 | //---------------- Schleife zum Finden des primitiven Elements --------------- |
---|
184 | //--- Schleife ist so angordnet, dass g in Charakteristik 0 linear bleibt ---- |
---|
185 | while (found==0) { |
---|
186 | j=eliminate(i+ideal(g-y),z); |
---|
187 | setring deglex2ring; |
---|
188 | j=std(imap(deglexring,j)); |
---|
189 | setring lexring; |
---|
190 | j=fglm(deglex2ring,j); |
---|
191 | if (size(j)==2) { |
---|
192 | if (deg(j[1])==grad1*grad2) { |
---|
193 | j[2]=j[2]/leadcoef(j[2]); // Normierung |
---|
194 | if (lead(j[2])==x) { // Alles ok |
---|
195 | found=1; |
---|
196 | } |
---|
197 | } |
---|
198 | } |
---|
199 | setring deglexring; |
---|
200 | if (found==0) { |
---|
201 | //------------------ waehle ein neues Polynom g ------------------------------ |
---|
202 | dbprint("Still searching for primitive element..."); |
---|
203 | countx=0; |
---|
204 | countz=0; |
---|
205 | while (found==0) { |
---|
206 | countx++; |
---|
207 | if (countx>=grad1) { |
---|
208 | countx=0; |
---|
209 | countz++; |
---|
210 | if (countz>=grad2) { |
---|
211 | "//** Error: No primitive element found!! This should NEVER happen!"; |
---|
212 | setring altring; |
---|
213 | return(ideal(0)); |
---|
214 | } |
---|
215 | } |
---|
216 | g = g +x^countx *z^countz; |
---|
217 | mat=coeffs(g,z); |
---|
218 | if (size(mat)>countz) { |
---|
219 | mat=coeffs(mat[countz+1,1],x); |
---|
220 | if (size(mat)>countx) { |
---|
221 | if (mat[countx+1,1] != 0) { |
---|
222 | found=1; // d.h. hier: neues g gefunden |
---|
223 | }}} |
---|
224 | } |
---|
225 | found=0; |
---|
226 | } |
---|
227 | } |
---|
228 | //------------------- primitives Element gefunden; Rueckgabe ----------------- |
---|
229 | setring lexring; |
---|
230 | j[2]=x-j[2]; |
---|
231 | setring altring; |
---|
232 | map transfer=lexring,var(1),var(2); |
---|
233 | return(transfer(j)); |
---|
234 | } |
---|
235 | example |
---|
236 | { "EXAMPLE:"; echo = 2; |
---|
237 | ring exring=3,(x,y),dp; |
---|
238 | ideal i=x2+1,y3+y2-1; |
---|
239 | primitive_extra(i); |
---|
240 | ring extension=(3,y),x,dp; |
---|
241 | minpoly=y6-y5+y4-y3-y-1; |
---|
242 | number a=y5+y4+y2+y+1; |
---|
243 | a^2; |
---|
244 | factorize(x2+1); |
---|
245 | factorize(x3+x2-1); |
---|
246 | } |
---|
247 | /////////////////////////////////////////////////////////////////////////////// |
---|
248 | |
---|
249 | proc splitring |
---|
250 | "USAGE: splitring(f,R[,L]); f poly, univariate and irreducible(!) over the |
---|
251 | active basering; R string, L list of polys and/or ideals (optional) |
---|
252 | CREATE: a ring with name R, in which f is reducible, and change to it. |
---|
253 | If the old ring has no parameter, the name 'a' is chosen for the |
---|
254 | parameter of R (if a is no variable; if it is, the proc takes 'b', |
---|
255 | etc.; if a,b,c,o are variables of the ring, produce an error message), |
---|
256 | otherwise the name of the parameter is kept and only the |
---|
257 | minimal polynomial is changed. |
---|
258 | The names of variables and orderings are not affected. |
---|
259 | |
---|
260 | It is also allowed to call splitring with R==\"\". Then the old basering |
---|
261 | will be REPLACED by the new ring (with the same name as the old ring). |
---|
262 | |
---|
263 | RETURN: list L mapped into the new ring R, if L is given; else nothing |
---|
264 | ASSUME: The active ring must allow an algebraic extension |
---|
265 | (e.g. it cannot be a transcendent ring extension of Q or Z/p). |
---|
266 | KEYWORDS: algebraic field extension; extension of rings |
---|
267 | EXAMPLE: example splitring; shows an example |
---|
268 | " |
---|
269 | { |
---|
270 | //----------------- split ist bereits eine proc in 'inout.lib' ! ------------- |
---|
271 | poly f=#[1]; string @R=#[2]; |
---|
272 | if (size(#)>2) { |
---|
273 | list L=#[3]; |
---|
274 | int L_groesse=size(L); |
---|
275 | } |
---|
276 | else { int L_groesse=-1; } |
---|
277 | //-------------- ermittle das Minimalpolynom des aktuellen Rings: ------------ |
---|
278 | string minp=string(minpoly); |
---|
279 | |
---|
280 | if (@R=="") { |
---|
281 | string altrname=nameof(basering); |
---|
282 | @R="splt_temp"; |
---|
283 | } |
---|
284 | |
---|
285 | def altring=basering; |
---|
286 | string charakt=string(char(altring)); |
---|
287 | string varnames=varstr(altring); |
---|
288 | string algname; |
---|
289 | int i; |
---|
290 | int anzvar=size(maxideal(1)); |
---|
291 | //--------------- Fall 1: Bisheriger Ring hatte kein Minimalpolynom ---------- |
---|
292 | if (minp=="0") { |
---|
293 | if (find(varnames,"a")==0) { algname="a";} |
---|
294 | else { if (find(varnames,"b")==0) { algname="b";} |
---|
295 | else { if (find(varnames,"c")==0) |
---|
296 | { algname="c";} |
---|
297 | else { if (find(varnames,"o")==0) |
---|
298 | { algname="o";} |
---|
299 | else { |
---|
300 | "** Sorry -- could not find a free name for the primitive element."; |
---|
301 | "** Try e.g. a ring without 'a' or 'b' as variable."; |
---|
302 | return(); |
---|
303 | }} |
---|
304 | } |
---|
305 | } |
---|
306 | //-- erzeuge einen String, der das Minimalpolynom des neuen Rings enthaelt: -- |
---|
307 | execute("ring splt1="+charakt+","+algname+",dp;"); |
---|
308 | ideal abbnach=var(1); |
---|
309 | for (i=1; i<anzvar; i++) { abbnach=abbnach,var(1); } |
---|
310 | map nach_splt1=altring,abbnach; |
---|
311 | execute("poly mipol="+string(nach_splt1(f))+";"); |
---|
312 | string Rminp=string(mipol); |
---|
313 | //--------------------- definiere den neuen Ring: ---------------------------- |
---|
314 | execute("ring "+@R+" = ("+charakt+","+algname+"),("+varnames+"),(" |
---|
315 | +ordstr(altring)+");"); |
---|
316 | execute("minpoly="+Rminp+";"); |
---|
317 | execute("export "+@R+";"); |
---|
318 | def neuring=basering; |
---|
319 | //---------------------- Berechne die zurueckzugebende Liste: ---------------- |
---|
320 | list erg; |
---|
321 | if (L_groesse>0) { |
---|
322 | // L ist ja nicht in 'neuring' def., daher merke man sich die Groesse als int |
---|
323 | map take=altring,maxideal(1); |
---|
324 | erg=take(L); |
---|
325 | } // take(empty list) gibt nicht empty list, sondern Fehlermeldung |
---|
326 | } |
---|
327 | else { |
---|
328 | //------------- Fall 2: Bisheriger Ring hatte ein Minimalpolynom: ------------ |
---|
329 | algname=parstr(altring); // Name des algebraischen Elements |
---|
330 | if (size(algname)>1) {"only one Parameter is allowed!!"; return();} |
---|
331 | //---------------- Minimalpolynom in ein Polynom umwandeln: ------------------ |
---|
332 | execute("ring splt2="+charakt+","+algname+",dp;"); |
---|
333 | execute("poly mipol="+minp+";"); |
---|
334 | // f ist Polynom in algname und einer weiteren Variablen --> mache f bivariat: |
---|
335 | execute("ring splt3="+charakt+",("+algname+","+varnames+"),dp;"); |
---|
336 | poly f=imap(altring,f); |
---|
337 | //-------------- Vorbereitung des Aufrufes von primitive: -------------------- |
---|
338 | execute("ring splt1="+charakt+",(x,y),dp;"); |
---|
339 | ideal abbnach=x; |
---|
340 | for (i=1; i<=anzvar; i++) { abbnach=abbnach,y; } |
---|
341 | map nach_splt1_3=splt3,abbnach; |
---|
342 | map nach_splt1_2=splt2,x; |
---|
343 | ideal maxid=nach_splt1_2(mipol),nach_splt1_3(f); |
---|
344 | ideal primit=primitive(maxid); |
---|
345 | if (size(primit)==0) { // Suche mit 1. Proc erfolglos |
---|
346 | primit=primitive_extra(maxid); |
---|
347 | } |
---|
348 | //-- erzeuge einen String, der das Minimalpolynom des neuen Rings enthaelt: -- |
---|
349 | setring splt2; |
---|
350 | map nach_splt2=splt1,0,var(1); // x->0, y->a |
---|
351 | minp=string(nach_splt2(primit)[1]); |
---|
352 | if (printlevel > -1) { "// new minimal polynomial:",minp; } |
---|
353 | //--------------------- definiere den neuen Ring: ---------------------------- |
---|
354 | execute("ring "+@R+" = ("+charakt+","+algname+"),("+varnames+"),(" |
---|
355 | +ordstr(altring)+");"); |
---|
356 | execute("minpoly="+minp+";"); |
---|
357 | execute("export "+@R+";"); |
---|
358 | def neuring=basering; |
---|
359 | |
---|
360 | //--------------- Uebersicht: wenn altring=(p,a),(x,y),dp; dann: ------------- |
---|
361 | //------------ splt1=p,(x,y),dp; splt2=p,a,dp; splt3=p,(a,x,y),dp; --------- |
---|
362 | |
---|
363 | list erg; |
---|
364 | if (L_groesse>0) { |
---|
365 | //---------------------- Berechne die zurueckzugebende Liste: ---------------- |
---|
366 | setring splt3; |
---|
367 | list zwi=imap(altring,L); |
---|
368 | map nach_splt3_1=splt1,0,var(1); // x->0, y->a |
---|
369 | //----- rechne das primitive Element von altring in das von neuring um: ------ |
---|
370 | ideal convid=maxideal(1); |
---|
371 | convid[1]=nach_splt3_1(primit)[2]; |
---|
372 | map convert=splt3,convid; |
---|
373 | zwi=convert(zwi); |
---|
374 | setring neuring; |
---|
375 | erg=imap(splt3,zwi); |
---|
376 | } |
---|
377 | } |
---|
378 | if (defined(altrname)) { |
---|
379 | if(system("with","Namespaces")) |
---|
380 | { kill Top::`altrname`; kill Top::splt_temp; } |
---|
381 | execute("kill "+altrname+";"); |
---|
382 | execute("def "+altrname+" = splt_temp;"); |
---|
383 | @R=altrname; |
---|
384 | execute("export "+altrname+";"); |
---|
385 | kill splt_temp; |
---|
386 | } |
---|
387 | |
---|
388 | execute("keepring "+@R+";"); |
---|
389 | if (L_groesse >= 0) { return(erg); } |
---|
390 | } |
---|
391 | example |
---|
392 | { "EXAMPLE:"; echo = 2; |
---|
393 | ring r=0,(x,y),dp; |
---|
394 | splitring(x2-2,"r1"); // change to Q(sqrt(2)) |
---|
395 | splitring(x2-a,"r2",a); // change to Q(sqrt(2),sqrt(sqrt(2)))=Q(a) |
---|
396 | // and return the transformed old parameter |
---|
397 | // the result is (a2) == (sqrt(sqrt(2)))^2 |
---|
398 | nameof(basering); |
---|
399 | r2; |
---|
400 | kill r1; kill r2; |
---|
401 | } |
---|