Skip to content

Expanded Reflexive strategy of Matrix // Matrix #3920

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

Open
wants to merge 5 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
15 changes: 12 additions & 3 deletions M2/Macaulay2/m2/matrix2.m2
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ Matrix \\ Matrix := Matrix => (g, f) -> quotient'(f, g)
quotient(Matrix, Matrix) := Matrix => opts -> (f, g) -> (
-- given f: A-->C and g: B-->C, then find (f//g): A-->B such that g o (f//g) + r = f
if target f != target g then error "quotient: expected maps with the same target";
if f == 0 then return map(source g, source f, 0);
c := runHooks((quotient, Matrix, Matrix), (opts, f, g), Strategy => opts.Strategy);
if c =!= null then c else error "quotient: no method implemented for this type of input")

Expand All @@ -408,11 +409,19 @@ addHook((quotient, Matrix, Matrix), Strategy => Default,
MinimalGenerators => opts.MinimalGenerators };
map(source g, source f, homomorphism(homomorphism'(f, opts) // Hom(source f, g, opts)))))

-- FIXME: this is still causing unreasonable slow downs, e.g. for (large m) // (scalar)
addHook((quotient, Matrix, Matrix), Strategy => "Reflexive", (opts, f, g) -> if f == 0 or isFreeModule source f then (
L := source f; -- result may not be well-defined if L is not free
addHook((quotient, Matrix, Matrix), Strategy => "Reflexive", (opts, f, g) -> (
L := source f;
M := target f;
N := source g;
-- TODO: should this be a separate strategy?
if not isFreeModule L then return (
-- result may not be well-defined if L is not free,
-- unless the composition h * syz p is zero
p := coverMap L;
h := quotient(f * p, g, Strategy => "Reflexive");
-- TODO: does h * gens ker p != 0 suffice?
if h * inducedMap(source p, kernel p) == 0 then map(N, L, h));
--
if M.?generators then (
M = cokernel presentation M; -- this doesn't change the cover
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ Node
reduction of @TT "f"@ modulo a Gröbner basis for the image of @TT "dual g"@.
See @TO quotient@ for the dual notion.

If the remainder @TT "f - h*g"@ is zero, then the quotient @TT "g\\f"@
satisfies the equation @TT "f === (g\\f) * g"@. Otherwise, the equation
If the remainder @TT "f - h*g"@ is zero, then the quotient @TT "g\\\\f"@
satisfies the equation @TT "f === (g\\\\f) * g"@. Otherwise, the equation
@TT "h * g + r === f"@ will hold, where @TT "r"@ is the map provided by
@TO remainder'@.
Example
Expand Down
7 changes: 6 additions & 1 deletion M2/Macaulay2/packages/Macaulay2Doc/ov_system.m2
Original file line number Diff line number Diff line change
Expand Up @@ -1870,7 +1870,12 @@ document { Key => "loadedFiles",
PARA { "After each source file is successfully loaded, the full path to the file is stored in the hash table ", TO "loadedFiles", ". It is stored as the
value, with the corresponding key being a small integer, consecutively assigned, starting at 0."
},
EXAMPLE "peek loadedFiles"}
EXAMPLE lines ///
loadedFiles#0
#loadedFiles
///,
--SeeAlso => { "filesLoaded" },
}

document { Key => "homeDirectory",
Headline => "the home directory of the user",
Expand Down
114 changes: 114 additions & 0 deletions M2/Macaulay2/tests/normal/quotient.m2
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,117 @@ assert(f \\ h == g)
assert((f\\h) * f == h)
assert(g // h == 0) -- does it always happen that this is zero if lift can't occur? Probably not
assert(h \\ f == 0)


-- tests which show that the "Reflexive" strategy doesn't always work
S = QQ[x_0,x_1,x_2] --/ sum(3, i -> x_i^3)
a = x_0 + x_1
b = x_0^2-x_0*x_1+x_1^2
A = matrix {{x_2, a}, {b, -x_2^2}}
B = matrix {{x_2^2, a}, {b, -x_2}}

f = map(S^2 / a, S^2 / a, A * B)
f' = map(S^2 / a, S^2, A * B)
g = map(S^2 / a, S^2, A)
h = map(S^2 / a, S^2 / a, B)
assert all({f', f, g, h}, isWellDefined)

-- f does not factor through g without a remainder
assert not isSubset(image homomorphism' f, image Hom(source f, g))

-- here is the example
q = f // g
assert(isWellDefined q and q == 0)

q = quotient(f, g, Strategy => Default)
assert(isWellDefined q and q == 0)

-- the Reflexive strategy is not applicable here
assert try ( quotient(f, g, Strategy => "Reflexive"); false ) else true

-- but f' does (left) factor through g
assert isSubset(image homomorphism' f, image Hom(g, target f))

q = g \\ f'
assert isWellDefined q
assert(f' == q * g)
assert(h == q)

q = quotient'(f', g, Strategy => Default)
assert isWellDefined q
assert(f' == q * g)
assert(h == q)

assert try ( quotient'(f', g, Strategy => "Reflexive"); false ) else true


-- this is an example where the improved "Reflexive" strategy works
f = homomorphism random Hom(image(A | B), S^2)
g = homomorphism random Hom(image(B | A), S^2)
h = homomorphism random Hom(image(A | B), image(B | A))
f = g * h
assert all({f, g}, isWellDefined)

-- f factors through g without a remainder
assert isSubset(image homomorphism' f, image Hom(source f, g))

-- here is the example
q = f // g
assert(isWellDefined q and f == g * q)

q = quotient(f, g, Strategy => Default)
assert(isWellDefined q and f == g * q)


-- this is an example where the improved "Reflexive" strategy works
R = ZZ/2[x,y,z,w]
g = matrix {{x, x+y+z}, {x+y+z, z}}
f = g * matrix {{y^2}, {z^2}}
f = inducedMap(target f / (x+y+z), source f / (x+y+z), f)
g = inducedMap(target g / (x+y+z), source g, g)
isWellDefined f
isWellDefined g

-- f does not factor through g without a remainder
assert not isSubset(image homomorphism' f, image Hom(source f, g))

q = quotient(f, g, Strategy => Default)
assert(isWellDefined q and q == 0)

assert try ( quotient(f, g, Strategy => "Reflexive"); false ) else true

----
clearAll
B = QQ[a..d]
f = prune map(B^1, image(map(B^{{-2}, 3:{-3}}, B^{{-3}, 3:{-4}, {-3}, 3:{-4}, {-3}, 3:{-4}, {-3}, 3:{-4}}, {{a, 0, 0, 0, b, 0, 0, 0, c, 0, 0, 0, d, 0, 0, 0}, {0, a, 0, 0, 0, b, 0, 0, 0, c, 0, 0, 0, d, 0, 0}, {0, 0, a, 0, 0, 0, b, 0, 0, 0, c, 0, 0, 0, d, 0}, {0, 0, 0, a, 0, 0, 0, b, 0, 0, 0, c, 0, 0, 0, d}})),{{a*b*c-a^2*d, a*b^3-a^3*c, a^2*c^2-a*b^2*d, a*c^3-a*b*d^2, b^2*c-a*b*d, b^4-a^2*b*c, a*b*c^2-b^3*d, b*c^3-b^2*d^2, b*c^2-a*c*d, b^3*c-a^2*c^2, a*c^3-b^2*c*d, c^4-b*c*d^2, b*c*d-a*d^2, b^3*d-a^2*c*d, a*c^2*d-b^2*d^2, c^3*d-b*d^3}})
g = prune map(B^1, image(map(B^1, B^{4:{-1}}, {{a, b, c, d}})), {{a, b, c, d}})
assert isSubset(image homomorphism' f, image Hom(source f, g))
elapsedTime assert(f == g * quotient(f, g, Strategy => Default))
elapsedTime assert(f == g * quotient(f, g, Strategy => "Reflexive"))

----
S = QQ[x]
f = random(S^1/x, S^1/x^3)
g = random(S^1/x, S^1/x^2)
elapsedTime assert(f == g * quotient(f, g, Strategy => Default))
elapsedTime assert(f == g * quotient(f, g, Strategy => "Reflexive"))

----
S = QQ[x,y];
M = coker matrix {{x,y},{-y,x}};
g = random(M, M)
f = g * random(M, M)
q = quotient(f, g, Strategy => "Reflexive")
assert(isWellDefined q and f == g * q)

----
S = QQ[x,y,z]
M = S^{-2}
N = S^{-3}
P = truncate(3, S^1)
h = homomorphism random(3, Hom(P, N))
g = homomorphism random(0, Hom(N, M))
f = g * h
assert all({f, g, h}, isWellDefined)
q = quotient(f, g, Strategy => "Reflexive")
assert(isWellDefined q and f == g * q)
2 changes: 1 addition & 1 deletion M2/cmake/build-libraries.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ ExternalProject_Add(build-msolve
TEST_EXCLUDE_FROM_MAIN ON
STEP_TARGETS install test
)
_ADD_COMPONENT_DEPENDENCY(programs msolve "gmp;mpfr;flint" MSOLVE_FOUND)
_ADD_COMPONENT_DEPENDENCY(programs msolve "gmp;mpfr;flint" MSOLVE)


# https://numpi.dm.unipi.it/software/mpsolve
Expand Down
Loading