Open mahrud opened 3 years ago
When lifting is possible, new method functions are added to lift
and to liftable
. So the criterion is whether a method for doing it is installed.
Why have liftable
then?
Is there a method for automatically doing either lift
or promote
depending on the situation?
Because you might be trying to "lift" a ring element to a subring, which is not always possible, but might be possible.
There is no method that does either lift or promote.
i1 : liftable(2/3,ZZ)
o1 = false
i2 : liftable(4/2,ZZ)
o2 = true
It seems like very poor design:
i1 : liftable(2, QQ)
stdio:1:1:(3): error: no method found for applying lift to:
argument 1 : 2 (of class ZZ)
argument 2 : QQ
Do you expect programmers to check whether a method is installed for two rings in the middle of a mathematical algorithm?
No, I don't expect them to check whether a method is installed. I expect them to know that there is no ring homomorphism from QQ to ZZ.
I expect them to know that there is no ring homomorphism from QQ to ZZ.
That's a useless answer. If you're given a R-module M and some element s in another ring S, how do you implement an algorithm to return s*M, or how do you check whether this is mathematically possible? Do you promote s to R or lift s to R? It doesn't seem mathematical to have to check whether a method is installed for it, so if that's your intention I think this is not a good design.
@mikestillman what would you do in this scenario?
The idea of lift and promote is that when there is a natural ring map A --> B. (e.g. ZZ --> QQ, kk --> kk[x,y,z]/I, etc), and a is in A and b is in B, then lift(b, A) will lift b to an element of A that maps to b, and promote(a, B) will give the image under this natural map. In order to compute ab, one cannot lift the result to A, as that might not make sense. Instead, one does promote(a,B) b. promote will always work, at least for what we (as implementors) thought was a natural map: from coefficient ring to polynomial rings, from polynomial rings to quotients, or fraction fields, etc (and including composites of these). liftable
returns true if it is possible to lift the element.
Perhaps the names could have been chosen better, but that is what we chose. Also, if the documentation doesn't make this clear, we should fix that!
The idea is that this respects the mathematics. If there is a natural map for which it is not installed, that is a bug, not (in my opinion) a bad design.
However, we only consider natural maps, not maps from one ring to another that e.g. have the same names of variables. We also don't automatically construct all such, e.g. I think that if A = ZZ[x], B = ZZ/5[x], I don't think that promote(1_A, B) is defined. It would be nice to add this, but when we create the lift and promote routines (during construction of the ring), we don't know about the other one...
@mahrud Does this answer your question?
Actually, looking at your question again, perhaps that doesn't answer it. In general, in order for aM to make sense, and a is in some ring A, then M must be an A-module. If instead, M is a B-module, one way to get the A-module structure is by the promote mechanism, if there is an obvious A-module structure (obvious is up to interpretation, and implementation). Another is to use a ring map f : A --> B, where M is a B-module. In this case, you need to use f(a) M.
That's right. And if f : A -> B
is a ring homomorphism, M
is an A-module and b
is an element of B, it doesn't make sense to try lifting b to A for the purpose of evaluating b*M, because M need not be a module over the image of f.
I do think it is a bit strange that liftable
would give an error: intuitively I would expect liftable
to be "safe", and would want to use it in an attempt to prevent errors. Why wouldn't liftable
simply return false if no suitable lift is found?
@mahrud: for purposes of pushForward, I was always thinking of lifting from a QuotientRing
to an ambient PolynomialRing
. Do you have an example where this breaks?
I agree with @jchen419 : I think that liftable
should return a boolean. In fact, I'm not sure I realized it didn't do that...
It does:
i19 : liftable(3/2,ZZ)
o19 = false
The error in this case is explained by the rings being inappropriate -- lifting would never be possible:
i20 : liftable(3,QQ)
stdio:20:1:(3): error: no method found for applying lift to:
argument 1 : 3 (of class ZZ)
argument 2 : QQ
Thanks, Mike. I definitely did not get this intuition about how to use lift
and liftable
from their respective documentation nodes.
I do think it is a bit strange that
liftable
would give an error: intuitively I would expectliftable
to be "safe", and would want to use it in an attempt to prevent errors. Why wouldn'tliftable
simply return false if no suitable lift is found?
This is my point exactly. I think this makes programming unsafe in some situations.
A safe alternative (in my opinion), would be to have a function liftable(Ring, Ring)
that always returns a boolean and never an error, such that if liftable(A, B)
is true then:
promote
from A to B is guaranteed to work, and is the same as applying map(B, A)
liftable(b, A)
is guaranteed to return a boolean, and if it is true then:
lift(b, A)
is guaranteed to give an element of A such that promote(a, B) = b
.Notice that checking member(A, B.baseRings)
doesn't do all that I want. The benefit of my suggestion is that it allows users to install a method lift(S/(f), S/(f, g))
even when neither is a base ring of the other, and be able to use lift
and liftable
without risking an error.
Note that methods(lift, ZZ, QQ)
and methods(lift, QQ, ZZ)
return the same thing, so that can't be used to check if lift and promote are defined between them either. The only way I know of is using lookup
, which is too hard for average mathematician.
@mahrud: for purposes of pushForward, I was always thinking of lifting from a
QuotientRing
to an ambientPolynomialRing
. Do you have an example where this breaks?
Yes, this is the situation in almost all examples from CompleteIntersectionResolutions
, where in matrixFactorization
there's a call to push forward across a map S/(f, g) <--- S/(f)
. Mathematically, the target is a quotient of the source, but not from the perspective of lift
.
Basically, when presentation ring of the source and target match and that the presentation of the source is a summand of the presentation of the target, then I think lift
should work even if one ring isn't a base ring of the other.
@mikestillman do you have any thoughts on this part?
Basically, when presentation ring of the A and B match and that the presentation of the A is a summand of the presentation of the B, then I think
lift
should work even if one ring isn't a base ring of the other.
Here is an example:
i1 : S = kk[x,y,z,w];
i2 : A = S/(z^2-y*w);
i3 : use S;
i4 : B = S/(z^2-y*w, y*z-x*w);
i5 : ring presentation A === ring presentation B
o5 = true
i6 : presentation A % presentation B == 0
o6 = true
It's mathematically correct to lift in this case, no?
In particular, isn't this incorrect?
i11 : isQuotientOf(A, B)
o11 = false
I understand the difference between math and programming, but this seems to be a simple improvement. (Also, isQuotientOf
should have a caveat).
What's the procedure for determining whether objects from one ring can be lifted to another ring by Macaulay2? The documentation for
lift
andliftable
seem to be lacking. Here is an example:cc: @jchen419 this seems to break the pushforward routine we wrote a few months back.