Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LeftIdeal (take two) #3020

Open
wants to merge 16 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions M2/Macaulay2/m2/exports.m2
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ export {
"Homogeneous",
"Homogeneous2",
"HorizontalSpace",
"LeftIdeal",
"Ideal",
"IgnoreExampleErrors",
"ImmutableType",
Expand Down
2 changes: 1 addition & 1 deletion M2/Macaulay2/m2/gb.m2
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ degreeToHeft = (R, d) -> (
-----------------------------------------------------------------------------

gb = method(TypicalValue => GroebnerBasis, Options => gbDefaults)
gb Ideal := GroebnerBasis => opts -> I -> gb (module I, opts)
gb LeftIdeal := GroebnerBasis => opts -> I -> gb (module I, opts)
gb Module := GroebnerBasis => opts -> M -> (
if M.?relations then (
if not M.cache#?"full gens" then M.cache#"full gens" = generators M | relations M;
Expand Down
12 changes: 6 additions & 6 deletions M2/Macaulay2/m2/intersect.m2
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ moduleIntersectOpts := {
}

-- ideally this should be unnecessary, but some code seems to depend on this
intersect Ideal := Ideal => idealIntersectOpts >> opts -> I -> doTrim(opts, I)
intersect LeftIdeal := LeftIdeal => idealIntersectOpts >> opts -> I -> doTrim(opts, I)
intersect Module := Module => moduleIntersectOpts >> opts -> M -> doTrim(opts, M)

-- intersect is a MethodFunctionBinary, so arbitrary lists
Expand All @@ -77,12 +77,12 @@ intersect Module := Module => moduleIntersectOpts >> opts -> M -> doTrim(opts, M
-- installing a method (intersect, S, T) => T enables intersect(S, T, T, ...)
-- installing a method (intersect, S, S) => S enables intersect(S, S, T, T, ...)
-- installing a method (intersect, T, S) => S enables intersect(S, T, S, T, ...)
intersect(Ideal, Ideal) := Ideal => idealIntersectOpts >> opts -> L -> intersectHelper(L, (intersect, Ideal, Ideal), opts)
intersect(LeftIdeal, LeftIdeal) := LeftIdeal => idealIntersectOpts >> opts -> L -> intersectHelper(L, (intersect, LeftIdeal, LeftIdeal), opts)
intersect(Module, Module) := Module => moduleIntersectOpts >> opts -> L -> intersectHelper(L, (intersect, Module, Module), opts)

-- Specializations for intersecting many objects at once, e.g. Modules,
-- can be installed on (symbol intersect, T), which calls T.intersect
Ideal.intersect = idealIntersectOpts >> opts -> L -> intersectHelper(L, (intersect, Ideal, Ideal), opts)
LeftIdeal.intersect = idealIntersectOpts >> opts -> L -> intersectHelper(L, (intersect, LeftIdeal, LeftIdeal), opts)
Module.intersect = moduleIntersectOpts >> opts -> L -> intersectHelper(L, (intersect, Module, Module), opts)

-----------------------------------------------------------------------------
Expand Down Expand Up @@ -112,7 +112,7 @@ scan({Default}, strategy ->

-----------------------------------------------------------------------------

algorithms#(intersect, Ideal, Ideal) = new MutableHashTable from {
algorithms#(intersect, LeftIdeal, LeftIdeal) = new MutableHashTable from {
Default => (opts, L) -> ideal intersect(opts, apply(L, module)),

-- TODO: can this be extended to do more than 2 at once?
Expand Down Expand Up @@ -145,6 +145,6 @@ algorithms#(intersect, Ideal, Ideal) = new MutableHashTable from {
newMonomialIdeal(R, rawIntersect(raw monomialIdeal I, raw monomialIdeal J)))),
}

-- Installing hooks for intersect(Ideal, Ideal)
-- Installing hooks for intersect(LeftIdeal, LeftIdeal)
scan({Default, "Elimination", Monomial}, strategy ->
addHook(key := (intersect, Ideal, Ideal), algorithms#key#strategy, Strategy => strategy))
addHook(key := (intersect, LeftIdeal, LeftIdeal), algorithms#key#strategy, Strategy => strategy))
157 changes: 105 additions & 52 deletions M2/Macaulay2/m2/matrix1.m2
Original file line number Diff line number Diff line change
Expand Up @@ -427,50 +427,59 @@ cokernel Matrix := Module => m -> (
cokernel RingElement := Module => f -> cokernel matrix {{f}}
image RingElement := Module => f -> image matrix {{f}}

Ideal = new Type of HashTable
LeftIdeal = new Type of HashTable
Ideal = new Type of LeftIdeal
Ideal.synonym = "ideal"

ideal = method(Dispatch => Thing, TypicalValue => Ideal)
ideal Ideal := identity

expression Ideal := (I) -> (expression ideal) unsequence apply(toSequence first entries generators I, expression)
net Ideal := (I) -> net expression I
toString Ideal := (I) -> toString expression I
toExternalString Ideal := (I) -> "ideal " | toExternalString generators I
texMath Ideal := (I) -> texMath expression I
expression LeftIdeal := (I) -> (expression ideal) unsequence apply(toSequence first entries generators I, expression)
net LeftIdeal := (I) -> net expression I
toString LeftIdeal := (I) -> toString expression I
toExternalString LeftIdeal := (I) -> "ideal " | toExternalString generators I
texMath LeftIdeal := (I) -> texMath expression I

isIdeal Ideal := I -> true
isHomogeneous Ideal := (I) -> isHomogeneous generators I
isIdeal LeftIdeal := I -> true
isHomogeneous LeftIdeal := (I) -> isHomogeneous generators I

degrees LeftIdeal := I -> degrees source generators I
-- TODO: deprecate these
degreeLength LeftIdeal := I -> degreeLength ring I
degreesRing LeftIdeal := I -> degreesRing ring I
-* should we keep this only for Ideal?
degrees Ideal := I -> degrees source generators I
*-

promote(Ideal,Number) :=
promote(Ideal,RingElement) := (I,R) -> ideal promote(generators I, R)
promote(LeftIdeal,Number) :=
promote(LeftIdeal,RingElement) := (I,R) -> ideal promote(generators I, R)

comodule Module := Module => M -> cokernel super map(M,M,1)
quotient Module := Module => opts -> M -> comodule M
comodule Ideal := Module => I -> cokernel generators I
quotient Ideal := Module => opts -> I -> (ring I) / I
module Ideal := Module => (cacheValue symbol module) (I -> image generators I)
comodule LeftIdeal := Module => I -> cokernel generators I
quotient LeftIdeal := Module => opts -> I -> (ring I) / I
module LeftIdeal := Module => (cacheValue symbol module) (I -> image generators I)

genera Ideal := (I) -> genera ((ring I)^1/I)
genus Ideal := (I) -> genus ((ring I)^1/I)
genera LeftIdeal := I -> genera ((ring I)^1/I)
genus LeftIdeal := I -> genus ((ring I)^1/I)

eulers(Ideal) := (I) -> eulers((ring I)^1/I)
euler(Ideal) := (I) -> euler((ring I)^1/I)
eulers LeftIdeal := I -> eulers((ring I)^1/I)
euler LeftIdeal := I -> euler((ring I)^1/I)

-- two-sided ideal expected
RingElement * Ideal := Ideal => (r,I) -> ideal (r ** generators I)
Ideal * RingElement := Ideal => (I,r) -> ideal ((generators I)**r)
LeftIdeal * RingElement := Ideal => (I,r) -> ideal ((generators I)*r) -- staying away from **
ZZ * Ideal := (r,I) -> ideal (r * generators I)
Ideal * ZZ := (I,r) -> ideal (r * generators I)

generators Ideal := Matrix => opts -> (I) -> I.generators
Ideal_* := I -> first entries generators I
Ideal / Function := List => (I,f) -> apply(flatten entries generators I, f)
Function \ Ideal := List => (f,I) -> apply(flatten entries generators I, f)
generators LeftIdeal := Matrix => opts -> (I) -> I.generators
LeftIdeal_* := I -> first entries generators I
LeftIdeal / Function := List => (I,f) -> apply(flatten entries generators I, f)
Function \ LeftIdeal := List => (f,I) -> apply(flatten entries generators I, f)

generator = method()
generator Ideal := RingElement => (I) -> (
generator LeftIdeal := RingElement => I -> (
if I.cache.?trim then I = I.cache.trim;
R := ring I;
n := numgens I;
Expand All @@ -492,18 +501,41 @@ generator Module := RingElement => (M) -> (
if n == 1 then return M_0;
error "expected ideal to have a single generator")

Ideal / Ideal := Module => (I,J) -> module I / module J
LeftIdeal / LeftIdeal := Module => (I,J) -> module I / module J

-- two-sided ideal expected
Module / Ideal := Module => (M,J) -> M / (J * M)

Ideal#AfterPrint = Ideal#AfterNoPrint = (I) -> (Ideal," of ",ring I)
-- This function exist because there is a lot of user (package?) code
-- where `R^1/I` means R/I as a _left_ R-module and, in non-commutative setting,
-- (however, R^1 is a currently a right module over R^{op}).
-- It is never used for `M/I` where M is not `R^1`.
Module / LeftIdeal := Module => (M,J) -> (
if isFreeModule M and rank M == 1
then comodule J
else "not defined for a left ideal (in general)"
)

LeftIdeal#AfterPrint = LeftIdeal#AfterNoPrint = I -> (LeftIdeal," of ",ring I)
Ideal#AfterPrint = Ideal#AfterNoPrint = I -> (Ideal," of ",ring I)

-- two-sided ideal expected
Ideal ^ ZZ := Ideal => (I,n) -> ideal symmetricPower(n,generators I)
Ideal * Ideal := Ideal => ((I,J) -> ideal flatten (generators I ** generators J)) @@ samering
Ideal * Module := Module => ((I,M) -> subquotient (generators I ** generators M, relations M)) @@ samering
Ideal + Ideal := Ideal => ((I,J) -> ideal (generators I | generators J)) @@ tosamering
Ideal + RingElement := Ideal + Number := ((I,r) -> I + ideal r) @@ tosamering
RingElement + Ideal := Number + Ideal := ((r,I) -> ideal r + I) @@ tosamering
Ideal _ ZZ := RingElement => (I,n) -> (generators I)_(0,n)

LeftIdeal + LeftIdeal := LeftIdeal => ((I,J) -> ideal (generators I | generators J)) @@ tosamering
-- Ideal + Ideal := Ideal => ((I,J) -> ideal (generators I | generators J)) @@ tosamering
LeftIdeal + RingElement := LeftIdeal + Number := ((I,r) -> I + ideal r) @@ tosamering
RingElement + LeftIdeal := Number + LeftIdeal := ((r,I) -> ideal r + I) @@ tosamering
LeftIdeal _ ZZ := RingElement => (I,n) -> (generators I)_(0,n)


-- Matrix % Ideal is a convenience function... and so is Matrix % LeftIdeal
-- the result of the latter has even less (natural) meaning as a map (on a one-sided module)
Matrix % LeftIdeal := Matrix => ((f,I) -> map(target f, source f, apply(entries f, row -> matrix row % gb I))) @@ samering

-- two-sided ideal expected (note: R/I is a problem !!!)
Matrix % Ideal := Matrix => ((f,I) ->
if numRows f === 1
then f % gb I
Expand All @@ -513,23 +545,35 @@ Matrix % Ideal := Matrix => ((f,I) ->
S := R/I;
lift(promote(f,S),R))
) @@ samering

Vector % Ideal := (v,I) -> new class v from {v#0%I}
numgens Ideal := (I) -> numgens source generators I
leadTerm Ideal := Ideal => (I) -> ideal leadTerm gb I
leadTerm(ZZ,Ideal) := Matrix => (n,I) -> ideal leadTerm(n,gb I)
jacobian Ideal := Matrix => (I) -> jacobian generators I
Ideal _ List := (I,w) -> (module I)_w

ring Ideal := (I) -> I.ring
Vector % LeftIdeal := (v,I) -> new class v from {v#0%I}

numgens LeftIdeal := I -> numgens source generators I
leadTerm LeftIdeal := Matrix => I -> leadTerm generators gb I
leadTerm(ZZ,LeftIdeal) := Matrix => (n,I) -> leadTerm(n,generators gb I)

-- two-sided ideal expected (unless defined for non-polynomial rings!!!)
jacobian Ideal := Matrix => I -> jacobian generators I

LeftIdeal _ List := (I,w) -> (module I)_w

Ideal == Ring := (I,R) -> (
ring LeftIdeal := I -> I.ring

LeftIdeal == Ring := (I,R) -> (
if ring I =!= R
then error "expected ideal in the given ring";
1_R % I == 0)

Ring == Ideal := (R,I) -> I == R
Ring == LeftIdeal := (R,I) -> I == R

Ideal == Ideal := (I,J) -> (
LeftIdeal == LeftIdeal := (I,J) -> (
samering(I,J);
( generators I == generators J or
-- if isHomogeneous I and isHomogeneous J -- can be removed later
Expand All @@ -538,14 +582,14 @@ Ideal == Ideal := (I,J) -> (
isSubset(I,J) and isSubset(J,I) -- can be removed later
))

Ideal == Module := (I,M) -> module I == M
Module == Ideal := (M,I) -> M == module I
LeftIdeal == Module := (I,M) -> module I == M
Module == LeftIdeal := (M,I) -> M == module I

isSubset(Module, Ideal) :=
isSubset(Ideal, Module) :=
isSubset(Ideal, Ideal) := (I, J) -> isSubset(module I, module J)
isSubset(LeftIdeal,LeftIdeal) := (I,J) -> isSubset(module I, module J)
isSubset(Module,LeftIdeal) := (M,J) -> isSubset(M, module J)
isSubset(LeftIdeal,Module) := (I,N) -> isSubset(module I, N)

ideal Matrix := Ideal => (f) -> (
ideal Matrix := LeftIdeal => f -> (
R := ring f;
if not isFreeModule target f or not isFreeModule source f
then error "expected map between free modules";
Expand All @@ -558,22 +602,30 @@ ideal Matrix := Ideal => (f) -> (
g := map(R^1,,f); -- in case the degrees are wrong
if isHomogeneous g then f = g;
);
new Ideal from { symbol generators => f, symbol ring => R, symbol cache => new CacheTable } )

ideal Module := Ideal => M -> if isIdeal M then ideal generators M else (
error "expected a submodule of a free module of rank 1")
new (
-- Ideal == two-sided ideal
if isWeylAlgebra R then LeftIdeal
else Ideal
) from { symbol generators => f, symbol ring => R, symbol cache => new CacheTable } )

ideal Module := LeftIdeal => M -> (
F := ambient M;
if isSubmodule M and rank F === 1 then ideal generators M
else error "expected a submodule of a free module of rank 1"
)

idealPrepare = method()
idealPrepare RingElement :=
idealPrepare Number := identity
idealPrepare Matrix := m -> flatten entries m
idealPrepare Ideal := I -> I_*
idealPrepare LeftIdeal := I -> I_*
idealPrepare Thing := x -> error "expected a list of numbers, matrices, ring elements or ideals"
ideal List := ideal Sequence := Ideal => v -> ideal matrix {flatten apply(toList splice v,idealPrepare)}
ideal RingElement := ideal Number := Ideal => v -> ideal {v}
ideal List := ideal Sequence := LeftIdeal => v -> ideal matrix {flatten apply(toList splice v,idealPrepare)}
ideal RingElement := ideal Number := LeftIdeal => v -> ideal {v}
ideal Ring := R -> ideal map(R^1,R^0,0)

Ideal ^ Array := (I, e) -> (
-- not well-defined (mathwise!!!)
Ideal ^ Array := (I, e) -> (
R := ring I;
n := numgens R;
-- Error if input is not correct.
Expand Down Expand Up @@ -642,7 +694,7 @@ degree Matrix := List => (f) -> (
if N.?generators then d = d + getshift N.generators;
d)

super(Matrix) := Matrix => (f) -> (
super Matrix := Matrix => (f) -> (
M := target f;
if M.?generators then map(super M, M, M.generators) * f
else f
Expand All @@ -651,18 +703,19 @@ super(Matrix) := Matrix => (f) -> (
isInjective Matrix := (f) -> kernel f == 0
isSurjective Matrix := (f) -> cokernel f == 0

-- AL: `**` may cause problems in the noncommutative case
scan({ZZ,QQ}, S -> (
lift(Ideal,S) := opts -> (I,S) -> (
lift(LeftIdeal,S) := opts -> (I,S) -> (
-- this will be pretty slow
if ring I === S then I
else (ideal lift(generators I,S,opts)) + ideal (presentation ring I ** S))));

content(RingElement) := Ideal => (f) -> ideal \\ last \ listForm f
content(RingElement, RingElement) := Ideal => (f,x) -> ideal last coefficients(f, Variables => {x})
content RingElement := LeftIdeal => f -> ideal \\ last \ listForm f
content(RingElement, RingElement) := LeftIdeal => (f,x) -> ideal last coefficients(f, Variables => {x})

cover(Matrix) := Matrix => (f) -> matrix f
cover Matrix := Matrix => f -> matrix f

rank Matrix := (f) -> (
rank Matrix := f -> (
if hasEngineLinearAlgebra ring f and isBasicMatrix f
then basicRank f
else rank image f
Expand Down
19 changes: 10 additions & 9 deletions M2/Macaulay2/m2/matrix2.m2
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,13 @@ complement Matrix := Matrix => (f) -> (
else if instance(R,QuotientRing) then map(target f,,R ** complement lift(f,ambient R))
else error "complement: expected matrix over affine ring or finitely generated ZZ-algebra")


-----------------------------------------------------------------------------
-- mingens and trim
-----------------------------------------------------------------------------

-- the method is declared in gb.m2
mingens LeftIdeal := Matrix => opts -> I -> mingens(module I, opts)
-- TODO: the strategies should be separated
mingens Ideal := Matrix => opts -> I -> mingens(module I, opts)
mingens Module := Matrix => opts -> M -> if isFreeModule M then generators M else cacheHooks(
symbol mingens, M, (mingens, Module), (opts, M), (opts, M) -> (
if opts.Strategy === null then opts = opts ++ { Strategy => Complement };
Expand Down Expand Up @@ -170,8 +170,8 @@ trim = method (Options => { Strategy => null -* TODO: add DegreeLimit => {} *-})
trim Ring := Ring => o -> identity
trim QuotientRing := Ring => o -> R -> quotient trim(ideal presentation R, o)

-- TODO: the strategies should be separated
trim Ideal := Ideal => opts -> I -> ideal trim(module I, opts)
trim LeftIdeal := LeftIdeal => opts -> I -> ideal trim(module I, opts)
-- old or new version???: trim LeftIdeal := LeftIdeal => opts -> (cacheValue (symbol trim => opts)) ((I) -> ideal trim(module I, opts))
trim Module := Module => opts -> M -> if isFreeModule M then M else cacheHooks(
(symbol trim, opts), M, (trim, Module), (opts, M), (opts, M) -> (
if opts.Strategy === null then opts = opts ++ { Strategy => Complement };
Expand Down Expand Up @@ -399,12 +399,12 @@ RingElement % Matrix := (r,f) -> (
else error "expected target of matrix to be free, and of rank 1"
)

RingElement % Ideal := (r,I) -> (
RingElement % LeftIdeal := (r,I) -> (
R := ring I;
if ring r =!= R then error "expected ring element and ideal for the same ring";
if r == 0 then return r;
r % if isHomogeneous I and heft R =!= null then gb(I, DegreeLimit => degree r) else gb I)
Number % Ideal := (r,I) -> (
Number % LeftIdeal := (r,I) -> (
R := ring I;
r = promote(r,R);
if r == 0 then return r;
Expand Down Expand Up @@ -434,7 +434,8 @@ indices Matrix := (f) -> rawIndices raw f
support = method()
support RingElement :=
support Matrix := f -> apply(try rawIndices raw f else {}, i -> (ring f)_i)
support Ideal := I -> support generators I
support LeftIdeal := I -> support generators I

--------------------
-- homogenization --
--------------------
Expand Down Expand Up @@ -482,7 +483,7 @@ homogenize(Module,RingElement) := Module => (M,z) -> (
if M.?generators then homogenize(generators gb M.generators,z),
if M.?relations then homogenize(generators gb M.relations,z)))

homogenize(Ideal,RingElement) := Ideal => (I,z) -> ideal homogenize(module I, z)
homogenize(LeftIdeal,RingElement) := LeftIdeal => (I,z) -> ideal homogenize(module I, z)

homogenize(Module,RingElement,List) := Module => (M,z,wts) -> (
if isFreeModule M then M
Expand Down Expand Up @@ -673,7 +674,7 @@ newCoordinateSystem(PolynomialRing, Matrix) := (S,x) -> (
( map(S,R,vars S * toS n), map(R,S,vars R * n^(-1)) )
)

lift(Ideal,RingElement) := Ideal => opts -> (I,S) -> (
lift(LeftIdeal,RingElement) := Ideal => opts -> (I,S) -> (
-- provisional, just for quotient rings
T := ring I;
if T === S then I
Expand Down
Loading
Loading