One Hat Cyber Team
Your IP :
216.73.216.14
Server IP :
194.44.31.54
Server :
Linux zen.imath.kiev.ua 4.18.0-553.77.1.el8_10.x86_64 #1 SMP Fri Oct 3 14:30:23 UTC 2025 x86_64
Server Software :
Apache/2.4.37 (Rocky Linux) OpenSSL/1.1.1k
PHP Version :
5.6.40
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
Macaulay2
/
View File Name :
CoincidentRootLoci.m2
if version#"VERSION" < "1.15" then error "this package requires Macaulay2 version 1.15 or newer"; newPackage( "CoincidentRootLoci", Version => "0.1.3", Date => "January 30, 2021", Headline => "coincident root loci", Authors => {{Name => "Giovanni Staglianò", Email => "giovannistagliano@gmail.com"}}, Keywords => {"Real Algebraic Geometry", "Interfaces"}, PackageExports => {"Cremona","Resultants"}, DebuggingMode => false, AuxiliaryFiles => true, OptionalComponentsPresent => try get "!qepcad -h 2>&1" then true else false, CacheExampleOutput => false, Reload => false ) export{"apolar", "recover", "CoincidentRootLocus", "coincidentRootLocus", "CRL", "supsets", "realRankBoundary", "complexrank", "realrank", "realroots", "QepcadOptions", "randomBinaryForm", "randomInCoisotropic", "generic", "projectiveJoin", "projectiveTangentSpace", "polarDegrees" } load "./CoincidentRootLoci/equationsCRL.m2"; load "./CoincidentRootLoci/equationsDualCRL.m2"; CLEAR = true; VAR = "t"; KK = QQ; --================================================================ --=== Coincident root loci ======================================= --================================================================ CRLOCUS := local CRLOCUS; CoincidentRootLocus = new Type of MutableHashTable; CoincidentRootLocus.synonym = "coincident root locus"; coincidentRootLocus = method(TypicalValue => CoincidentRootLocus, Dispatch => Thing, Options => {Variable => VAR}); coincidentRootLocus Thing := o -> LK -> ( LK = sequence LK; (lambda,K) := if #LK == 2 and (class last LK === Ring or class last LK === QuotientRing) then LK else (LK,KK); lambda = toList deepSplice lambda; try assert(ring matrix {lambda} === ZZ and min lambda > 0) else error "expected a list of positive integers"; if not isField K then error "the coefficient ring needs to be a field"; lambda = rsort lambda; if class CRLOCUS_(lambda,K,o.Variable) === CoincidentRootLocus then return CRLOCUS_(lambda,K,o.Variable); d := #lambda; n := sum lambda; R := for i to d-1 list Grass(0,1,K,Variable=>toString(o.Variable)|toString(i)); P1d := R_0; for i from 1 to d-1 do P1d = P1d ** R_i; y := local y; F := P1d[y_0,y_1]; g := for i to d-1 list flatten entries sub(vars R_i,P1d); s := switch1 product apply(d,j->(switch1(g_j,F))^(lambda_j)); phi := rationalMap(ring matrix {s},Grass(0,n,K,Variable=>o.Variable),s); if n <= 7 then forceImage(phi,idealCRL_lambda gens target phi); phi2 := if class phi === RationalMap then phi else parametrize(phi,getSymbol toString(o.Variable)); if phi#"idealImage" =!= null and phi2#"idealImage" === null then forceImage(phi2,image phi); multiplicities := for i to n list #select(lambda,e -> e == i); X := new CoincidentRootLocus from { "partition" => lambda, "multiplicities" => multiplicities, "dim" => d, "ambient" => n, "degree" => lift((d!) * (product lambda) / (product apply(multiplicities,i->i!)),ZZ), "map" => phi, "map2" => phi2, "variable" => o.Variable, "singularLocus" => null, "dual" => null }; CRLOCUS_(lambda,K,o.Variable) = X ); coincidentRootLocus (VisibleList,Ring) := o -> (lambda,K) -> coincidentRootLocus(lambda,K,Variable=>o.Variable); coincidentRootLocus (List) := o -> (lambda) -> coincidentRootLocus(lambda,KK,Variable=>o.Variable); CRL = coincidentRootLocus; JoinOfCoincidentRootLoci = new Type of MutableHashTable; dualOfCoincidentRootLocus = method(); dualOfCoincidentRootLocus (CoincidentRootLocus) := (X) -> ( l := partition X; n := X#"ambient"; m1 := (X#"multiplicities")_1; B := apply(for i to #l-1 list if l_i >= 2 then {n-l_i+2}|toList(l_i-2:1) else continue,t -> coincidentRootLocus(t,coefficientRing X,Variable=>X#"variable")); if #B == 0 then error "method not applicable"; if #B == 1 then return first B; new JoinOfCoincidentRootLoci from { "listCRloci" => B, "dim" => n-1-m1, "ambient" => n, "degree" => if m1 == 0 then lift(((#l+1)!) * (product apply(l,j->j-1)) / (product apply((X#"multiplicities")_{2..#(X#"multiplicities")-1},i -> i!)),ZZ) else null, "ideal" => if n <= 6 then trim idealDualCRL_l gens ring X else null, "dual" => X } ); expression CoincidentRootLocus := (X) -> ( s := (if # partition X == 1 then "(" else "") | toString unsequence toSequence partition X | (if # partition X == 1 then ")" else ""); s = "CRL" | substring(s,0,#s-1) | (if coefficientRing X =!= KK then ";"|toString(coefficientRing X) else "") | (if X#"variable" =!= VAR then ";'"|toString(X#"variable")|"'" else "") | ")"; expression s ); expression JoinOfCoincidentRootLoci := (Z) -> ( L := apply(Z#"listCRloci",X -> toString expression X); E := L_0; for i from 1 to #L-1 do E = E|" * "|L_i; E = E|" (dual of "|toString expression dual Z|")"; expression E ); net CoincidentRootLocus := (X) -> net expression X; CoincidentRootLocus#{WebApp,AfterPrint} = CoincidentRootLocus#{WebApp,AfterNoPrint} = CoincidentRootLocus#{Standard,AfterPrint} = CoincidentRootLocus#{Standard,AfterNoPrint} = X -> ( << endl << concatenate(interpreterDepth:"o") << lineNumber << " : " << "Coincident root locus" << endl; ); net JoinOfCoincidentRootLoci := (Z) -> net expression Z; JoinOfCoincidentRootLoci#{WebApp,AfterPrint} = JoinOfCoincidentRootLoci#{WebApp,AfterNoPrint} = JoinOfCoincidentRootLoci#{Standard,AfterPrint} = JoinOfCoincidentRootLoci#{Standard,AfterNoPrint} = X -> ( << endl << concatenate(interpreterDepth:"o") << lineNumber << " : " << "Join of ", << #(X#"listCRloci") <<" coincident root loci" << endl; ); texMath JoinOfCoincidentRootLoci := texMath CoincidentRootLocus := texMath @@ net; toString CoincidentRootLocus := (X) -> "CRL("|toString partition X|","|toString coefficientRing X|","|"Variable=>"|toString X#"variable"|")"; toString JoinOfCoincidentRootLoci := (X) -> "dual("|toString dual X|")"; map CoincidentRootLocus := o -> (X) -> X#"map"; partition CoincidentRootLocus := (X) -> X#"partition"; partition JoinOfCoincidentRootLoci := (X) -> partition dual X; ideal CoincidentRootLocus := (X) -> ( if (map X)#"idealImage" =!= null then return image map X; forceImage(map X,trim homogenize(kernel affineMap X,first gens ring X)); if (X#"map2")#"idealImage" === null then forceImage(X#"map2",image map X); image map X ); ideal JoinOfCoincidentRootLoci := (Z) -> ( -- [H. Lee, B. Sturmfels, Duality of multiple root loci, Corollary 2.3] if Z#"ideal" === null then Z#"ideal" = projectiveJoin(unsequence toSequence apply(Z#"listCRloci",affineMap),SubringLimit=>if codim Z == 1 then 1 else infinity); Z#"ideal" ); ring CoincidentRootLocus := (X) -> target map X; ring JoinOfCoincidentRootLoci := (Z) -> ring dual Z; coefficientRing CoincidentRootLocus := (X) -> coefficientRing ring X; coefficientRing JoinOfCoincidentRootLoci := (Z) -> coefficientRing ring Z; dim CoincidentRootLocus := (X) -> X#"dim"; dim JoinOfCoincidentRootLoci := (Z) -> Z#"dim"; codim CoincidentRootLocus := {} >> opts -> X -> X#"ambient" - X#"dim"; codim JoinOfCoincidentRootLoci := {} >> opts -> Y -> Y#"ambient" - Y#"dim"; degree CoincidentRootLocus := (X) -> X#"degree"; degree JoinOfCoincidentRootLoci := (Z) -> ( if Z#"degree" === null then Z#"degree" = degree ideal Z; Z#"degree" ); singularLocus (CoincidentRootLocus) := (X) -> ( -- Chipalkatti - On equations defining coincident root loci if X#"singularLocus" === null then ( d := X#"ambient"; e := X#"multiplicities"; S := {}; local f; for r1 from 1 to d do for r2 from 1 to d do if r1+r2<=d and e_r1>=1 and e_r2>=1 and r1!=r2 then (f = new MutableList from e; f#r1 = e_r1 - 1; f#r2 = e_r2 - 1; f#(r1+r2) = e_(r1+r2) + 1; S = append(S,toList f)); for r2 from 1 to d do for t from 1 to d do if t*r2<=d and t*r2!=r2 and e_(t*r2)>0 and e_r2>=t then (f = new MutableList from e; f#(t*r2) = e_(t*r2) + 1; f#r2 = e_r2 - t; S = append(S,toList f)); for r1 from 1 to d do for r2 from 1 to d do for t1 from 1 to d do for t2 from 1 to d do if t1*r1==t2*r2 and t1*r1<=d and r1!=r2 and r1!=t1*r1 and r2!=t1*r1 and e_r1>=t1 and e_r2>=t2 then (f = new MutableList from e; f#r1 = e_r1 - t1; f#r2 = e_r2 - t2; f#(t1*r1) = e_(t1*r1) + 2; S = append(S,toList f)); X#"singularLocus" = sort apply(apply(unique S,v -> rsort deepSplice apply(#v,j->v_j:j)),l -> coincidentRootLocus(l,coefficientRing X,Variable=>X#"variable")); ); X#"singularLocus" ); dual (CoincidentRootLocus) := {} >> o -> X -> ( if X#"dual" === null then X#"dual" = dualOfCoincidentRootLocus X; X#"dual" ); dual (JoinOfCoincidentRootLoci) := JoinOfCoincidentRootLoci => {} >> o -> Z -> Z#"dual"; CoincidentRootLocus == CoincidentRootLocus := (X,Y) -> X#"variable" === Y#"variable" and coefficientRing X === coefficientRing Y and partition X == partition Y; JoinOfCoincidentRootLoci == JoinOfCoincidentRootLoci := (X,Y) -> X#"dual" === Y#"dual"; member (RingElement,Ideal) := (F,I) -> ( if not (isPolynomialRing ring I and isHomogeneous I) then error "expected a homogeneous ideal in a polynomial ring"; if not (isPolynomialRing ring F and numgens ring F == 2 and isHomogeneous F and first degree F == numgens ring I -1 and char coefficientRing ring F === char coefficientRing ring I) then error("expected a binary form of degree "|toString(numgens ring I -1)|" over "|toString(coefficientRing ring I)); t := gens ring I; c := switch1 F; sub(I,apply(#t,i -> t_i => c_i)) == 0 ); member (RingElement,CoincidentRootLocus) := (F,X) -> ( checkBinaryForm F; if first degree F =!= X#"ambient" then error("expected a binary form of degree "|toString(X#"ambient")); if char coefficientRing ring F =!= char coefficientRing X then error("expected a binary form over "|toString(coefficientRing X)); if (map X)#"idealImage" === null then ( if codim X == 1 then return discriminant F == 0; if coefficientRing ring F === coefficientRing X then return dim((map X)^* switch2(F,Variable=>X#"variable")) - dim(X) >= 0; ); t := gens ring X; c := switch1 F; return sub(ideal X,apply(#t,i -> t_i => c_i)) == 0; ); member (RingElement,JoinOfCoincidentRootLoci) := (F,Z) -> ( checkBinaryForm F; if first degree F =!= Z#"ambient" then error("expected a binary form of degree "|toString(Z#"ambient")); if char coefficientRing ring F =!= char coefficientRing Z then error("expected a binary form over "|toString(coefficientRing Z)); if Z#"ideal" =!= null or coefficientRing ring F =!= coefficientRing Z then return sub(ideal Z,apply(gens ring Z,switch1 F,(t,c) -> t => c)) == 0; X := Z#"dual"; l := flatten entries compress matrix {apply(partition X,j -> j-1)}; J := apolar(F,sum l); if J == 0 then return false; L := switch2(J,Variable=>X#"variable"); Y := coincidentRootLocus(l,coefficientRing X,Variable=>X#"variable"); f := map Y; return if (map Y)#"idealImage" === null then dim(f^* L) - (#l) >= 0 else dim((ideal Y) + L) >= 1; ); random (CoincidentRootLocus) := o -> (X) -> ( f := map X; p := f ideal apply(entries diagonalMatrix toList((dim X):1),u -> random(u,source f)); switch2 p ); random (JoinOfCoincidentRootLoci) := o -> (Z) -> ( X := Z#"dual"; f := map X; J :=sub(transpose jacobian matrix f,apply(gens source f,x -> x => random coefficientRing X)); T := ideal image basis(1,intersect apply(entries transpose mingens image J, u -> minors(2,(vars target f)||matrix{u}))); assert(dim T -1 == dim X); H := ideal sum(T_*,g -> random(coefficientRing X) * g); switch2 pairingIsomorphism dualVariety H ); generic = method(Options => {Variable => null, Reduce => false}) generic (CoincidentRootLocus) := o -> (X) -> ( x := if o.Variable === null then (if toString(X#"variable") =!= toString(VAR) then VAR else "x") else o.Variable; M := if o.Reduce then matrix X#"map2" else matrix map X; R := Grass(0,1,frac ring M,Variable=>x); F := switch1(flatten entries sub(M,frac ring M),R); R':= (ring numerator 1_(coefficientRing R))[gens R]; sub(F,R') ); generic (PolynomialRing) := o -> (R) -> ( -- undocumented x := if o.Variable === null then VAR else o.Variable; P := Grass(0,1,frac R,Variable=>x); F := switch1(flatten entries sub(vars R,frac R),P); P':= (ring numerator 1_(coefficientRing P))[gens P]; sub(F,P') ); describe (CoincidentRootLocus) := (X) -> ( S := "Coincident root locus associated with the partition "|toString partition X|" defined over "|toString coefficientRing X|newline; S = S|"ambient: P^"|toString X#"ambient"|" = Proj("|toString ring X|")"|newline; S = S|"dim = "|toString dim X|newline; S = S|"codim = "|toString codim X|newline; S = S|"degree = "|toString degree X|newline; SingX := singularLocus X; if #SingX == 0 then S = S|"The singular locus is empty" else if #SingX == 1 then S = S|"The singular locus coincides with the coincident root locus associated with the partition "|toString partition first SingX else S = S|"The singular locus is the union of the coincident root loci associated with the partitions: "|newline|toString toSequence apply(SingX,partition); if codim X == 1 and (map X)#"idealImage" =!= null then S = S|newline|"The defining polynomial has "|toString(# terms (ideal X)_0)|" terms of degree "|toString degree X; return S; ); describe (JoinOfCoincidentRootLoci) := (X) -> ( S := "Dual of the coincident root locus associated with the partition "|toString partition dual X|" defined over "|toString coefficientRing X|newline; S = S|"which coincides with the join of the coincident root loci associated with the partitions:"|(if #(X#"listCRloci") > 2 then newline else " ")|toString toSequence apply(X#"listCRloci",partition)|newline; S = S|"ambient: P^"|toString X#"ambient"|" = Proj("|toString ring X|")"|newline; S = S|"dim = "|toString dim X|newline; S = S|"codim = "|toString codim X; if X#"degree" =!= null then S = S|newline|"degree = "|toString degree X; if codim X == 1 and X#"ideal" =!= null then S = S|newline|"The defining polynomial has "|toString(# terms (ideal X)_0)|" terms of degree "|toString degree X; return S; ); refinedPartitions = method() refinedPartitions (List) := (l) -> ( L := flatten for h to #l-1 list if l_h > 1 then for i from 1 to l_h - 1 list rsort(l_{0..h-1} | {i,l_h - i}| l_{(h+1..#l-1)}) else continue; if #L == 0 then return {l} else return rsort unique ({l} | L | flatten apply(L,refinedPartitions)) ); coarseningPartitions = method() coarseningPartitions (List) := (l) -> ( if #l== 1 then return {l}; rsort({l} | unique flatten apply(unique flatten for i to #l-1 list for j from i+1 to #l-1 list rsort append(l_{0..i-1}|l_{i+1..j-1}|l_{j+1..#l-1},l_i+l_j),coarseningPartitions)) ); isRefinement = method(); -- l1 <= l2 isRefinement (List,List) := (l1,l2) -> member(l1,coarseningPartitions l2); isSubset(CoincidentRootLocus,CoincidentRootLocus) := (X,Y) -> ( if ring X =!= ring Y then return false; isRefinement(partition X,partition Y) ); CoincidentRootLocus ? CoincidentRootLocus := (X,Y) -> ( if X == Y then return symbol == else if isSubset(X,Y) then return symbol < else if isSubset(Y,X) then return symbol > else if dim X < dim Y then return symbol < else if dim X > dim Y then return symbol > else return incomparable; ); supsets = method(); supsets (CoincidentRootLocus) := (X) -> sort apply(refinedPartitions partition X,l -> coincidentRootLocus(l,coefficientRing X,Variable=>X#"variable")); subsets (CoincidentRootLocus) := (X) -> sort apply(coarseningPartitions partition X,l -> coincidentRootLocus(l,coefficientRing X,Variable=>X#"variable")); affineMap = method(TypicalValue => RingMap) affineMap (CoincidentRootLocus) := (X) -> ( f := X#"map2"; x := gens source f; n := #x -1; K := coefficientRing f; F := sub(sub(matrix f,x_0=>1),K[x_{1..n}]); map(ring F,target f,F) ); affineMap (JoinOfCoincidentRootLoci) := (X) -> ( -- Thm 2.5 [Lee, Sturmfels - Duality of multiple root loci] K := coefficientRing X; n := X#"ambient"; l := select(partition X,i -> i>1); s := local s; t := local t; u := local u; T := K[s_0..s_(#l-1),t_0..t_(#l-1),flatten for i to #l-1 list for j to l_i-3 list u_(i,j)]; y := local y; F := T[y_0,y_1]; f := switch1 sum for i to #l-1 list s_i * (switch1({1_T,t_i},F))^(n-l_i+2) * switch1(prepend(1_T,toList(u_(i,0)..u_(i,l_i-3))),F); map(T,ring X,f) ); chowForm (CoincidentRootLocus) := o -> (X) -> chowForm(map X#"map2",Variable=>o.Variable); isInCoisotropic (Ideal,CoincidentRootLocus) := o -> (L,X) -> ( if not (isPolynomialRing ring L and numgens ring L == 2 and coefficientRing ring L === coefficientRing X and isHomogeneous L and unique flatten degrees L === {X#"ambient"}) then error("expected an ideal generated by binary forms of degree "|toString(X#"ambient")|" over "|toString(coefficientRing X)); return isInCoisotropic(sub(switch2 L,vars ring X),ideal X,Duality=>o.Duality); ); randomInCoisotropic = method() randomInCoisotropic (Ideal,ZZ,Ideal) := (I,i,p) -> ( if ring p =!= ring I then error "common ring not found"; if not isPolynomialRing ring I then error "expected a polynomial ring"; if not (isHomogeneous I and isHomogeneous p) then error "expected a homogeneous ideal"; if not (dim p == 1 and degree p == 1 and unique degrees p == {{1}}) then error "expected last argument to be the ideal of a point"; if not isSubset(I,p) then error "expected a point of the variety"; subs := apply(gens ring I,flatten entries coefficients parametrize p,(x,s) -> x => s); T := trim ideal((vars ring I) * sub(jacobian I,subs)); K := coefficientRing ring I; c := codim I; n := numgens ring I -1; d := n - c; -- dim I -1 L := trim(T + ideal apply(d-i,i -> ((gens p) * random(K^n,K^1))_(0,0))); m := numgens L; H := trim ideal apply(n-c+1-i,i -> ((gens L) * random(K^m,K^1))_(0,0)); (H,(dim H - 1 == c - 1 + i and dim T - 1 == d and dim L - 1 == i and isSubset(T,L) and isSubset(L,p))) ); randomInCoisotropic (Ideal,ZZ) := (I,i) -> ( local H; condition := false; while not condition do (H,condition) = randomInCoisotropic(I,i,point I); H ); randomInCoisotropic (CoincidentRootLocus,ZZ) := (X,i) -> ( local H; condition := false; while not condition do (H,condition) = randomInCoisotropic(ideal X,i,switch2 random X); J := switch2 H; if isIdeal J then J else ideal J ); CoincidentRootLocus + CoincidentRootLocus := (X,Y) -> ( -- intersection, undocumented if ring X =!= ring Y then error "expected same ring"; S := toList((set subsets X) * (set subsets Y)); E := S; for A in S do for B in select(subsets A,s -> dim A - dim s > 0) do E = delete(B,E); if #E == 1 then first E else E ); projectiveTangentSpace = method() projectiveTangentSpace (CoincidentRootLocus,RingElement) := (X,F) -> ( checkBinaryForm F; if first degree F =!= X#"ambient" then error("expected a binary form of degree "|toString(X#"ambient")); if coefficientRing ring F =!= coefficientRing X then error("expected a binary form over "|toString(coefficientRing X)); if not member(F,X) then error("expected a binary form belonging to "|toString net X); J := sub(jacobian ideal X,apply(gens ring X,switch1 F,(x,s) -> x => s)); sub(switch2 ideal((vars ring X) * J),vars ring F) ); --================================================================ --===== Polar degrees of CRL ===================================== --================================================================ polarDegrees = method(); polarDegrees (CoincidentRootLocus) := (X) -> ( lambda := partition X; n := #lambda; e := n - (X#"multiplicities")_1; -- to be replaced "degree dual CRL" with the explicit Oeding formula P := for j to e list lift((sum(conj(lambda,j),u -> (last u) * degree dual CRL(first u,ZZ/101)))/(n-j+1),ZZ); P | toList(n-e : 0) ); conj = method(); conj (List,ZZ) := (lambda,j) -> ( n := #lambda; r := sum lambda; d := n + r - j; D := descendantsPartitions(lambda,j); F := apply(D,a -> (apply(a|toList((n-#a):0),i->i+1),partitionMultiplicity(a,lambda))); select(F,y -> #select(first y,u -> u==1) == 0) ); partitionMultiplicity = method() partitionMultiplicity (List,List) := (lambda',lambda) -> ( try assert(ring matrix {lambda} === ZZ and min lambda > 0 and ring matrix {lambda'} === ZZ and min lambda' > 0) else error "expected lists of positive integers"; lambda = rsort lambda; lambda' = rsort lambda'; n := #lambda; lambda' = lambda'|toList((n-#lambda'):0); r := sum lambda; r' := sum lambda'; j := r-r'; J := toList (set {0,1})^**n; for i to n-3 do J = apply(J,splice); J = select(apply(J,toList),a -> sum a == j); A := select(J,a -> rsort(lambda' + a) == lambda); #A ); descendantsPartitions = method() descendantsPartitions (List,ZZ) := (lambda,j) -> ( try assert(ring matrix {lambda} === ZZ and min lambda > 0) else error "expected a list of positive integers"; lambda = rsort lambda; n := #lambda; J := toList (set {0,1})^**n; for i to n-3 do J = apply(J,splice); J = select(apply(J,toList),a -> sum a == j); unique apply(J,a -> rsort flatten entries compress matrix{lambda - a}) ); --================================================================ --=== Real algebraic boundary ==================================== --================================================================ realRankBoundary = method(Options => {Variable => VAR}) realRankBoundary (ZZ,ZZ,Ring) := o -> (n,k,K) -> ( if not (1 <= k and ceiling((n+1)/2) <= k and k <= n) then return {}; if k == n then return coincidentRootLocus(toList prepend(2,n-2:1),K,Variable=>o.Variable); if n == 4 and k == 3 then return coincidentRootLocus({2,1,1},K,Variable=>o.Variable); if n == 5 and k == 4 then return {realRankBoundary(5,3,K,Variable=>o.Variable),realRankBoundary(5,5,K,Variable=>o.Variable)}; if n == 6 and k == 5 then return append(realRankBoundary(6,4,K,Variable=>o.Variable),realRankBoundary(6,6,K,Variable=>o.Variable)); if k == ceiling((n+1)/2) then ( if odd n then ( return dual coincidentRootLocus(toList prepend(3,k-2:2),K,Variable=>o.Variable); ) else ( return {dual coincidentRootLocus({3,3}|toList(k-4:2),K,Variable=>o.Variable),dual coincidentRootLocus(toList prepend(4,k-3:2),K,Variable=>o.Variable)}; ); ); if n == 7 and k == 5 then ( return {dual coincidentRootLocus({3,2,2},K,Variable=>o.Variable),dual coincidentRootLocus({4,3},K,Variable=>o.Variable),dual coincidentRootLocus({5,2},K,Variable=>o.Variable)}; ); if n == 7 and k == 6 then ( return {dual coincidentRootLocus({4,3},K,Variable=>o.Variable),dual coincidentRootLocus({5,2},K,Variable=>o.Variable),dual coincidentRootLocus({7},K,Variable=>o.Variable)}; ); if n == 8 and k == 6 then ( return {dual coincidentRootLocus({3,3,2},K,Variable=>o.Variable),dual coincidentRootLocus({4,2,2},K,Variable=>o.Variable),dual coincidentRootLocus({4,4},K,Variable=>o.Variable),dual coincidentRootLocus({5,3},K,Variable=>o.Variable),dual coincidentRootLocus({6,2},K,Variable=>o.Variable)}; ); if n == 8 and k == 7 then ( return {dual coincidentRootLocus({4,4},K,Variable=>o.Variable),dual coincidentRootLocus({5,3},K,Variable=>o.Variable),dual coincidentRootLocus({6,2},K,Variable=>o.Variable),dual coincidentRootLocus({8},K,Variable=>o.Variable)}; ); error "not implemented yet"; ); realRankBoundary (ZZ,ZZ) := o -> (n,k) -> realRankBoundary(n,k,KK,Variable=>o.Variable); --================================================================ --=== Apolarity ================================================== --================================================================ catalecticantMatrix = method() catalecticantMatrix (RingElement,ZZ) := (F,k) -> ( mm := flatten entries gens (ideal vars ring F)^k; mm':= flatten entries gens (ideal vars ring F)^(first degree F - k); D := matrix {apply(mm,t -> diff(t,F))}; sub(last coefficients(D,Monomials=>mm'),coefficientRing ring F) ); catalecticantMatrix (PolynomialRing,ZZ) := (R,k) -> ( K := coefficientRing R; n := numgens R -1; x := gens R; H := matrix for i to n-k list for j to k list x_(i+j); H * (coefficients pairingIsomorphism(k,K))^-1 ); Trim = method() Trim (Ideal) := (I) -> ( if not isPolynomialRing ring I then error "expected an ideal in a polynomial ring"; K := coefficientRing ring I; if isField K and class K =!= FractionField then return trim I; n := numgens ring I -1; x := local x; local R; local R'; local K'; local I'; if not isField K then ( K' = frac K; R = K[x_0..x_n]; R'= K'[x_0..x_n]; I'= trim sub(sub(I,vars R),R'); ) else ( K' = K; K = ring numerator(1_K'); R = K[x_0..x_n]; R'= K'[x_0..x_n]; I'= trim sub(I,vars R'); ); if I' == 0 then return ideal ring I; return sub(trim ideal matrix{apply(I'_*,g -> sub(g * lcm apply(flatten entries sub(last coefficients g,K'),denominator),R))},vars ring I); ); apolar = method(Options => {Variable => VAR}) apolar (RingElement) := o -> (F) -> ( checkBinaryForm F; K := coefficientRing ring F; d := first degree F; I := Trim sum(d+1, k -> apolar(F,k)); try assert((numgens I == 1 and first degree I_0 == 1) or (numgens I == 2 and sum apply(degrees I,first) == d+2)) else error "internal error encountered"; I ); apolar (RingElement,ZZ) := o -> (F,k) -> ( checkBinaryForm F; K := coefficientRing ring F; if not isField K then ( K':= frac K; x := local x; y := local y; R := K[x,y]; R':= K'[x,y]; F':= sub(sub(F,vars R),R'); return sub(sub(Trim apolar(F',k),R),vars ring F); ); A := catalecticantMatrix(F,k); I := (gens (ideal vars ring F)^k) * (mingens kernel A); Trim ideal I ); apolar (ZZ,ZZ,Ring) := o -> (n,s,K) -> (-- apolar map P^n --> G(2*s-n-1,s,K) ~ G(n-s,s) if n > 2*s then error "expected integers n,s with n < 2*s+1"; Pn := Grass(0,n,K,Variable=>o.Variable); H := catalecticantMatrix(Pn,s); f := rationalMap dualize map rationalMap(Pn,Grass(n-s,s,K,Variable=>o.Variable),gens minors(n-s+1,H)); assert(target f === Grass(2*s-n-1,s,K,Variable=>o.Variable)); f ); apolar (ZZ,ZZ) := o -> (n,s) -> apolar(n,s,KK,Variable=>o.Variable); recover = method() recover (Ideal) := (I) -> ( x := local x; K := coefficientRing ring I; if not isField K then try ( I' := sub(I,vars Grass(0,1,frac(K),Variable=>x)); F' := recover I'; assert(K === ring numerator(1_(coefficientRing ring F'))); R := K[gens ring F']; return sub(sub((Trim ideal F')_0,R),vars ring I); ); if not (isPolynomialRing ring I and isHomogeneous I) then error "expected a homogeneous ideal in a polynomial ring"; if # unique degrees I > 1 then if numgens I == 2 then I = ideal image basis(max flatten degrees I,I) else error "expected an ideal generated by forms of the same degree"; M := matrix apply(I_*,switch1); p := plucker(M,Variable=>x); k := numgens target M -1; N := numgens source M -1; f := apolar(2*N-k-1,N,K,Variable=>x); q := f^* p; if degrees q =!= toList((2*N-k-1):{1}) then if dim I >= 1 then error "the ideal is not apolar"; F := sub(switch2(q,Variable=>x),vars ring I); (Trim ideal F)_0 ); recover (RingElement,RingElement) := (g,h) -> recover ideal(g,h); --================================================================ --=== Real rooted forms and Qepcad =============================== --================================================================ isSomeLinearCombinationRealRooted = method(TypicalValue => Boolean, Options => {QepcadOptions => (20000000,10000), Range => (-infinity,infinity), Verbose => false}) isSomeLinearCombinationRealRooted (Matrix) := o -> (F) -> ( if numgens target F != 1 then error "expected a matrix with one row"; if not (isPolynomialRing ring F and numgens ring F == 2) then error "expected a matrix with entries in a polynomial ring with two variables"; K := coefficientRing ring F; x := local x; y := local y; Txy := K[x,y]; F = sub(F,vars Txy); Fe := F; if K =!= QQ then ( if not(isPolynomialRing K and coefficientRing K === QQ and numgens K <= 1) then error "expected coefficient ring of the form QQ or QQ[e]"; Fe = sub(F,frac(coefficientRing K)[gens Txy]); ); if not isHomogeneous ideal Fe then error "expected a homogeneous matrix"; d := unique apply(flatten entries Fe,degree); if #d > 1 then error "expected forms of the same degree" else d = first d; if #d > 1 then error "expected a standard graded polynomial ring" else d = first d; n := numgens source F -1; if n == 0 and K === QQ then ( Tx := K[x]; f := sub(sub(F_(0,0),y=>1),Tx); if o.Verbose then <<"--computing bezoutian matrix of a binary form of degree "<<d<<endl; if first degree f < d-1 then return false else return (#select(leadingPrincipalMinors bezoutianMatrix f,m -> m <= 0) == 0); ); t := local t; Rxy := K[t_0..t_n][x,y]; Rx := K[t_0..t_n][x]; q := (sub(F,Rxy) * transpose(vars coefficientRing Rxy))_(0,0); q' := sub(sub(q,y=>1),Rx); d' := first degree q'; if d' < d-1 then return false; tn := last gens coefficientRing Rx; Sx := if n-1 >= 0 then K[t_0..t_(n-1)][x] else K[x]; q1 := sub(sub(q',tn => 1),Sx); isRealRootedViaQEPCAD(q1,QepcadOptions=>o.QepcadOptions,Range=>o.Range,Verbose=>o.Verbose) ); isRealRootedViaQEPCAD = method(Options => {QepcadOptions => (20000000,10000), Range => (-infinity,infinity), Verbose => false}) isRealRootedViaQEPCAD (RingElement) := o -> (F) -> ( if not isPolynomialRing ring F then error "expected a polynomial"; if not isPolynomialRing coefficientRing ring F then error "expected a polynomial with polynomial coefficients"; if first o.QepcadOptions < 20000000 or last o.QepcadOptions < 10000 then <<"--warning: small number of cells in the garbage collected space"<<endl; try assert((class o.Range === Sequence or class o.Range === Array) and # o.Range == 2) else error "Range option accepts a sequence or an array of length 2"; if numgens ring F != 1 then error "expected a univariate polynomial"; K := (coefficientRing coefficientRing ring F)[vars(0 .. (numgens coefficientRing ring F)-1)]; z := local z; R := K[z]; F' := sub(F,apply(numgens K,j -> (gens coefficientRing ring F)_j => (gens K)_j) | {first gens ring F => z}); try assert(F == sub(F',apply(numgens K,j -> (gens K)_j => (gens coefficientRing ring F)_j) | {z => first gens ring F})) else error "something went wrong"; S := "[Existence of real values of "|toString unsequence toSequence gens K|" such that a given polynomial in "|toString(R)|" is real-rooted]"|newline; gg := toSequence((gens coefficientRing K)|(gens K)|(gens R)); S = S | (if #gg =!= 1 then toString gg else "("|toString(first gg)|")") | newline; S = S | toString(numgens coefficientRing K) | newline; S = S | concatenate apply(gens K,g -> "(F "|toString(g)|") ") | "(X " | toString(first degree F') | " " | toString(z) | ") " | "["|replace("\\*"," ",replace("\\+"," + ",replace("-"," - ",toString F'))) | " = 0]. " | newline; if numgens coefficientRing K > 0 and (first o.Range =!= -infinity or last o.Range =!= infinity) then ( ass1 := toString(first o.Range) | (if class o.Range === Sequence then " < " else " <= ") | toString(first gens coefficientRing K); ass2 := toString(first gens coefficientRing K) | (if class o.Range === Sequence then " < " else " <= ") | toString(last o.Range); ass := if first o.Range =!= -infinity and last o.Range =!= infinity then "[ " | ass1 | " /\\ " | ass2 | " ]" else if first o.Range =!= -infinity then "[ " | ass1 | " ]" else "[ " | ass2 | " ]"; if o.Verbose then <<"--assumption: " << ass << endl; S = S | "assume " | ass | newline; ); S = S | "finish " | newline; dir := rootPath | temporaryFileName(); (dir|"-input") << S << close; C := "qepcad +N"|toString(first o.QepcadOptions)|" +L"|toString(last o.QepcadOptions)|" < '"|dir|"-input'"; if o.Verbose then << "--running " << C << endl; try (Out := get("!"|C); if CLEAR then removeFile(dir|"-input")) else error "error occurred while executing QEPCAD. Please make sure that it is installed and configured correctly."; jj := toList first regex("An equivalent quantifier-free formula:"|newline|newline,Out); V := substring(Out,sum jj,5); if V === "TRUE"|newline then return true else if V === "FALSE" then return false else ( lOut := first first regex(newline|"===================== The End =======================",Out); error("unable to interpret QEPCAD output:"|newline|newline|substring(Out,sum jj,lOut - (sum jj) -2)); ); ); realrank = method(Options => {QepcadOptions => (20000000,10000), Range => (-infinity,infinity), Verbose => false, Limit => infinity}); realrank (RingElement) := o -> (F) -> ( checkBinaryForm F; K := coefficientRing ring F; if K =!= QQ and not(isPolynomialRing K and coefficientRing K === QQ and numgens K <= 1) then error "expected coefficient ring of the form QQ or QQ[e]"; d := first degree F; if d == 5 and K === QQ then (if o.Verbose then <<"--trying to apply Comon and Ottaviani's algorithm for the real rank of a generic quintic"<<endl; try return realrank5 F else if o.Verbose then <<"--method failed due to the lack of genericity"<<endl;); Jl := apply(d+1,k -> apolar(F,k)); J := Trim sum Jl; if numgens J == 1 then if first degree(J_0) == 1 then return 1; if numgens J != 2 then error "internal error encountered"; (e1,e2) := toSequence sort apply(degrees J,first); if e1+e2 =!= d+2 then error "internal error encountered"; g1 := first select(J_*,g -> first degree g == e1); g2 := first select(J_*,g -> first degree g == e2); if o.Verbose then <<"--detected that the real rank belongs to "<<toString unique deepSplice{e1,e2..d}<<endl; if o.Verbose then (if e1 < e2 then <<"--verifying if the real rank is "<< e1 <<endl else <<"--preliminary tests to verify if the real rank is "<< e2 <<endl); if isSomeLinearCombinationRealRooted(matrix g1,QepcadOptions=>o.QepcadOptions,Range=>o.Range,Verbose=>o.Verbose) then return e1; if o.Verbose then if e1 < e2 then <<"--preliminary test to verify if the real rank is "<< e2 <<endl; if isSomeLinearCombinationRealRooted(matrix g2,QepcadOptions=>o.QepcadOptions,Range=>o.Range,Verbose=>o.Verbose) then return e2; for j from e2 to d-2 do ( if j >= o.Limit then return (j..d); if o.Verbose then <<"--verifying if the real rank is "<< j <<endl; if isSomeLinearCombinationRealRooted(gens Jl_j,QepcadOptions=>o.QepcadOptions,Range=>o.Range,Verbose=>o.Verbose) then return j else continue; ); if d-1 >= o.Limit then return (d-1,d); if K =!= QQ or d < 3 or discriminant F == 0 then ( if o.Verbose then <<"--verifying if the real rank is "<< d-1 <<endl; if isSomeLinearCombinationRealRooted(gens Jl_(d-1),QepcadOptions=>o.QepcadOptions,Range=>o.Range,Verbose=>o.Verbose) then return (d-1) else return d; ) else ( if isSomeLinearCombinationRealRooted(matrix F,QepcadOptions=>o.QepcadOptions,Range=>o.Range,Verbose=>o.Verbose) then return d else return (d-1); ); ); realrank5 = method() realrank5 (RingElement) := (F) -> ( if first degree F != 5 then error "expected a binary form of degree 5"; if discriminant F == 0 then error "method failed due to the lack of genericity"; if isSomeLinearCombinationRealRooted matrix F then return 5; a := switch1 F; x := local x; y := local y; R := QQ[x,y]; g := (det matrix {{a_1,a_2,a_3},{a_2,a_3,a_4},{a_3,a_4,a_5}})*x^3 - (det matrix {{a_0,a_2,a_3},{a_1,a_3,a_4},{a_2,a_4,a_5}})*x^2*y + (det matrix {{a_0,a_1,a_3},{a_1,a_2,a_4},{a_2,a_3,a_5}})*x*y^2 - (det matrix {{a_0,a_1,a_2},{a_1,a_2,a_3},{a_2,a_3,a_4}})*y^3; if discriminant g == 0 then error "method failed due to the lack of genericity"; if isSomeLinearCombinationRealRooted matrix g then return 3 else return 4; ); complexrank = method(Options => {Limit => infinity}); complexrank (RingElement) := o -> (F) -> ( checkBinaryForm F; if not isField coefficientRing ring F then error "the coefficient ring needs to be a field"; d := first degree F; Jl := apply(d+1, k -> apolar(F,k)); J := Trim sum Jl; if numgens J == 1 then if first degree(J_0) == 1 then return 1; if numgens J != 2 then error "internal error encountered"; (e1,e2) := toSequence sort apply(degrees J,first); if e1+e2 =!= d+2 then error "internal error encountered"; g1 := first select(J_*,g -> first degree g == e1); g2 := first select(J_*,g -> first degree g == e2); if discriminant g1 != 0 then return e1; return e2; -- It follows from Terracini's Lemma. -- if discriminant g2 != 0 then return e2; -- K := coefficientRing ring F; -- local I; local g; -- for j from e2 to d-1 do ( -- if j >= o.Limit then return (j..d); -- I = Jl_j; -- g = (gens I * random(K^(numgens I),K^1))_(0,0); -- if discriminant g != 0 then return j else continue; -- ); -- return d; ); matriceCompagna = method(TypicalValue => Matrix) matriceCompagna (RingElement,RingElement) := (f,h) -> ( if not (ring f === ring h and isPolynomialRing ring f and numgens ring f == 1) then error "expected a univariate polynomial"; x := first gens ring f; K := coefficientRing ring f; d := first degree f; f = (leadCoefficient f)^-1 * f; R := (ring f)/f; b := sub(matrix{apply(d,i -> x^i)},R); sub(last coefficients(h * b,Monomials=>b),K) ); bezoutianMatrix = method(TypicalValue => Matrix) bezoutianMatrix (RingElement) := (f) -> ( if not (isPolynomialRing ring f and numgens ring f == 1) then error "expected a univariate polynomial"; if not isUnit leadCoefficient f then (z := local z; f = sub(f,vars((frac coefficientRing ring f)[z]))); x := first gens ring f; d := first degree f; v := apply(2*d-1,i -> trace matriceCompagna(f,x^i)); matrix table(d,d,(i,j) -> v_(i+j)) ); leadingPrincipalMinors = method(TypicalValue => Boolean) leadingPrincipalMinors (Matrix) := (M) -> ( try assert(M - transpose M == 0) else error "expected a symmetric matrix"; for i to numgens source M -1 list det submatrix(M,{0..i},{0..i}) ); realroots = method(Options => {Verbose => false}) realroots (RingElement) := o -> (F) -> ( checkBinaryForm F; K := coefficientRing ring F; if K =!= QQ then error "expected coefficient ring to be QQ"; x := local x; y := local y; R := K[x,y]; F = sub(F,vars R); f := sub(sub(F,y => 1),K[x]); ro := toList(((first degree F) - (first degree f)) : [1.0,0.0]); ro = ro | apply(select(roots f,a -> abs(imaginaryPart a) < 0.0000001),r -> [realPart r,1.0]); if o.Verbose then ( <<"number real roots: "<<#ro<<endl; <<"number distinct real roots: "<<#unique ro<<endl; <<"number non-real roots: "<<(first degree F) - #ro <<endl; ); ro ); --================================================================ --=== Joins ====================================================== --================================================================ projectiveJoin = method(Dispatch => Thing, Options => {SubringLimit => infinity}); projectiveJoin (Thing) := o -> U -> ( U = sequence U; if #U == 0 then return; if apply(U,class) === (#U):RingMap then return joinOfAffineParameterizations(U,SubringLimit=>o.SubringLimit) else if apply(U,class) === (#U):RationalMap then return joinOfParameterizations(U,SubringLimit=>o.SubringLimit) else if apply(U,class) === (#U):Ideal then ( if #U <= 2 then return joinOfIdeals(U,SubringLimit=>o.SubringLimit); if #U >= 3 then return projectiveJoin(projectiveJoin unsequence toSequence(U_{0..#U-2}),last U,SubringLimit=>o.SubringLimit); ) else if apply(U,class) === (#U):CoincidentRootLocus then return joinOfHooks U else error "expected a sequence of ideals, or rational maps, or ring maps, or coincident root loci"; ); joinOfIdeals = method(TypicalValue => Ideal, Dispatch => Thing, Options => {SubringLimit => infinity}); joinOfIdeals (Thing) := o -> U -> ( U = sequence U; r := #U-1; if r == -1 then return; if apply(U,class) =!= (r+1):Ideal then error "expected a sequence of ideals"; if # unique apply(U,ring) > 1 then error "expected same ring"; K := coefficientRing ring first U; if not isField K then error "the coefficient ring needs to be a field"; ringPn := ring first U; if not isPolynomialRing ringPn then error "expected ideals in a polynomial ring"; if apply(U,isHomogeneous) =!= (r+1):true then error "expected homogeneous ideals"; if r == 0 then return trim first U; n := numgens ringPn -1; x := local x; T := for i to r list K[x_(0,i)..x_(n,i)]; t := local t; z := local z; R := K[t_0..t_r,flatten apply(T,gens),z_0..z_n,MonomialOrder=>Eliminate ((n+2)*(r+1))]; W := ideal(matrix{{z_0..z_n}} - sum(r+1,i -> t_i * sub(vars T_i,R))); W = trim(W + sum(r+1,i -> sub(sub(U_i,vars T_i),R))); trim sub(sub(ideal selectInSubring(1,gens gb(W,SubringLimit=>o.SubringLimit)),K[z_0..z_n]),vars ringPn) ); joinOfParameterizations = method(TypicalValue => Ideal, Dispatch => Thing, Options => {SubringLimit => infinity}); joinOfParameterizations (Thing) := o -> U -> ( U = sequence U; r := #U-1; if r == -1 then return; if apply(U,class) =!= (r+1):RationalMap then error "expected a sequence of rational maps"; if # unique apply(U,target) > 1 then error "expected maps with the same target"; ringPN := target first U; if not isPolynomialRing ringPN then error "expected maps between projective spaces"; for f in U do if not isPolynomialRing source f then error "expected maps between projective spaces"; if r == 0 then return trim kernel(map first U,SubringLimit=>o.SubringLimit); N := numgens ringPN -1; x := local x; K := coefficientRing first U; T := for i to r list K[x_(0,i)..x_(numgens source U_i -1,i)]; t := local t; z := local z; R := K[t_0..t_r,flatten apply(T,gens),z_0..z_N,MonomialOrder=>Eliminate (r+1+sum(U,f -> numgens source f))]; W := trim ideal(matrix{{z_0..z_N}} - sum(r+1,i -> t_i * sub(sub(matrix U_i,vars T_i),R))); trim sub(sub(ideal selectInSubring(1,gens gb(W,SubringLimit=>o.SubringLimit)),K[z_0..z_N]),vars ringPN) ); joinOfAffineParameterizations = method(TypicalValue => Ideal, Dispatch => Thing, Options => {SubringLimit => infinity}); joinOfAffineParameterizations (Thing) := o -> U -> ( U = sequence U; r := #U-1; if r == -1 then return; if apply(U,class) =!= (r+1):RingMap then error "expected a sequence of ring maps"; if # unique apply(U,source) > 1 then error "expected ring maps with the same source"; ringPN := source first U; if not isPolynomialRing ringPN then error "expected maps between polynomial rings"; for f in U do if not isPolynomialRing target f then error "expected maps between polynomial rings"; if r == 0 then return trim kernel(first U,SubringLimit=>o.SubringLimit); N := numgens ringPN -1; x := local x; K := coefficientRing ringPN; T := for i to r list K[x_(0,i)..x_(numgens target U_i -1,i)]; t := local t; z := local z; R := K[t_0..t_r,flatten apply(T,gens),z_0..z_N,MonomialOrder=>Eliminate (r+1+sum(U,f -> numgens target f))]; W := trim ideal(matrix{{z_0..z_N}} - sum(r+1,i -> t_i * sub(sub(matrix U_i,vars T_i),R))); trim sub(sub(ideal selectInSubring(1,gens gb(W,SubringLimit=>o.SubringLimit)),K[z_0..z_N]),vars ringPN) ); joinOfHooks = method(Dispatch => Thing); joinOfHooks (Thing) := U -> ( U = sequence U; r := #U-1; if r == -1 then return; if apply(U,class) =!= (r+1):CoincidentRootLocus then error "expected a sequence of coincident root loci"; R := ring first U; n := numgens R -1; local p; local p0; l := for i to #U-1 list ( if ring U_i =!= R then error "expected a sequence of coincident root loci with the same ring"; p = partition U_i; p0 = first p; if p =!= prepend(p0,toList(n-p0:1)) then error "expected a sequence of coincident root loci determined by hook shapes"; n + 2 - p0 ); m1 := n - sum l; if m1 < 0 then error "too many coincident root loci"; dual coincidentRootLocus(l|toList(m1:1),coefficientRing R,Variable=>(first U)#"variable") ); CoincidentRootLocus * CoincidentRootLocus := (X,Y) -> joinOfHooks(X,Y); JoinOfCoincidentRootLoci * CoincidentRootLocus := (X,Y) -> joinOfHooks append(toSequence(X#"listCRloci"),Y); CoincidentRootLocus * JoinOfCoincidentRootLoci := (X,Y) -> Y + X; JoinOfCoincidentRootLoci * JoinOfCoincidentRootLoci := (X,Y) -> joinOfHooks (toSequence(X#"listCRloci") | toSequence(Y#"listCRloci")); --================================================================ --=== Binary forms and utilities ================================= --================================================================ RingElement ~ := (F) -> RingElement := (G) -> ( if not (isPolynomialRing ring F and isPolynomialRing ring G and numgens ring F == 2 and numgens ring G == 2) then error "expected two binary forms"; K := coefficientRing ring F; if K =!= coefficientRing ring G then error "got different coefficient rings"; (x,y) := (local x,local y); R := K[x,y]; F = sub(F,vars R); G = sub(G,vars R); if not isField K then ( K = frac K; R = K[gens R]; F = sub(F,R); G = sub(G,R); ); if not (isHomogeneous F and isHomogeneous G) then error "expected two binary forms"; ideal F == ideal G ); switch1 = method() switch1 (RingElement) := (p) -> ( checkBinaryForm p; G := ring p; mm := gens (ideal gens G)^(first degree p); c := flatten entries sub(last coefficients(p,Monomials=>mm),coefficientRing G); apply(#c,j -> c_j * (binomial(first degree p,j))^-1) ); switch1 (List) := (l) -> switch1(l,Grass(0,1,ring matrix {l},Variable=>VAR)); switch1 (List,PolynomialRing) := (l,G) -> ( if 2 != numgens G then error "expected polynomial ring with two variables"; K := if isField ring matrix {l} then ring matrix {l} else frac(ring matrix {l}); mm := flatten entries gens (ideal gens G)^(#l-1); F := sum(#l,j -> l_j * mm_j * binomial(#l-1,j)); (Trim ideal F)_0 ); switch2 = method(Options => {Variable => null}) switch2 (Ideal) := o -> (p) -> ( if not (isPolynomialRing ring p and isHomogeneous p) then error "expected a homogeneous ideal in a polynomial ring"; if # unique degrees p > 1 then error "expected an ideal generated by forms of the same degree"; d := first unique degrees p; x := if o.Variable === null then ring p else o.Variable; K := coefficientRing ring p; if d === {1} then ( I := Trim ideal apply(entries transpose coefficients parametrize p,u -> switch1(u,Grass(0,1,K,Variable=>x))); return if numgens I == 1 then I_0 else I; ) else return linearSpanOfRows(matrix apply(p_*,switch1),Grass(0,first d,K,Variable=>x)); ); switch2 (RingElement) := o -> (F) -> switch2(ideal F,Variable=>o.Variable); switch (RingElement) := (F) -> switch1 F; switch (Ideal) := (I) -> switch2 I; switch (List) := (L) -> switch2 switch1 L; pairingIsomorphism = method() pairingIsomorphism (Ring) := (R) -> inverse rationalMap for i to numgens R -1 list binomial(numgens R -1,i) * (gens R)_i; pairingIsomorphism (Ideal) := (I) -> (pairingIsomorphism ring I) I; pairingIsomorphism (ZZ,Ring) := (n,K) -> pairingIsomorphism Grass(0,n,K,Variable=>VAR); randomBinaryForm = method(Options => {Variable => VAR}) randomBinaryForm (ZZ,Thing,Thing,Ring) := o -> (n,RealRank,ComplexRank,K) -> ( try assert (RealRank === null or (ring RealRank === ZZ and RealRank >= 1 and RealRank <= n)) else error("illegal value for argument 2, expected null or integer between 1 and "|toString(n)|", the real rank"); try assert (ComplexRank === null or (ring ComplexRank === ZZ and ComplexRank >= 1 and ComplexRank <= n)) else error("illegal value for argument 3, expected null or integer between 1 and "|toString(n)|", the complex rank"); if n < 0 then error "illegal value for argument 1, expected a nonnegative integer"; if not isField K then error "expected a field"; x := o.Variable; R := Grass(0,1,K,Variable=>x); if RealRank === null and ComplexRank === null then return (Trim ideal random(n,R))_0; if RealRank === null and ComplexRank =!= null then ( if ComplexRank === 1 then return (randomBinaryForm(1,,,K,Variable=>x))^n; return recover(randomBinaryForm(ComplexRank,,,K,Variable=>x),(randomBinaryForm(1,,,K,Variable=>x))^2 * randomBinaryForm(n-ComplexRank,,,K,Variable=>x)); ); if RealRank =!= null and ComplexRank === null then ( if RealRank === 1 then return (randomBinaryForm(1,,,K,Variable=>x))^n; return recover(randomRealRootedBinaryForm(RealRank,K,Variable=>x),randomNotRealRootedBinaryForm(n+2-RealRank,K,Variable=>x)); ); if RealRank =!= null and ComplexRank =!= null then ( if RealRank === 1 and ComplexRank === 1 then return (randomBinaryForm(1,,,K,Variable=>x))^n; if RealRank === ComplexRank then return recover(randomRealRootedBinaryForm(RealRank,K,Variable=>x),(randomBinaryForm(1,,,K,Variable=>x))^2 * randomBinaryForm(n-ComplexRank,,,K,Variable=>x)); if RealRank + ComplexRank == n+2 and ComplexRank <= RealRank then return recover(randomNotRealRootedBinaryForm(ComplexRank,K,Variable=>x),randomRealRootedBinaryForm(RealRank,K,Variable=>x)); error("unable to build a binary form of degree "|toString(n)|", real rank "|toString(RealRank)|" and complex rank "|toString(ComplexRank)); ); ); randomBinaryForm (ZZ,Thing,Thing) := o -> (n,RealRank,ComplexRank) -> randomBinaryForm(n,RealRank,ComplexRank,KK,Variable=>o.Variable); randomBinaryForm (ZZ,Ring) := o -> (n,K) -> randomBinaryForm(n,,,K,Variable=>o.Variable); randomBinaryForm (ZZ) := o -> (n) -> randomBinaryForm(n,KK,Variable=>o.Variable); randomRealRootedBinaryForm = method(Options => {Variable => VAR}) randomRealRootedBinaryForm (ZZ,Ring) := o -> (n,K) -> (Trim ideal product(n,i -> randomBinaryForm(1,,,K,Variable=>o.Variable)))_0; randomNotRealRootedBinaryForm = method(Options => {Variable => VAR}) randomNotRealRootedBinaryForm (ZZ,Ring) := o -> (n,K) -> ( x := o.Variable; q := randomBinaryForm(2,,,K,Variable=>x); while -discriminant q >= 0 do q = randomBinaryForm(2,,,K,Variable=>x); (Trim ideal(q * randomBinaryForm(n-2,,,K,Variable=>x)))_0 ); linearSpanOfRows = method(); linearSpanOfRows (Matrix,Ring) := (M,R) -> ( m := numgens target M -1; u := local u; x := local x; K := coefficientRing R; n := numgens R -1; assert (numgens source M -1 == n and ring M === K); S := K[u_0..u_m,x_0..x_n,MonomialOrder=>Eliminate(m+1)]; I := ideal(matrix{toList(u_0..u_m)} * M - matrix{toList(x_0..x_n)}); Trim sub(sub(ideal selectInSubring(1,gens gb I),K[x_0..x_n]),vars R) ); checkBinaryForm = method() checkBinaryForm (RingElement) := (F) -> ( E := "expected a binary form"; if not (isPolynomialRing ring F and numgens ring F == 2) then error E; K := coefficientRing ring F; if isField K then ( if not isHomogeneous F then error E; ) else ( (x,y) := (local x,local y); R := K[x,y]; F = sub(F,vars R); try assert(isHomogeneous sub(F,(frac K)[x,y])) else error E; ); ); load "./CoincidentRootLoci/documentation.m2" load "./CoincidentRootLoci/tests.m2" welcome := "CoincidentRootLoci v."|CoincidentRootLoci.Options.Version|" loaded successfully (last updated: "|CoincidentRootLoci.Options.Date|")"; if notify then if (options CoincidentRootLoci)#OptionalComponentsPresent then <<concatenate(#welcome:"*")<<endl<<welcome<<endl<<concatenate(#welcome:"*")<<endl else <<"--warning: Qepcad required but not present"<<endl;