Let C be a category. If I understand correctly, "A in C" tells whether
A is an object of C. But how does one test whether A is a morphism in
C?
Currently, we have
sage: R.<x,y,z> = ZZ[]
sage: f = R.hom([x^2,y^2,z^2])
sage: C = R.category()
sage: f in C
False
sage: f in C.hom_category()
True
It seems to me that the last line is not correct (and perhaps I have
to apologize, because it is possible that I was responsible for it -
but I'm not sure). Namely, the objects of C.hom_category() are homsets
of C - f is *contained* in a homset of C, but it is of course not a
homset, itself.
What should be the "official" way to test whether f is a morphism in
C? Of course, in that particular example, one has f.category_for(),
but I think in general one should better test
parent(f) in C.hom_category()
, right?
I ask for the following reason:
An group action of G on a set S can be thought of as a morphism from
Groupoid(G) to Sets(). An element g of G is a morphism in the category
Groupoid(G), but of course there is no attribute g.category_for(). But
"parent(g) in Groupoid(G).hom_category()" (which is not implemented,
yet) would make sense, wouldn't it?
On Wed, Dec 29, 2010 at 07:53:25AM -0800, Simon King wrote: > Let C be a category. If I understand correctly, "A in C" tells > whether A is an object of C.
Yep.
> But how does one test whether A is a morphism in C?
As far as I know, no idiom has been yet chosen for this feature. There should be one.
> Currently, we have > sage: R.<x,y,z> = ZZ[] > sage: f = R.hom([x^2,y^2,z^2]) > sage: C = R.category() > sage: f in C > False > sage: f in C.hom_category() > True
> It seems to me that the last line is not correct (and perhaps I have > to apologize, because it is possible that I was responsible for it - > but I'm not sure). Namely, the objects of C.hom_category() are homsets > of C - f is *contained* in a homset of C, but it is of course not a > homset, itself.
Agreed.
> What should be the "official" way to test whether f is a morphism in > C?
Maybe ``f in C.morphisms()'' ? I'll use it in the examples below, but that's just a suggestion among others.
> Of course, in that particular example, one has f.category_for(), > but I think in general one should better test > parent(f) in C.hom_category() > , right?
I am not sure. Assume f is a QQ-algebra morphism. Then, we should have:
sage: f in Algebras(QQ).morphisms() True
We could also choose to have:
sage: f in VectorSpaces(QQ).morphisms() True
which is both natural and possibly practical (though this means implicitly applying a forgetful functor).
But we can't go this way using ``parent(f)``:
sage: parent(f) Homsets from A to B in category of Algebras(QQ)
since the later is certainly not a homset in the category of VectorSpaces(QQ) (e.g. the sum of two algebras morphisms is not an algebra morphism).
By the way: recall that, as advertised in the category roadmap, the hierarchy of categories for homsets is currently mathematically incorrect (Hom is not a covariant functionrial construction as is currently implemented). A typical consequence is:
sage: V = SymmetricFunctions(QQ) # An algebra(QQ) sage: H = Hom(V,V) sage: H.category() Join of Category of hom sets in Category of modules over Rational Field and Category of hom sets in Category of rings
I take the blame for that. And this probably needs to be fixed before further serious cleanup around homsets.
> I ask for the following reason:
> An group action of G on a set S can be thought of as a morphism from > Groupoid(G) to Sets(). An element g of G is a morphism in the category > Groupoid(G), but of course there is no attribute g.category_for(). But > "parent(g) in Groupoid(G).hom_category()" (which is not implemented, > yet) would make sense, wouldn't it?
Hmm, it's too late for me to have a clear idea right now :-)
On 29 Dez., 22:59, "Nicolas M. Thiery" <Nicolas.Thi...@u-psud.fr>
wrote:
> > What should be the "official" way to test whether f is a morphism in
> > C?
> Maybe ``f in C.morphisms()'' ? I'll use it in the examples below, but
> that's just a suggestion among others.
The disadvantage would be that one needed to implement yet another
parent structure for C.morphisms(), namely the union of all homsets of
C.
What about ``C.is_morphism(f)", and for the sake of symmetry also
``C.is_object(A)" as a synonyme for "A in C"?
> By the way: recall that, as advertised in the category roadmap, the
> hierarchy of categories for homsets is currently mathematically
> incorrect ... And this probably needs to be fixed before
> further serious cleanup around homsets.
I do think that implementing a framework for "containment in a
homset" (aka "is f a morphism in C") is possible and worth-while even
without a thorough cleanup: For "proper" morphisms, we have the
method "f.category_for()", so that the functionality
"C.is_morphism(f)" (or whatever syntax) is easy to implement on top of
it - and it should then also be easy to treat the special case
"C=Groupoid(G)", like
{{{
def is_morphism(self, f):
return f in self.__G
}}}
for Groupoids, and generically
{{{
def is_morphism(self, f):
try:
C = f.category_for()
except AttributeError:
return False
return C.is_subcategory(self)
On Dec 29, 8:49 pm, Simon King <simon.k...@uni-jena.de> wrote:
> > > What should be the "official" way to test whether f is a morphism in
> > > C?
I think "f in C" should return True, and that this should be the
"official" way of testing: it has the advantages of being compatible
with the way sage tests membership of other things, and being
mathematically accurate.
> What about ``C.is_morphism(f)", and for the sake of symmetry also
> ``C.is_object(A)" as a synonyme for "A in C"?
This was my second thought, and I think both is_morphism and is_object
should be added, they should test for membership, and test
additionally whether the input is an object or a morphism (e.g., for
morphisms, test for existence of domain & codomain methods, and
whether they return objects of the category). Perhaps the cleanest
way to code would be to move the bulk of the code for "A in C" to a
new "is_object" method, write an "is_morphism" method, and then have
"x in C" return the truth value of "C.is_object(x) or
C.is_morphism(x)".
Also, should "C.is_morphism" be "C.has_morphism" (and similarly for
"is_object") instead? In most of the rest of sage, the .is_ methods
take no argument and apply to "self" (e.g. is_finite, is_commutative,
is_noetherian, etc.). Perhaps "C.contains_morphism" is clearest of
all . . . other ideas?
Although I'm in favor of the categories cleanup, this could, I think,
be independent of it.
On 30 Dez., 16:33, Niles <nil...@gmail.com> wrote:
> my 2 cents:
> On Dec 29, 8:49 pm, Simon King <simon.k...@uni-jena.de> wrote:
> > > > What should be the "official" way to test whether f is a morphism in
> > > > C?
> I think "f in C" should return True, and that this should be the
> "official" way of testing: it has the advantages of being compatible
> with the way sage tests membership of other things, and being
> mathematically accurate.
I wouldn't agree here.
For example, 1 is an element of ZZ and ZZ is an object in Rings(), but
certainly we only want "ZZ in Rings()", not "1 in Rings()". And
similarly, a ring homomorphism f from ZZ to QQ['x'] is contained in
Hom(ZZ,QQ['x']), which is a homset in Rings() (or an object in
Rings().hom_category()) -- so, we may consider to have
"Hom(ZZ,QQ['x']) in Rings()" (however, I wouldn't like that!), but
certainly we don't want f in Rings().
> Also, should "C.is_morphism" be "C.has_morphism" (and similarly for
> "is_object") instead? In most of the rest of sage, the .is_ methods
> take no argument and apply to "self" (e.g. is_finite, is_commutative,
> is_noetherian, etc.). Perhaps "C.contains_morphism" is clearest of
> all . . . other ideas?
Yes, C.has_morphism(f) sounds better than C.is_morphism(f) (also from
a grammatical point of view). And it is shorter than
C.contains_morphism(f).
So, I am "+1" to C.has_morphism(f)
> Although I'm in favor of the categories cleanup, this could, I think,
> be independent of it.
Yes, I think the functionality should be fairly straight forward to
implement, regardless of category cleanup.
I am already doing doctests, so, probably I'll soon open a ticket.
On 30 Dez., 17:30, Simon King <simon.k...@uni-jena.de> wrote:
> I am already doing doctests, so, probably I'll soon open a ticket.
Before I do so, I have some questions.
Currently, it is sage.categories.map.Map that implements the method
"category_for" -- which is rather strange for a *map* that is not
necesserily a morphism.
In sage.categories.morphism, I read
def category(self):
return self.parent().category() # Shouln't it be Category of
elements of ...?
I ask:
* Shouldn't Morphism.category() do what Map.category_for() currently
does? Shouldn't Morphism.category() be replaced by the current
Map.category_for()?
* Should Map really be derived from Element, should it really be an
element of a Homset? Or should this all be moved to Morphism? It seems
to me that Map should only inherit from object, whereas Morphism
should inherit from both Map and Element The problem is that, as far
as I know, there is no double inheritance for a "cdef class".
However, I think that (if you answer the above affirmatively) it would
not be good to have one huge ticket doing all of that simultaneously.
I'd prefer to have a small ticket providing "containment test for
morphisms", a medium sized ticket for moving category()/
category_for(), and a big ticket that changes the inheritance of Map
and Morphism.
Or do you think that one huge ticket is better than three not so huge?
On Thu, Dec 30, 2010 at 10:42:33AM -0800, Simon King wrote: > Currently, it is sage.categories.map.Map that implements the method > "category_for" -- which is rather strange for a *map* that is not > necesserily a morphism.
> In sage.categories.morphism, I read > def category(self): > return self.parent().category() # Shouln't it be Category of > elements of ...?
> I ask: > * Shouldn't Morphism.category() do what Map.category_for() currently > does? Shouldn't Morphism.category() be replaced by the current > Map.category_for()?
I wrote that comment :-)
I don't know if Morphism.category is actually used anywhere, so we probably can change its semantic. I don't like the current semantic of Morphism.category because it is incompatible with the semantic of .category() for elements. I think it should be something like:
sage: f = Hom(QQ,QQ)(1) sage: f.category() Category of elements of Set of Homomorphisms from Rational Field to Rational Field
or maybe something more specific:
sage: f.category() Category of morphisms in Category of rings
Note that:
sage: f.category() Category of rings
would also be incompatible with the semantic of .category() for elements. This is the reason why I added an extra ``category_for'' method. And I take the blame for not finding some more suitable name; better suggestions welcome!
A bit of fuel for the discussion: the following assertion should always be verified, for any Sage object:
sage: f in f.category() True
(see the last assert in sage.structure.sage_object.SageObject._test_category)
> * Should Map really be derived from Element, should it really be an > element of a Homset? Or should this all be moved to Morphism? It seems > to me that Map should only inherit from object, whereas Morphism > should inherit from both Map and Element The problem is that, as far > as I know, there is no double inheritance for a "cdef class".
I am not sure what the exact intention was for having two distinct concepts of Maps and Morphisms, so I can't really help. But what you say sounds right. We should get feedback from the original authors (Robert, ...).
> However, I think that (if you answer the above affirmatively) it would > not be good to have one huge ticket doing all of that simultaneously. > I'd prefer to have a small ticket providing "containment test for > morphisms", a medium sized ticket for moving category()/ > category_for(), and a big ticket that changes the inheritance of Map > and Morphism.
Yes, if you can naturally split the work in several independent tickets, go for it!
On Thu, Dec 30, 2010 at 08:30:43AM -0800, Simon King wrote: > > I think "f in C" should return True, and that this should be the > > "official" way of testing: it has the advantages of being compatible > > with the way sage tests membership of other things, and being > > mathematically accurate.
> I wouldn't agree here.
+1
> Yes, C.has_morphism(f) sounds better than C.is_morphism(f) (also from > a grammatical point of view). And it is shorter than > C.contains_morphism(f).
> So, I am "+1" to C.has_morphism(f)
+1.
What about the following variant:
sage: f.is_morphism(category = C)
I guess it depends whether the actual code doing the test depends more on the kind of morphism or on the category.
> > Although I'm in favor of the categories cleanup, this could, I think, > > be independent of it.
> Yes, I think the functionality should be fairly straight forward to > implement, regardless of category cleanup.
On 31 Dez., 13:36, "Nicolas M. Thiery" <Nicolas.Thi...@u-psud.fr>
wrote:
> I wrote that comment :-)
> I don't know if Morphism.category is actually used anywhere, so we
> probably can change its semantic.
I know that it would be used once #8807 (which has a positive review)
was merged. But when I open a new ticket for adding has_morphism then
I would of course build on top of #8807.
> I don't like the current semantic of
> Morphism.category because it is incompatible with the semantic of
> .category() for elements. I think it should be something like:
> sage: f = Hom(QQ,QQ)(1)
> sage: f.category()
> Category of elements of Set of Homomorphisms from Rational Field to Rational Field
What is meant by a "category of elements"? I just saw that it already
exists:
sage: 1.category()
Category of elements of Integer Ring
But I don't understand: What are the morphisms of a "category of
elements"?
*If* we agree that there should be a "category" of elements then there
should of course be a category of morphisms as well.
> Note that:
> sage: f.category()
> Category of rings
> would also be incompatible with the semantic of .category() for
> elements.
Here I am not so sure if I agree. It seems to me that the common
syntax in textbooks is different for elements and for morphisms:
One would say "x is an element of an object P of a category C" -
nobody would say "x is an element of a category C".
In the case of a morphism, one *could* say "f is an element of the
Homset from P to Q in a category C" or "f is an element of an object
of the category of homsets of C". But it seems common to say "f is a
morphism in C".
Therefore, I would strongly oppose against "1 in Rings()", but I would
only weakly oppose against "ZZ.hom([1]) in Rings()".
> A bit of fuel for the discussion: the following assertion should
> always be verified, for any Sage object:
> sage: f in f.category()
> True
Hence, either one removes f.category() for morphisms, or one makes it
a synonyme for f.category_for() and accepts "ZZ.hom([1]) in Rings()"
- but please not ZZ.hom([1]) in Rings().hom_category()", which is
currently the case!!
> Yes, if you can naturally split the work in several independent
> tickets, go for it!
On 31 Dez., 13:39, "Nicolas M. Thiery" <Nicolas.Thi...@u-psud.fr>
wrote:
> What about the following variant:
> sage: f.is_morphism(category = C)
> I guess it depends whether the actual code doing the test depends more
> on the kind of morphism or on the category.
If one writes code then, I guess, one typically knows that something
(C) is a category and wants to know whether some argument (f) is a
morphism in C. Hence, typically it is guaranteed that C is a category,
but there is nothing known about f. Hence, one always needed to code
"if hasattr(f,'is_morphism') and f.is_morphism(C):" -- which is
awkward.
Therefore, I prefer C.has_morphism(f) over f.is_morphism(C).
Let's make a little poll:
1) Should we have "1 in Rings()"?
I am strongly -1 on this question.
2) Should we have "ZZ.hom([1]) in Rings()"?
I am very weakly +1 on this question.
3) If x is an element of G: Should x be a morphism of Groupoid(G)
(hence, "Groupoid(G).is_morphism(x)" returns True)? Or should there be
a difference between an element of G and a morphism of Groupoid(G)?
I am undecided on these questions. But if x is not a morphism of
Groupoid(G), then at least Groupoid(G)(x) should return a morphism of
Groupoid(G).
On Fri, Dec 31, 2010 at 05:57:25AM -0800, Simon King wrote: > What is meant by a "category of elements"? I just saw that it already > exists: > sage: 1.category() > Category of elements of Integer Ring
> But I don't understand: What are the morphisms of a "category of > elements"?
Good question. Ask whoever implemented this concept :-)
Another funny one:
sage: gap(1).category() Category of elements of Gap
> *If* we agree that there should be a "category" of elements then there > should of course be a category of morphisms as well.
Possibly; can you be more specific though?
What I care about is that morphisms shall be normal elements (of their homsets). So *if* we keep that notion of "Category of elements of a parent", then f.category() should be a subcategory of the "Category of the elements of f.parent()".
> > would also be incompatible with the semantic of .category() for > > elements.
> Here I am not so sure if I agree. It seems to me that the common > syntax in textbooks is different for elements and for morphisms:
> One would say "x is an element of an object P of a category C" - > nobody would say "x is an element of a category C". > In the case of a morphism, one *could* say "f is an element of the > Homset from P to Q in a category C" or "f is an element of an object > of the category of homsets of C". But it seems common to say "f is a > morphism in C".
> Therefore, I would strongly oppose against "1 in Rings()",
Yes.
> but I would only weakly oppose against "ZZ.hom([1]) in Rings()".
Would you say: "the morphism f is in C"? It seems to me that "is a morphism in C" is a single block that can't be reduced to "is a morphism" and "is in C".
> > A bit of fuel for the discussion: the following assertion should > > always be verified, for any Sage object:
> > sage: f in f.category() > > True
> Hence, either one removes f.category() for morphisms, or one makes it > a synonyme for f.category_for() and accepts "ZZ.hom([1]) in Rings()"
I vote -1 for the latter. But there might be other options than the former. The question comes back to whether elements / morphisms should have a category.
> - but please not ZZ.hom([1]) in Rings().hom_category()", which is > currently the case!!
On 31 Dez., 15:29, "Nicolas M. Thiery" <Nicolas.Thi...@u-psud.fr>
wrote:
> On Fri, Dec 31, 2010 at 05:57:25AM -0800, Simon King wrote:
> > ...
> > *If* we agree that there should be a "category" of elements then there
> > should of course be a category of morphisms as well.
> Possibly; can you be more specific though?
*If* we agree that the "category of elements of a parent P" is not
nonsense then the "category of morphisms of a category C" is not
nonsense either.
> What I care about is that morphisms shall be normal elements (of their
> homsets). So *if* we keep that notion of "Category of elements of a
> parent", then f.category() should be a subcategory of the "Category of
> the elements of f.parent()".
Yes. *If* we agree that Element should have an attribute .category().
It seems to me that Element.category() is redundant: There is no
information in x.category() that is not already in x.parent(). Should
it perhaps be removed?
> > but I would only weakly oppose against "ZZ.hom([1]) in Rings()".
> Would you say: "the morphism f is in C"? It seems to me that "is a
> morphism in C" is a single block that can't be reduced to "is a
> morphism" and "is in C".
Good point.
> > Hence, either one removes f.category() for morphisms, or one makes it
> > a synonyme for f.category_for() and accepts "ZZ.hom([1]) in Rings()"
> I vote -1 for the latter. But there might be other options than the
> former.
If one does not remove f.category() then one will have "f in
f.category()", as one should.
Then I see three options:
1) (Current behaviour) f.category() returns
"f.category_for().hom_category()" - but we certainly don't want that
"ZZ.hom([1]) in Rings().hom_category()".
2) ``Map`` inherits the method category() from ``Element`` - then,
f.category() is the "category of elements of f.parent()". We could
probably live with f being contained in that category, but the
question is whether we like to think of that as a category.
3) f.category() returns f.category_for(). But you don't like
"ZZ.hom([1]) in Rings()".
If there is no fourth option, it seems to me we should better
remove .category() from all classes deriving from Element.
> The question comes back to whether elements / morphisms should
> have a category.
On Dec 30, 11:30 am, Simon King <simon.k...@uni-jena.de> wrote:
> On 30 Dez., 16:33, Niles <nil...@gmail.com> wrote:
> > I think "f in C" should return True, and that this should be the
> > "official" way of testing: it has the advantages of being compatible
> > with the way sage tests membership of other things, and being
> > mathematically accurate.
> I wouldn't agree here.
I think I didn't mean to say "mathematically accurate", but rather "in
current usage in mathematical writing" -- that seems to be the
conclusion of some of the other discussion here too. But the comment
I want to add now is that I *do* think it's mathematically accurate,
but maybe whether you agree or not depends on what you think the
definition of a category is. Often, people write things like "A
category is a class of objects such that for every pair of objects X,
Y there is a class (or set) Hom(X,Y) satisfying ..." -- this kind of
definition would lead to things like "f is an element in the homset
Hom(X,Y) of the category C". However, one could also make the
definition "A category consists of a class of objects and a class of
morphisms satisfying the following properties: 1) every morphism has
a source and target, and these are objects in the category, 2) ...".
Wikipedia's page gives the latter definition [1], as does Mac Lane's
"Categories for the working mathematician" (around page 10 -- it's
somewhat longer than what I've written here, but carries the same
idea). The nLab (wiki used by many people active in higher category
theory) gives both definitions, and some discussion of language
relating to the different definitions [2].
... oh dear, I think this may be turning into a rant -- I didn't want
that :) In any case, I guess you can see why I'm in favor of
"ZZ.hom([1]) in Rings()" being True, while *not* in favor of "ZZ(1) in
Rings()" being True.
On Dec 31, 10:16 am, Simon King <simon.k...@uni-jena.de> wrote:
> *If* we agree that the "category of elements of a parent P" is not
> nonsense then the "category of morphisms of a category C" is not
> nonsense either.
I agree -- the morphisms in both of these categories should all be
identity maps. With this understanding, "category of elements" and
"category of morphisms" are good stand-in's for "class of elements"
and "class of morphisms" (in the set-theoretic sense of the word
class, not the object-oriented sense) -- I think we should leave this
alone rather than talk about implementing a Class class. Along these
lines, there is also the "category of objects", so someone pedantic
might be tempted to argue that "ZZ.category()" could return "Category
of objects of category Rings". This would be silly, but consistent
with the others -- so I think they're silly too. (Although perhaps
necessary.)
> Then I see three options:
> 1) (Current behaviour) f.category() returns
> "f.category_for().hom_category()" - but we certainly don't want that
> "ZZ.hom([1]) in Rings().hom_category()".
There are, I think, two reasonable expectations for what
"hom_category" could mean: The first, and current, is the category
whose objects are homsets and whose morphisms (presumably) are
identities. The second is the category whose objects are morphisms of
C, and whose morphisms are identities. This could be returned by
something like "Rings().morphisms()". Those not in favor of option
(3) might like f.category() to return f.category_for().morphisms().
In this scenario, it might help clarify the distinction to
change .hom_category() to .homset_category(), if possible.
> 2) ``Map`` inherits the method category() from ``Element`` - then,
> f.category() is the "category of elements of f.parent()". We could
> probably live with f being contained in that category, but the
> question is whether we like to think of that as a category.
If I understand correctly, this option make "ZZ.hom([1]).category()"
return "Category of elements of Set of Homomorphisms from Integer Ring
to Integer Ring". That's my least favorite.
> 3) f.category() returns f.category_for(). But you don't like
> "ZZ.hom([1]) in Rings()".
+1
This is consistent with one of the definitions of category (it may be
the prominent one), and with popular usage.
> If there is no fourth option, it seems to me we should better
> remove .category() from all classes deriving from Element.
I believe elements should not have a category. But I thought it was
against the spirit of object-oriented programming to remove methods
from a derived class. I tried once very hard to figure out how to do
it, and couldn't find a good way -- do you have one? (And do you not
feel guilty when doing it? :)
On 31 Dez. 2010, 23:53, Niles <nil...@gmail.com> wrote:
> ... oh dear, I think this may be turning into a rant -- I didn't want
> that :) In any case, I guess you can see why I'm in favor of
> "ZZ.hom([1]) in Rings()" being True, while *not* in favor of "ZZ(1) in
> Rings()" being True.
I think it really is a delicate question, and it seems to change daily
whether I am "weakly +1" or "weakly -1" to "ZZ.hom([1]) in Rings()".
Today, I tend to -1, since I thought: "For what purpose would one
write 'bla in C' in a program?"
One would certainly use it in the form "if bla in C: do something with
bla". But if "bla in C" gives the same answer for things that are so
different as morphisms and objects, I'd say it is practically useless.
> > *If* we agree that the "category of elements of a parent P" is not
> > nonsense then the "category of morphisms of a category C" is not
> > nonsense either.
> I agree -- the morphisms in both of these categories should all be
> identity maps. With this understanding, "category of elements" and
> "category of morphisms" are good stand-in's for "class of elements"
> and "class of morphisms" (in the set-theoretic sense of the word
> class, not the object-oriented sense) -- I think we should leave this
> alone rather than talk about implementing a Class class.
Isn't "class" a reserved word in Python?
But, should we have "category of elements of one parent" (that's the
current meaning), or should one have "class of elements of all parents
in a give category"?
> > 1) (Current behaviour) f.category() returns
> > "f.category_for().hom_category()" - but we certainly don't want that
> > "ZZ.hom([1]) in Rings().hom_category()".
> There are, I think, two reasonable expectations for what
> "hom_category" could mean: The first, and current, is the category
> whose objects are homsets and whose morphisms (presumably) are
> identities.
> The second is the category whose objects are morphisms of
> C, and whose morphisms are identities. This could be returned by
> something like "Rings().morphisms()".
By the way, in the German Wikipedia, I found the approach of having
"Hom(X,Y) for any pair of objects". And I found that the class of
morphisms is sometimes denoted "Fl(C)" (French flèche = arrow).
> > 2) ``Map`` inherits the method category() from ``Element`` - then,
> > f.category() is the "category of elements of f.parent()". We could
> > probably live with f being contained in that category, but the
> > question is whether we like to think of that as a category.
> If I understand correctly, this option make "ZZ.hom([1]).category()"
> return "Category of elements of Set of Homomorphisms from Integer Ring
> to Integer Ring". That's my least favorite.
Yes, unless we change Element.category() into something that returns
the "class of elements of objects of category C".
> > If there is no fourth option, it seems to me we should better
> > remove .category() from all classes deriving from Element.
> I believe elements should not have a category.
I believe that, too.
> But I thought it was
> against the spirit of object-oriented programming to remove methods
> from a derived class.
Well, Element derives from Element as well, so, my suggestion was to
remove it there :)
On Jan 1, 3:29 am, Simon King <simon.k...@uni-jena.de> wrote:
> Well, Element derives from Element as well, so, my suggestion was to
> remove it there :)
This won't remove the .category() method though -- it will be
inherited from SageObject, and then ZZ(1).category() will return
"Category of objects". To me, this is just as good/bad as "Category
of elements of bla". I guess the advantage is that we don't have to
deal with the question of what "bla" should be. "The category of
elements of ZZ" and "the category of all elements of all commutative
rings" are, I think, both reasonable answers.
> But, should we have "category of elements of one parent" (that's the
> current meaning), or should one have "class of elements of all parents
> in a give category"?
Whatever happens, I hope .category() will return a category of some
kind, rather than "class of ..."
> On 31 Dez. 2010, 23:53, Niles <nil...@gmail.com> wrote:
> > ... oh dear, I think this may be turning into a rant -- I didn't want
> > that :) In any case, I guess you can see why I'm in favor of
> > "ZZ.hom([1]) in Rings()" being True, while *not* in favor of "ZZ(1) in
> > Rings()" being True.
> I think it really is a delicate question, and it seems to change daily
> whether I am "weakly +1" or "weakly -1" to "ZZ.hom([1]) in Rings()".
> Today, I tend to -1, since I thought: "For what purpose would one
> write 'bla in C' in a program?"
I agree that it's delicate. And I think the source of the delicacy is
that there are two commonly accepted and useful definitions of
category -- do you think there's more to it than that?
Do you think sage can reasonably expect to be consistent with both
definitions? I have some hope that it can, but also some concern.
> One would certainly use it in the form "if bla in C: do something with
> bla". But if "bla in C" gives the same answer for things that are so
> different as morphisms and objects, I'd say it is practically useless.
Well, it would be useful in cases where you have a morphism of one
category, and want to test whether it's in a particular subcategory or
not, or whether it coerces to some other category. Note that "bla in
ZZ[x]" gives the same answer for lots of different things (prime
numbers, composite numbers, monomials, ...). Since a category holds
much more data than a ring, I'm happy to consider more things to be
"in" a category.
> By the way, in the German Wikipedia, I found the approach of having
> "Hom(X,Y) for any pair of objects". And I found that the class of
> morphisms is sometimes denoted "Fl(C)" (French flèche = arrow).
thanks -- I should have checked these too :)
I've also seen Ob(C) and Mor(C) for the objects and morphisms of C.
Perhaps another way of approaching this issue is to say that
containment is well-defined for sets, and even for classes, but a
category -- using either definition -- is neither of these. Thus "x
in C" must be shorthand for "x in X", where X is some class. And
there are a number of natural choices for what X should be. Using one
definition, X should be the class of objects and (possibly) homsets of
C. Using another definition, X should be the class of objects and
morphisms of C.
We could opt to be as permissive as possible, and take X to be the
objects, homsets, *and* morphisms of C; what do you think of that?
At the risk of pushing this too far, I also want to mention the
"single-sorted" definition of category:
This is the morphism-centric counterpart to the "objects and homsets"
definition of category, defining it as a collection of morphisms with
some additional data (the essential idea is that an object can be
identified by its identity morphism). I don't see it being terribly
useful right now to implement all possible definitions of category,
but I do think we should try to avoid excluding them, if we can. For
example, I can think of a some applications in algebraic geometry or
algebraic topology where it would be useful to be able to implement
internal categories or enriched categories -- these arise as
generalizations of different definitions of category. If someone does
eventually want to work on one of these, it would be nice (although
not necessary) if the category framework is flexible enough to be
compatible with them.
> > Well, Element derives from Element as well, so, my suggestion was to
> > remove it there :)
> This won't remove the .category() method though -- it will be
> inherited from SageObject, and then ZZ(1).category() will return
> "Category of objects".
Ouch, that's right.
But why is it that SageObject has a method category? After all, there
is a distinct class sage.structure.category_object.CategoryObject - it
directly derives from SageObject, but overrides the category() method.
I see that Parent (which clearly should have a category() method)
inherits from CategoryObject.
So, why don't we remove the category() method from SageObject? If a
class ought to have a category() method, then it should be derived of
CategoryObject, and if it doesn't (like Element) then it should just
be derived from SageObject.
> > I think it really is a delicate question, and it seems to change daily
> > whether I am "weakly +1" or "weakly -1" to "ZZ.hom([1]) in Rings()".
> > Today, I tend to -1, since I thought: "For what purpose would one
> > write 'bla in C' in a program?"
> I agree that it's delicate. And I think the source of the delicacy is
> that there are two commonly accepted and useful definitions of
> category -- do you think there's more to it than that?
In this case, I just tried to take the point of view of a programmer,
not a mathematician, and tried to think of the use of "bla in C" in a
program.
> Do you think sage can reasonably expect to be consistent with both
> definitions? I have some hope that it can, but also some concern.
No, that's hardly possible. We should stick with one definition.
> > One would certainly use it in the form "if bla in C: do something with
> > bla". But if "bla in C" gives the same answer for things that are so
> > different as morphisms and objects, I'd say it is practically useless.
> Well, it would be useful in cases where you have a morphism of one
> category, and want to test whether it's in a particular subcategory or
> not, or whether it coerces to some other category.
That's the purpose of C.has_morphism(f), proposed in the posts above.
> Note that "bla in
> ZZ[x]" gives the same answer for lots of different things (prime
> numbers, composite numbers, monomials, ...).
> Since a category holds
> much more data than a ring, I'm happy to consider more things to be
> "in" a category.
I see a clear difference between "bla in ZZ['x'] for bla=1,x,primes,
non-primes,..." and "bla in Rings() for objects, homsets, morphisms
and perhaps elements":
If you have "bla in ZZ['x']" then it is guaranteed that bla is an
element, and (after coercion) one can do arithmetic with all other
elements of ZZ['x'].
I would expect to have a similar guarantee for "bla in Rings()".
Hence, I would expect that I can define Hom(bla,X) for any other thing
that satisfies "X in Rings()". From that point of view, "bla in
Rings()" should return "False", if bla is a morphism. Therefore ...
> We could opt to be as permissive as possible, and take X to be the
> objects, homsets, *and* morphisms of C; what do you think of that?
... I am a bit sceptic.
> At the risk of pushing this too far, I also want to mention the
> "single-sorted" definition of category:
On Jan 1, 10:05 am, Simon King <simon.k...@uni-jena.de> wrote:
> But why is it that SageObject has a method category? After all, there
> is a distinct class sage.structure.category_object.CategoryObject - it
> directly derives from SageObject, but overrides the category() method.
> I see that Parent (which clearly should have a category() method)
> inherits from CategoryObject.
> So, why don't we remove the category() method from SageObject? If a
> class ought to have a category() method, then it should be derived of
> CategoryObject, and if it doesn't (like Element) then it should just
> be derived from SageObject.
This sounds great to me. Just to see what would be involved, I
removed SageObject.category(), Element.category() and ran some
doctests. There were a number of failures in sage/structure and sage/
categories, but they seemed mostly to come from ._test_category();
maybe they wouldn't be too hard to fix up. I also tested sage/
algebras and sage/schemes; there were just two failures in algebras,
and none in schemes. This makes me hopeful that the rest of sage
doesn't depend too much on SageObject.category().
To carry this out, would we first have to implement a deprecation
warning, and then wait for a couple of releases before removing the
functionality?
> > Well, it would be useful in cases where you have a morphism of one
> > category, and want to test whether it's in a particular subcategory or
> > not, or whether it coerces to some other category.
> That's the purpose of C.has_morphism(f), proposed in the posts above.
I'm willing to leave it at that for now. Is it accurate to say that
removing .category() from SageObject and Element and implementing
Category.has_morphism() will resolve most of our issues? Then "x in
C" will be shorthand for "x is an object of C", and testing for
individual morphisms and for homsets will be handled by other methods,
which seems reasonable.
Do you know who put the category methods in SageObject and Element in
the first place, and whether there are other issues we should consider
before removing them?
> ...
> This sounds great to me. Just to see what would be involved, I
> removed SageObject.category(), Element.category() and ran some
> doctests.
Good, thank you!
> There were a number of failures in sage/structure and sage/
> categories, but they seemed mostly to come from ._test_category();
> maybe they wouldn't be too hard to fix up.
If SageObject has no category() then probably _test_category() should
be moved to CategoryObject (currently CategoryObject simply inherits
_test_category() from SageObject) .
> I also tested sage/
> algebras and sage/schemes; there were just two failures in algebras,
> and none in schemes. This makes me hopeful that the rest of sage
> doesn't depend too much on SageObject.category().
Good news.
> To carry this out, would we first have to implement a deprecation
> warning, and then wait for a couple of releases before removing the
> functionality?
I guess that is a question for sage-devel?
> I'm willing to leave it at that for now. Is it accurate to say that
> removing .category() from SageObject and Element and implementing
> Category.has_morphism() will resolve most of our issues? Then "x in
> C" will be shorthand for "x is an object of C", and testing for
> individual morphisms and for homsets will be handled by other methods,
> which seems reasonable.
I think that's the plan.
> Do you know who put the category methods in SageObject and Element in
> the first place, and whether there are other issues we should consider
> before removing them?
Sorry, I don't know (but I am sure that s/he is reading sage-
algebra...)
On Sat, Jan 01, 2011 at 07:05:42AM -0800, Simon King wrote: > > > I think it really is a delicate question, and it seems to change daily > > > whether I am "weakly +1" or "weakly -1" to "ZZ.hom([1]) in Rings()". > > > Today, I tend to -1, since I thought: "For what purpose would one > > > write 'bla in C' in a program?"
> > I agree that it's delicate. And I think the source of the delicacy is > > that there are two commonly accepted and useful definitions of > > category -- do you think there's more to it than that?
Yes, a category C is made of two things: Obj(C) and Mor(C). Very much like a graph G = (V,E) is defined in term of two sets: its nodes and its vertices. So in principle, we should only allow for
P in Obj(C) f in Mor(C)
Now, especially given our categories are named, I find it convenient, to allow for:
P in VectorSpaces()
whose meaning is immediately clear to any reader. On the other hand:
f in VectorSpaces()
to test if f is a morphism in VectorSpaces() is not intuitive. So I am also +1 on having ``x in C'' mean exactly ``x is an object of C'', as is the case currently.
> > What about the following variant:
> > sage: f.is_morphism(category = C)
> > I guess it depends whether the actual code doing the test depends more > > on the kind of morphism or on the category. > If one writes code then, I guess, one typically knows that something > (C) is a category and wants to know whether some argument (f) is a > morphism in C. Hence, typically it is guaranteed that C is a > category, but there is nothing known about f. Hence, one always > needed to code "if hasattr(f,'is_morphism') and f.is_morphism(C):" > -- which is awkward. > Therefore, I prefer C.has_morphism(f) over f.is_morphism(C).
That's a good point.
So, right now, my preferred idiom is ``f in C.morphisms()'', because it's the straightforward translation of ``f in Mor(C)''. But I guess ``C.has_morphism(f)'' will do until we have another concrete use for ``C.morphisms()''.
> On Sat, Jan 01, 2011 at 07:05:42AM -0800, Simon King wrote: >> > > I think it really is a delicate question, and it seems to change daily >> > > whether I am "weakly +1" or "weakly -1" to "ZZ.hom([1]) in Rings()". >> > > Today, I tend to -1, since I thought: "For what purpose would one >> > > write 'bla in C' in a program?"
>> > I agree that it's delicate. And I think the source of the delicacy is >> > that there are two commonly accepted and useful definitions of >> > category -- do you think there's more to it than that?
> Yes, a category C is made of two things: Obj(C) and Mor(C). Very much > like a graph G = (V,E) is defined in term of two sets: its nodes and > its vertices. So in principle, we should only allow for
> P in Obj(C) > f in Mor(C)
> Now, especially given our categories are named, I find it convenient, > to allow for:
> P in VectorSpaces()
> whose meaning is immediately clear to any reader. On the other hand:
> f in VectorSpaces()
> to test if f is a morphism in VectorSpaces() is not intuitive. So I am > also +1 on having ``x in C'' mean exactly ``x is an object of C'', as > is the case currently.
>> > What about the following variant:
>> > sage: f.is_morphism(category = C)
>> > I guess it depends whether the actual code doing the test depends more >> > on the kind of morphism or on the category.
>> If one writes code then, I guess, one typically knows that something >> (C) is a category and wants to know whether some argument (f) is a >> morphism in C. Hence, typically it is guaranteed that C is a >> category, but there is nothing known about f. Hence, one always >> needed to code "if hasattr(f,'is_morphism') and f.is_morphism(C):" >> -- which is awkward. >> Therefore, I prefer C.has_morphism(f) over f.is_morphism(C).
> That's a good point.
> So, right now, my preferred idiom is ``f in C.morphisms()'', because > it's the straightforward translation of ``f in Mor(C)''. But I guess > ``C.has_morphism(f)'' will do until we have another concrete use for > ``C.morphisms()''.
On 5 Jan., 14:56, "Nicolas M. Thiery" <Nicolas.Thi...@u-psud.fr>
wrote:
> whose meaning is immediately clear to any reader. On the other hand:
> f in VectorSpaces()
> to test if f is a morphism in VectorSpaces() is not intuitive.
I somehow agree.
> So, right now, my preferred idiom is ``f in C.morphisms()'', because
> it's the straightforward translation of ``f in Mor(C)''. But I guess
> ``C.has_morphism(f)'' will do until we have another concrete use for
> ``C.morphisms()''.
Why wait? I guess it would be straight forward to introduce a very
basic structure whose purpose is: Knowing that it is a class of
morphisms; knowing the category to which these morphisms belong;
testing containment.
Projected usage:
sage: M = Rings().morphisms()
sage: M
Class of morphisms in category of rings
M should belong to a category, but of course this is not Rings() in
this example. In general, M will not be a set but a class.
Is there a category of classes? Do all classes form a class?
And if one can define it: Should the "Category of classes" exist in
Sage, likely being very similar to `Sets`?
I guess I am not sure about the exact meaning of Objects(): Is
Objects() a sub- or a super-category of the category of classes? Or is
it actually the same?
Note that if we have Classes() in addition to Sets() then it should be
easy to implement the notion of "small" categories.
So, we should have either
sage: M in Objects()
True
or (with more work)
sage: M in Classes()
True
Concerning the category for which M was defined: What about the method
name "defining_category"? Better suggestions? Then:
sage: M.defining_category() is Rings()
True
sage: ZZ.hom([1]) in M
True
sage: ZZ in M
False
Code draft:
{{{
class MorphismSet(Parent):
def __init__(self, category, is_small=False):
Parent.__init__(self, category=Sets() if is_small else
Objects()) # or better "Sets() if is_small else Classes()"??
self.__cat = category
def _repr_(self):
return "Class of morphisms in category of
%s"%self.__cat._repr_object_names()
def __contains__(self, f):
return self.__cat.has_morphism(f)
def an_element(self):
E = self.__cat.example()
if E is NotImplemented:
raise NotImplementedError, "Please implement the method
'example()' for category of %s, or implement the method 'an_element()'
for %s"%(self.__cat._repr_object_names(), repr(self))
return E.Hom(E).an_element()
}}}
Of course, for now, the only purpose of that class is to provide an
intuitive syntax for testing morphism containment. But I wouldn't
object if eventually someone would add useful stuff to it. And for
symmetry, there could also be an ObjectSet class.
On Wed, Jan 05, 2011 at 09:05:38AM -0800, Simon King wrote: > > So, right now, my preferred idiom is ``f in C.morphisms()'', because > > it's the straightforward translation of ``f in Mor(C)''. But I guess > > ``C.has_morphism(f)'' will do until we have another concrete use for > > ``C.morphisms()''.
> Why wait? I guess it would be straight forward to introduce a very > basic structure whose purpose is: Knowing that it is a class of > morphisms; knowing the category to which these morphisms belong; > testing containment.
I don't see any reason if you don't anymore :-) Please go ahead!
> Projected usage:
> sage: M = Rings().morphisms() > sage: M > Class of morphisms in category of rings
+1
> M should belong to a category
Do we really need this at this point? Here again, I would just leave what you wrote somewhere (e.g. a track ticket) and skip that step until we have more use cases for "Classes" and other business with non-small categories.
> Concerning the category for which M was defined: What about the method > name "defining_category"? Better suggestions?
Sounds good. An alternative would be to use base_category() since that's already in use for other objects parametrized by a category (although those objects are probably all categories)
> sage: M.defining_category() is Rings() > True > sage: ZZ.hom([1]) in M > True > sage: ZZ in M > False
> {{{ > class MorphismSet(Parent): > def __init__(self, category, is_small=False): > Parent.__init__(self, category=Sets() if is_small else > Objects()) # or better "Sets() if is_small else Classes()"?? > self.__cat = category > def _repr_(self): > return "Class of morphisms in category of > %s"%self.__cat._repr_object_names() > def __contains__(self, f): > return self.__cat.has_morphism(f) > def an_element(self): > E = self.__cat.example() > if E is NotImplemented: > raise NotImplementedError, "Please implement the method > 'example()' for category of %s, or implement the method 'an_element()' > for %s"%(self.__cat._repr_object_names(), repr(self)) > return E.Hom(E).an_element() > }}}
+1
Maybe MorphismsOfCategory for the name of the class?
> Of course, for now, the only purpose of that class is to provide an > intuitive syntax for testing morphism containment. But I wouldn't > object if eventually someone would add useful stuff to it.
+1.
> And for symmetry, there could also be an ObjectSet class.
+1, at least as soon as we will have an actual need for it.
On Wed, Jan 05, 2011 at 09:43:39AM -0800, Simon King wrote: > On 5 Jan., 18:05, Simon King <simon.k...@uni-jena.de> wrote: > > class MorphismSet(Parent): > > def __init__(self, category, is_small=False): > > ...
> ... or rather > class MorphismSet(Parent,UniqueRepresentation): > @staticmethod > def __classcall__(cls, category, is_small=False): > return super(MorphismSet, cls).__classcall__(cls, category, > is_small) > def __init__(self, category, is_small) > Parent.__init__(self, category= Sets() if is_small else > Objects()) > self.__cat = category > self.__small = is_small > def is_small (self): > return self.__small > def _repr_(self): > return "%s of morphisms in category of %s"%("Set" if > self.__small else "Class",self.__cat._repr_object_names()) > ...
I'd say not to worry too much about this small business. I actually would be fine with an output like ``hom(Category of Vector Spaces)'' even though it's not perfectly consistent with other representations for parents.
On 5 Jan., 21:37, "Nicolas M. Thiery" <Nicolas.Thi...@u-psud.fr>
wrote:
> I'd say not to worry too much about this small business. I actually
> would be fine with an output like ``hom(Category of Vector Spaces)''
> even though it's not perfectly consistent with other representations
> for parents.
Well, any set is a class. Hence, for now, I return *small* morphism/
object classes only for sub-categories of FiniteEnumeratedSets() (I
hope it is correct that these are all small categories?).
Also, for now I simply assume that Objects() is a good replacement for
a (pseudo)category of all classes. After all, Objects() is thought of
as the biggest category in Sage. So, if the category C is small then
C.morphisms() is in Sets(), and otherwise C.morphisms() is in
Objects(). I suppose that's a sufficient approximation to the
mathematical reality.
One question about the layout/name:
How should I call the module in which ObjectsOfCategory and
MorphismOfCategory are implemented? I thought about
sage.categories.class_of, because
sage.categories.class_of.MorphismsOfCategory sounds quite natural to
me (from a grammatical point of view).