Unfortunately, I’ve got some, well, ambiguous news.

Remember I told you about hash-randomisation failures in computing

diagram embeddings? Well, it turned out that diagram embeddings was

quite OK, and the problem went as far back as the Diagram class.

Essentially, I have done a really bad job implementing it at the

beginning of the summer: I wanted it to directly store all possible

morphism compositions. However, in that implementation, I didn’t

really store all compositions, but just a part of them; which part I

stored depended on the order in which the morphisms were supplied

(severe facepalmðŸ˜¦ )I tried thinking of some good fixes, but, as you can easily imagine,

the whole idea of storing all composites has suffered an epic

disintegration in the face of diagrams with cycles. I am really

_really_ astonished at how this has managed to slip by me for such a

long time!ðŸ˜¦I have spent the first one third of Friday on trying to save the

existing design somehow, by carefully processing all possible edge

cases, but this has very quickly started to be abominable, and, of

course, it didn’t work. So, I have spent the greater part of Friday

on thinking out a new Diagram. I have spent all of yesterday, (all of

Saturday, that is), on implementing this new concept. Basically, the

new Diagram only stores the relevant generator morphisms, but it is

still able to correctly determine and enumerate the morphisms that

belong to it. It is also capable of determining whether it is finite

or not (i.e., whether there are cycles in the underlying directed

multigraph). When asked for all morphisms, the new Diagram yields a

generator which acts correctly both in the finite and infinite cases.

In the finite case it produces all the morphisms of the Diagram. This

is clearly impossible in the infinite case, but Diagram is

sufficiently clever in this case to produce the morphisms in a

BFS-like manner. Intuitively, it will first yield all length one

morphisms, then all morphisms of length two, etc.I have made some changes to the interface of the Diagram to better

reflect the new internals. Nevertheless, the behaviour in the finite

case is the same as that of the old Diagram (modulo some property

names and minor changes, of course).One bit of good news that deserves standing out in a separate

paragraph is that I only had to change _one_ line of code in

diagram_drawing.py to get it to work with the new Diagram. (Well, I

did drop three other lines, because they were redundant), so this

radical swerve with the Diagram has left the larger part of my GSoC

work unaffected.Now, I have started cherry-picking the diagram embeddings code, and I

have arrived at a conclusion that Diagram has to be further extended.

(“Extending” means adding something new, not rewriting it again.)

Namely, it is insufficient to know whether the whole Diagram is finite

or not; I really need to know whether a certain hom-set is finite or

not. It’s not that hard to implement, and I’ve got a cool book on

graphs; however, it’s going to require some extra time.Here comes the most important part of my message: I’m working at the

fullest possible cruising speed (not sprinting yet; that I’m saving

for the last 100m). I won’t obviously have everything done tomorrow,

on Monday; however, I strongly believe that I only need another couple

days to finish the bulk of inferencing. Provided that on Monday we

have what is referred to as _soft_ pencils-down date, I hope that I’m

still OK with the GSoC timeframe. Further, I think I have already

mentioned a couple times that I’m going to have another couple free

weeks after GSoC, during which I will be easily able to finalise

whatever will be unfinished. Do note, however, that I definitely

expect to have inferencing done _within_ the GSoC timeframe.Conclusion: despite the rather radical direction things have taken in

the last two days, I’m _still_ more or less fine with the timing.At the moment, you will not be able to see the code I’m working on on

GitHub. The reason is that I’m juggling branches rather ninja-ily

right now, so I don’t really have the most relevant one to push

online, and they are all relatively short-lived. I do expect to get

back to working sequentially today, and once I’ve got there, I’ll push

to ct3-commutativity to reflect the updates.I’m documenting everything I do in as minute detail as possible. I

think the Diagram class and the embeddings functionality has more

comments than actual code. I expect this to make reviewing and later

maintenance considerably more agreeable. Further, my commits are

almost all rather short, with acceptably long commit messages. There

is one commit that breaks the rule, however: the commit which adds the

new Diagram. It is one relatively large chunk of code, which replaces

the old Diagram with the new one and shows that the old tests still

pass modulo minor changes. I have nevertheless reformatted the

history a bit to make this commit easier to review and, of course, the

code itself is just literally stuffed with comments. All other

commits are much more like my usual ones.

Whenever I’m done with the core parts of inferencing, I will write a proper blogpost.

]]>

The second half of the week was considerably more exciting and thought intensive: it was related to finding diagram embeddings. As it should be clear from the last post, this functionality lies at the foundation of deciding the commutativity of diagrams and implications. In what follows, I will refer to the diagram which we need to embed as to the *pattern*, and to the diagram into which we need to embed as to the *model*. This seems to be an almost universally accepted terminology and comes from the fact that finding subgraph isomorphisms often lies at the base of various pattern matching implementations.

I have started by selecting and analysing the excellent paper by J. R. Ullman, [Ullm1976], which describes a very clear way of enumerating all possible graph embeddings. This solution, however, was not exactly what I needed. First of all, the algorithm described in details in [Ullm1976] is actually meant for *undirected* graphs, whereas one can clearly see arrows in diagrams. Furthermore (a thought that has occurred to me quite late), diagrams, are actually multigraphs, in the sense that there can be more than one morphism between two objects. Yet further, a diagram embedding must preserve morphism properties, in the sense that the embedding must map a morphism in the pattern to a morphism in the model, which has exactly the same properties as the morphism in the pattern.

I attempted to find whether someone has addressed the directed multigraph embedding problem before; however, I haven’t managed to find any references on the Internet, so I started thinking on adapting Ullman’s solution to my case. The first thing I figured out was that I could reduce the directed multigraph embedding problem to a directed graph embedding problem. Indeed, take a diagram and flatten down all multiple morphisms *going in the same direction* between the same to objects to one *directed* edge between these two objects. Then construct directed graph embeddings and, for each such embeddings, for each directed edge of the flattened pattern, construct injective, property-preserving, mappings from the set of morphisms of the pattern, which were flattened to , into the set of morphisms associated with the edge in the flattened model, to which is mapped by the subgraph isomorphism. (These mappings are actually property-preserving embeddings in their own right, but I won’t call them so, since I’m good and I understand that the blog post has just become a bit unclear, so to sayðŸ˜€ )

Let’s see an example. Consider the diagram comprising two different morphisms: and , where has the property `golden`; this diagram is going to be out pattern. Now, consider the model: a diagram comprising three morphisms , , and , in which has the property `golden`. Quite obviously, all of our *property-preserving* embeddings should map to , while $\latex g$ can be mapped to either or . Also note that the flattened pattern in this case is the graph consisting of a single edge , while the flattened model is another one-edge graph, . More complex diagrams are treated in a similar fashion: flatten the pattern and the model to directed graphs, find directed graph embeddings, and then find the property-preserving morphism mappings.

There was another slight surprise underway, however. Ullman does describe some of the modifications which will make the original algorithm capable of constructing directed graph embeddings, however, he has apparently forgot to describe one of them. I will give some definitions before going into more detail. Ullman uses to refer to the adjacency matrix of the pattern, to refer to the adjacency matrix of the model, and to refer to the matrix representing a mapping of the vertices of the pattern into the vertices of the model; means that vertex in the pattern is mapped to vertex in the model.

Now, for given , , and , compute . Condition (1) in [Ullm1976] states that, if , for any vertices and of the patern, then represents an embedding. (As usual, are elements of and are elements of ). When I tried to actually use this criterion for a directed graph, I found that, apparently, should be used, instead of . The formal explanation follows. By abuse of terminology, I will use “pattern” and “model” to refer to the flattened pattern and flattened model as well.

Let . means that , where is a vertex of the model. In other words, this means that the vertex of the pattern is mapped to a unique vertex of the model, such that in the model there exists the (directed) edge . Obviously, if is an element of , the role of the indices is reversed, that is: the vertex of the pattern is mapped to a unique vertex of the model, such that in the model there exists the (directed) edge .

Now, means that . Deciphering the meanings of the values of the elements of these matrices, this means that the vertex of the pattern is mapped to a vertex of the model, vertex of the pattern is mapped to a vertex of the model, such that in the model there is the edge . Now, suppose there is an edge in the pattern. means maps to and to , such that the model contains the edge . That is, the condition (1) as stated in [Ullm1976] and applied to directed graphs checks that actually *reverses* the direction of edges! Therefore, one must actually use to check for embeddings.

Now, since the original algorithm in [Ullm1976] was designed for *undirected* graphs, this extra transposition did not matter, and I think this is the reason why Ullman does not mention it.

I have implemented all the things I have described so far, so diagram embeddings kinda work I have played with python generators a bit, so the code only produces embeddings on the as-needed basis. I did that because I thought of the situation when any diagram embedding will suffice, but also because using generators has resulted in what I believe to be more elegant code. The code abounds in comments, so I think it shouldn’t be a problem to comprehend for someone different from myself. I don’t have a formal proof for this statement, however, so, I guess, Tom is going to be the test subject for this supposition ^_^

There are still a couple things to do, though. First of all Ullman shows a nice optimisation to his algorithm; it looks pretty simple, so I’ll add it. I will then write a couple more tests, including some crash tests involving complete graphs. I will also have to rename the function which does all this magic from `subdiagram_embeddings` to `diagram_embeddings`, for obvious (I hope ) reasons.

[Ullm1976] J. R. Ullman, An Algorithm for Subgraph Isomorphism, J. Association of Computing Machinery, March, 1976, 16, 31–42.

]]>

Something which makes me very content is that I have finally submitted a fix for the sort key problem for unordered collections. The essence of the problem is as follows. With hash randomisation enabled, the order of `Basic.args` changes on every run. On the other hand, `Basic.sort_key` traverses the arguments in the order in which they are stored; therefore, sort keys are dependent on the actual order of the arguments. This has given me trouble when working on laying out diagrams, specifically, in handling groups. The thing is that the group handling code relies on `FiniteSet` (this maybe isn’t the best idea, but that’s a different story, really :-)): groups are eventually converted to `FiniteSet`‘s of `FiniteSet`‘s. To assure stable output, the collection of `FiniteSet`‘s is *sorted*. However, due to the influence of hash randomisation on sort keys, this sorting would *not* actually produce the desired consequences. There was a similar problem in the same block of functionality which had to do with sorting `Diagram`‘s; the issue there was that a `Diagram` stores `Dict`‘s which, being unordered collections, were subject to the same sort key trouble. Pull request #1446 fixes all of these issues and, finally, the diagram drawing code almost always passes all of its tests.

It is worth mentioning that while the fix for the sort key problem was not included in the #1429, I was inclined to classify all problems as related to `FiniteSet.sort_key`. With the fix in the branch, it turned out that there were some other subtle sorting issues, which I am still fixing.

I have also sent pull request #1440 which fixes the pretty printing of morphisms and diagrams, introduced by myself in #1338. Initially, I would use short Unicode arrows for pretty printing morphisms, but Tom and I have arrived at the conclusion that these arrows look too condensed. I have then chosen to use long Unicode arrows; it turned out however that Unicode characters which span more than one symbol are not rendered consistently across different machines. On my computer, the longer arrow would overlap with the next character in line; on Tom’s, it would not. Aaron has suggested building up arrows out of em dashes and black right-pointing triangles, and this seems to work better, although it still looks ugly with some fonts (e.g., the default font in *rxvt-unicode*, as reported by Tom).

I have also promised to implement variable-length horizontal arrows. I have decided to postpone this for now, however, in order to better focus on my GSoC project. I will keep that task in mind, however, and will most probably return to it in a couple of days.

As for deciding the commutativity of diagrams, I have run into an unexpected conceptual problem, arising from the fundamental difference between diagrams with conclusions and without conclusions. Before explaining the problem, I will remind the description of these two types of constructions. A commutative diagram is a collection of morphisms (which usually form a connected directed graph) with the property that composing all morphisms along any two paths between any two objects produces the same composite morphism. While being quite general, in category theory it is customary to produce statements like “if there are such morphisms, there exist such morphisms, and the diagram is commutative”. This statement is clearly an implication. The class `Diagram` is a representation of the second type of statement and contains sets of premise morphisms and conclusion morphisms. `Diagram` is also conventionally capable of representing simple commutativity if no conclusions are specified.

While I was initially quite comfortable with using `Diagram` for both types of statements, I am really inclined to considering the creation of two separate classes now. Thus I plan to rename `Diagram` to `Implication` and add a different `Diagram` which will represent what I used to call “commutative diagram without conclusions”. That is, `Diagram` will hold only one collection of morphisms.

With this separation, it is immediately clear that, in the context of my model, the question “Is this diagram commutative?” actually incorporates two totally different questions:

- Is this
`Diagram`commutative? - Is this
`Implication`true and commutative?

Fortunately for me ( ), this newly-discovered separation does not remove the possibility of answering both questions with almost the same algorithm. I will start with question (1) to further stress the difference between the semantics of diagrams and implications.

Consider a collection of `Diagram`‘s and `Implication`‘s known to be commutative. (By saying “an `Implication` is commutative” I will abuse the terminology and mean “an `Implication` is true and commutative.”) We need to decide whether the target `Diagram` is commutative. The algorithm I will describe is based on backward chaining and is therefore recursive. A recursive step consists of two stages: the *commutativity* stage and the *inference* stage. The goal of the commutativity stage is to decide whether the current version of the target `Diagram` is commutative; the goal of the inference stage is to see whether applying one of the `Implication`‘s will make the target `Diagram` commutative.

The commutativity stage starts with taking every morphism of the target `Diagram` and putting each of them into its own commutative subdiagram. Now, for each commutative subdiagram, the algorithm will pick a subset of morphisms and will then put the subsets together to form another subdiagram. This subdiagram will then be compared with each of the `Diagram`‘s known to be commutative. If a match is found, the subdiagram is added to the set of commutative subdiagrams. Then, all possible “absorptions” among the diagrams are performed (i.e., if subdiagram is a subdiagram of , the subdiagram is removed from the collection of subdiagrams (for obvious reasons)) and the iteration returns to its start, where it picks subsets of the new subdiagrams. Since the number of morphisms in the diagram is finite, this process is finite. If, in the end, the collection of commutative subdiagrams contains only the target diagram, it is deemed commutative.

Note that this alrogithm is very similar to one of the methods of finding all prime implicants of a boolean function (we called that Blake-Poretski algorithm at the university, but I cannot find any references on my Internet). I have considered the possibilities of directly converting the commutativity stage to a boolean function minimisation problem, but I haven’t found a sufficiently elegant way yet.

The inference stage exactly follows the idea of backward chaining. For each `Implication` an attempt is made to find the embedding of the premises into the target `Diagram`. If such an embedding is found, the corresponding conclusions are added to a copy of the target `Diagram` and a recursive examination of the modified `Diagram` is made. The found embedding of one of the `Implication`‘s plus the added conclusions are propagated down the recursion tree as commutative subdiagrams. The commutative stages of the following recursive calls will take their commutativity for granted.

If one of these recursive calls returns a positive result, this positive result is propagated up the call stack. If neither of the recursive calls returned a positive result, or if no embedding of an `Implication` has been found in a certain recursive call, a negative result is returned from this recursive call.

Note that it actually was the inference stage that I described in my original GSoC proposal.

Before showing how to answer question (2), I would like to analyse the algorithm idea I have just presented a little bit. One can see that the commutativity and inference stages are *very* different; so different, in fact, that they are almost independent. Therefore, these two bits of functionality will live in separate pieces of code, and will be later combined to function together. I will start by defining two internal classes, `_CommutativityStage` and `_InferenceStage` which will host the corresponding functions. The code that will actually combine the two will either be a global function or a class; this will be clearer later and is not important at the moment.

Question (2) now: “Is the given `Implication` true (and commutative)?”. In this case, one should start from the premises of the given `Implication` and apply the same strategy as in answering question (1). Here, however, the terminal criterion is that the target `Diagram` (obtained from the premises of the original `Implication`) is commutative *and* contains the conclusions of the original `Implication`.

A remark about comparing diagrams is due here: this is nothing but the subgraph isomorphism problem. I have already found this paper (haven’t read it yet), but I’m open to other paper suggestions in this regard

EDIT: I have decided to not follow this article and instead focus on a more basic solution. Should the need occur, I will implement this (apparently) more efficient version.

It is necessary to keep in mind that, besides finding the subgraph isomporphism proper, the code will have to pay attention to morphism properties as well.

Now, the most attentive readers might have already remarked that semantically splitting the class `Diagram` into two will impact diagram drawing. Yet, the impact will be rather modest, since the drawing code already knows how to deal with something similar to `Implication`; adding explicit support for new `Diagram` is going to require minimal effort.

In this blog post, I recognize that my initial class model was flawed in yet another place. I try to see this is as a sign of personal progress, though

]]>

Among the changes worth mentioning are some updates to the choice of internal data structures of `DiagramGrid`. Previously, `FiniteSet` was used to store any sets. Following my mentor’s suggestion, though, I have refactored the code to only use `FiniteSet` when something needs to be stored in `Basic.args`. On all other occasions, the built-ins `set` and `frozenset` are used, depending on whether a mutable set or an immutable hashable container is needed.

The other change bearing no fundamental importance but still worth mentioning is the transition to storing undirected edges as two-element `frozenset`‘s. Previously, edges were stored as two-element tuples which caused a bit of hassle in what concerned recognizing the equality of `(A, B)` and `(B, A)`. The choice of `frozenset` has brought in more elegant code. In terms of performance, I do not think that this transition has had a really important impact, since I didn’t really keep performance in mind when writing other parts of the code anyway. (I am mainly referring to the construction of the skeleton of the diagram and splitting it into triangles.)will l

Among more significant improvements, I will list the support for disconnected diagrams, one-object diagrams, and, the pinnacle, graceful handling of the situations when growing a pseudopod fails. Before you start thinking abut who the hell would need disconnected or one-object diagrams, I will remind/introduce the process and the necessity of pseudopods in diagram layout (Hey, that did sound like rubbish, did itðŸ˜€ )

The layout algorithm essentially considers the slightly augmented underlying undirected graph of the diagram and splits it into as many triangles as it can. Then it tries to sort those triangles according to some rather heuristic (i.e., arbitrary) priority metric, picks them one by one, in this order, and tries to place them on the plane, edge to edge. The strategy being pure greedy, at some point in time it may happen that there are still triangles, but there are no free edges on the plane to which they could be attached. In this situation, the algorithm attempts to attach one of the remaining triangles by a vertex, that is, it tries to find such a vertex already in the plane, which also belongs to one of the remaining triangles. Finally, the algorithm adds an edge of the found triangle to the plane and restarts the process of picking triangles and attaching them by edges. This new added edge is referred to as *pseudopod*.

Now, what happens when a pseudopod cannot be grown? Initially, I was under the impression that it is rather hard to construct such a diagram. However, it turned out to be rather easy. Consider the set of objects and the set of morphisms . `DiagramGrid` will lay out the first 8 of the quite all right: as one would expect, gets to be the center of a 3×3 square, whose borders consist of the 8 ‘s. However, the last two ‘s condition the situation when there are triangles left, but no pseudopods can be grown.

In an attempt to address this problem, I have considered various possible strategies, and have chosen the following one. When no pseudopod can be grown, take the set of all objects that have not yet been placed and construct from them a subdiagram of the diagram to plot. Lay that diagram out recursively and then attach the resulting grid to the initial diagram.

One important remark is due here. This strategy is a “oh, gosh, things have gone very bad” strategy, in that is is applied only when all other approaches have failed and in that it does not really guarantee the nice look of the final diagram. However, it does provide a graceful handling of the specific situations and I do believe that the output is still going to look acceptable.

While the idea itself is rather simple, it is necessary to pay attention to what subtleties it actually brings around. First of all, the subdiagram constructed from the remaining objects is *not* necessarily connected. That’s easy to see even in the example I have shown in the previous paragraphs. Furthermore, the constructed diagrams do not necessarily have non-loop morphisms! (By abuse of graph theoretic terminology, I call a morphism with the same domain and codomain a *loop* morphism). That is, addressing pseudopod extension failures brings about the necessity to handle disconnected diagrams and one-object diagrams.

There is not much to say about the support of disconnected diagrams and one-object diagrams, but that I have implemented support for these two cases as well. The latter case is handled trivially, while the former case employs standard depth-first search of the underlying undirected graph and separate layout of the connected components. The components are currently dumbly positioned side by side, in a line, and a comment in the source code evokes the possibility of using groups to get a different layout. I’m open to suggestions of further improvements in this area, though.

It’s time to speak about my plans. I have spent more than initially expected on handling pseudopod growth failures. This means that there are still some suggestions by my mentor waiting to get fixed (I haven’t read them yet; hopefully, nothing fundamental thereðŸ˜€ ). Further, I absolutely must fix the problem with the sort key of `FiniteSet`. I have been talking about fixing it for about two weeks already, and it doesn’t seem to require that much effort. It is essential that this fix be done, though, since, without it, tests in the `categories` module fail half of the time. Finally, I will fix how morphisms are currently pretty printed by removing the use of wide Unicode symbols. These activities will not hopefully take me more than 2 days, at the very most.

Next comes the other exciting part of my project, deciding the commutativity of diagrams. I have provided the general idea of the algorithm in my proposal. Given that I am currently about two weeks behind the schedule in my proposal, and that I will still need to spend time on getting the code in the pull requests up to snuff, I’m really feeling very wary about planning my own time. However, since deciding the algorithm for deciding the commutativity of diagrams I describe in the proposals *seems* to be rather straightforward, I think I will have at least a basic working version of it two weeks from now, that is, by August 5. Allowing another week as buffer time and yet another week for merging the corresponding pull request, I do expect to be in time for the firm pencils-down date.

One last remark to make is that after the official end of the GSoC timeframe, I will still have at least one week of rather spare time (I actually expect to have about 2.5 to 3 weeks of time), which means that I will bring the code to a sufficiently polished state despite any possible lags.

]]>

In terms of material progress, this week has been rather unimpressive: I haven’t written that many lines of code and that which I have written has introduced seemingly inessential changes to the aspect of the diagrams. Nevertheless, I think this week can be marked as one of the most thought-intensive.

In the beginning of this week I have extended the drawing of curved morphisms to take into account the situations when there are multiple morphisms between the same two pair of objects. This allows to automatically typeset diagrams such as Diagram 1.

The next two days I have been smashing my head against the simplest approach to the problem of positioning morphisms labels such that they don’t get intersected by morphisms. The upsetting part is that, despite the amount of thinking I have done and the amount of code and comments I have written, the actual output hasn’t really got much better. (It may be considered to be a success, though, that it hasn’t got much worse either ). Consider Diagram 2. No special care about the position of the labels is taken.

Now consider Diagram 3; notice that the labels are now on the outer sides of the diagram. The trick basically (very basically) consists in detecting those morphisms which form the outer edges of the diagram and then placing their labels on the proper side. While for vertical and horizontal morphisms the procedure is pretty straightforward, for diagonal morphisms I resolved to apply some basic ideas from analytic geometry and yes, I even do floating-point computations (although I of course try to do them as little as possible). Nevertheless, the approach I have implemented feels very far from perfect. I hope though that I have managed to achieve some balance between code that works sufficiently fast and well and code that is intelligible. Note that the positioning of the labels of the morphsisms which are in the bowels of the visual structure of the diagram remains pretty arbitrary, which may sometimes get ugly.

The next feature I have added is the possibility to draw “loop” morphisms, i.e., morphisms which have the same domains and codomains. While proper layout of such morphisms is not guaranteed for very crowded diagrams, this functionality is of some use, as can be seen in Diagram 4.

Finally, I have implemented the support for custom arrow formatters. Arrow formatters are associated to morphisms properties. Whenever a morphism with some properties is typeset, after the necessary thinking has been carried out, the resulting data is passed to the formatter. The formatter is free to modify anything it wants in order to influence the appearance of the arrow. A common usage is shown in Diagram 5. This effect was achieved with a two-line formatter.

I must confess that dealing with hash randomisation-related issues takes up much more time that I always expect. I have been constantly getting back to certain bits of my code and adding new and new invocations of `sorted` to assure stable output. Working on this, as well as on some obscure tuning of small details of the diagram is actually what has consumed the bulk of my time this week. The visual input of such modifications is usually minimal; yet, I do believe they bear a rather important role.

]]>

The work I have done this week belongs to two essentially different classes. In the first half of the week I was still adding new features to the layout functionality; this is mainly about logical groups, which are a way for the user to exercise some control over how the objects are laid out. The idea behind offering the user some control over the layout is that `DiagramGrid` cannot always guess which placement of objects would be the best for the user, additional input would be very welcome on such occasions. It was important though to require this input in such a way as to demand as little effort as possible on the part of the user.

Take a look at the definition of a pullback. In this diagram, one can easily see that the objects , , , are distinctly separated from the object . It is easy to note further that many of universal properties also rely on such semantic grouping of objects. Further yet, in a lot of diagrams, logical groups are easily seen, as it happens in the case of the five lemma. These observations have made me think that allowing logical groups would be a perfect addition to the existing automatic layout functionality.

In the current implementation, the user specifies the logical groups by supplying a set of sets of objects. Thus, in the case of the five lemma, the user can supply the set as the description of the groups that can be seen in the diagram. In the case of the pullback, the following set would be a valid specification: . Note how it is not necessary to include separate objects in singleton sets.

One more detail on how the groups are handled, about which I am not yet very sure, both in the meaning of utility and test completeness, is that groups can be nested to arbitrary depth. This is because the current procedure of handling groups is as follows: all supplied elements of the supplied set of groups, which are sets, are considered as diagrams in their own right and are laid out. The algorithm does not really look into the structure of such a group before going into recursion. After having laid out each of groups, the current implementation constructs a dummy diagram, starting from the original one in the following way. The new diagram has as objects all objects and groups included in the groups set. If between the objects of any two groups there exists a morphism, it is added to the new diagram. Duplicate morphisms of this kind are essentially omitted for efficiency reasons. This new dummy diagram is laid out. Then, in the resulting grid, the cells (and the respective rows and columns) which correspond to groups are expanded to hold the grids into which the groups have been laid out.

The procedure I describe is rather simple, which makes me believe that it is also robust. Nevertheless, I cannot say I am fully satisfied with how much I have tested it; somewhat pessimistically, I do expect quite a number of bugs.

While logical groups seems to a be rather powerful feature already, it does not help get the layout of the five lemma just like it is usually laid out. Moreover, I noticed that the current algorithm would never lay out a line diagram in a line. To avoid this I have added a hint to the layout functionality which would instruct the usage of a different layout algorithm, and which would result in a more line-like shapes. This algorithm essentially does a depth-first traversal of the underlying undirected graph of the diagram and places the objects according to their distance from the root. Now, since I wanted to see such a layout applied to some logical groups as well (cf. the five lemma), I have implemented the possibility to supply separate layout hints for each group. With these instruments at hand, as well as with the simple hint `transpose` which instructs the layout engine to eventually flip the grid about its main diagonal, it is possible to give `DiagramGrid` sufficient information to have the five lemma laid out properly.

While I think that this result is pretty satisfactory, it would of course be way cooler to have `DiagramGrid` guess such stuff automatically. It is a rather nontrivial task, however. Take the five lemma, again. It can be laid out in a line, and look not that bad. It seems very hard to decide automatic criteria to answer such questions. Yet, I expect that nice results can be achieved by diversifying the controls offered to the user in what concerns the layout.

I am also considering the possibility of a partially manual layout (and, eventually, a fully manual one), by specifying the exact initial positions of some of the objects. I believe this would be very useful in the long run, because it would offer a great deal of control, and wouldn’t still require much unnecessary effort on the user side. The implementation of such a thing is however still a matter of the future.

I have finished the first half of the week by documenting the layout algorithm in the source itself, as well writing proper docstrings for `DiagramGrid` and its methods.

The second half of the week I have spent working on producing actual Xy-pic code. As expected, the most difficult part lied in drawing bent arrows. I have implemented some basic routine to solve this question. The pinnacle of the currently available functionality is shown in the figure.

There is a bit of work left, however. First of all, notice how the arrow curving from to is too close to the objects it passes by. I plan to solve this by increasing the default amount of curving. Further, nothing will currently be done if another morphism between these two objects is added, which results in ugly overlaps. Yet another important problem is positioning of the labels of the morphisms: some of them are too loose in space and it is hard to understand which arrow they belong to. The label is even crossed by the arrow . Unfortunately, I don’t expect to solve all of these problems with positioning of morphisms labels, because, in many cases, it would be necessary to know the actual graphical information, which is impossible at the current level of abstraction.

Thus my immediate plans are to fix the problems I have enumerated to as a complete extent as possible, and to then submit the layout functionality and the actual drawing functionality as two pull requests, to facilitate review.

]]>

OK, it’s time to take a general look over what has been done. In the end, I will describe my short-term further plans a bit.

First of all, the goal. When you want to lay out a (commutative) diagram, you should really aim at grid layout. This is how people normally typeset diagrams in articles, and this is the thing the semblance of which I would be happy to achieve. The resulting grid layout is one of the traits of diagrams which make the task of automatically drawing them different from the task of automatically drawing a graph. The other specific feature is that, when you get a diagram, you can (and you should) actually throw away those morphisms which are not really interesting. In the following sections, I will try to describe the philosophy behind the functionality I have implemented, for each bit in part.

The first stage of the algorithm is to remove the **uninteresting morphisms**. At this stage, those composite morphisms which have no properties are discarded; identity morphisms without properties are discarded as well. In fact, this corresponds pretty well to how people draw diagrams. This first stage ends by merging the premises and the conclusions of the diagram into a single container. This is because, at drawing, the distinction between premises and conclusions is not important at all, since all interesting morphisms should make their way into the final picture.

At the second stage, the algorithm abstracts morphisms away, in favour of unoriented edges between objects. The code builds the so-called **skeleton** of the diagram (that’s an ad-hoc name). The skeleton is a graph which has all objects of the diagram as vertices. Between two vertices of the skeleton there is an *undirected* edge, if these objects are connected by an (interesting) morphism. Notice how we discard the direction of the connection. After all edges corresponding to morphisms have been added, the skeleton is further completed in the following way. An edge is added between any two objects and for which there exists and object such that and are connected with an interesting morphism and and are connected with an interesting morphism. This is *not* the transitive closure of the graph, it is only the first step of it. The new edges are dummy edges, in the sense that they may not correspond to interesting morphisms.

The next stage is the first key stage of the algorithm. The skeleton is tesselated into triangles, which will eventually be used to get as many right angles in the layout as possible. Here is when the dummy edges come into play. Their presence assures that the diagram can be completely split into triangles. For those who have read my proposal, I will remark that all the stages of diagram analysis I described *after* laying out the triangles are actually unnecessary, namely because of these dummy edges, which guarantee that we have sufficiently many triangles. Yet, dummy edges are indeed dummy, in the sense that most of them will not appear in the final diagram. This makes the triangles we find in the skeleton unevenly interesting to us. Triangles which have more than one dummy edge are totally extra, because they would distract the attention of the code from triangles with more meaningful edges and would mess things up, generally. Therefore, such triangles are immediately dropped.

Once the “triangulating” stage is complete, the core of the algorithm comes into play. Basically, the idea is to pick one of the triangles, pick one of its edges and put it on a grid, horizontally, remembering that it is in the fringe. Then, iteratively, “**weld**” interesting triangles to the fringe, eventually placing all objects of the diagram on the grid. This part is the trickiest part of the whole algorithm, so prepare to hear a talk about a lot of magic

Any triangle is placed on the grid as a right-angled triangle, with the perpendicular edges being horizontal and vertical. This assures that we keep “quite” close to the desired grid layout. Whenever a triangle is placed on the grid, the objects which form its vertices are recorded as already placed. Then, those triangles which only contain objects which have already been placed (uninteresting triangles) are dropped. That is, once the places of some objects are decided, those objects are never considered again. This may constitute a point of future improvement, of course, because objects are often drawn in several copies to make the diagram look clearer.

When placing the triangle on the grid, the code attempts to assure that as many interesting (not dummy) edges as possible will be drawn horizontally or vertically. There is some dark magic in the code which detects such situations, but I hope that after following the trail of comments and just reading the code itself, the whole thing should become rather clear.

Now, since the algorithm is essentially greedy, there can be situations when all edges to which the remaining triangles could have been welded, have already been positioned inside the structure and it is now impossible to find the welding edge. In this case, the algorithm attempts to attach a triangle to the existing structure by a vertex only. If such a possibility is found, an edge (the **pseudopod**) of the triangle is placed as vertically (or horizontally) as possible and then the welding process can be continued, since there already is a welding edge.

Let’s now focus on what happens to the fringe. When a new triangle is welded, the two new edges are added to the fringe. No edges are deleted however, because the welding edge might still have some free space to its other part. Edges are deleted from the fringe only when they are detected as possible welding edges, but when the algorithm finds that there is no space around them actually. I have considered several possibilities of correcting the fringe on different occasions; my conclusions so far have been that it’s not generally worth it, performance-wise. This question however should be better investigated, including doing some complexity analysis.

You might have noticed that I do not in any way treat the situation when a pseudopod cannot be grown. I have not encountered such situations during the testing yet, so I decided not to attempt to handle them before I have actually seen an example. Taking into consideration that I am going to work with diagrams rather intensively later, if such situations are possible, I will indeed run into them. I must confess that I haven’t considered the problem theoretically yet, though

The description of the essential parts of the algorithm is complete here, so I’m passing over to the overview of the remaining problems and further short-term plans.

Tom Bachmann, my mentor, has suggested that I describe the steps of the algorithm in the docs which come with the source code. I will do this shortly. I believe it is essential to write such documentation as soon as possible, despite the abundant (hopefully) comments in the code.

My immediately next task is, however, producing the actual Xy-pic code. I expect that getting this done at a basic level shouldn’t be hard. However, drawing longer morphisms and avoiding intersections for as much as possible may prove a rather hard task to achieve.

Oh, and the almost forgotten conclusion: I now essentially have the core of the automatic diagram plotting functionality, since laying out objects is the most difficult part of the affair.

]]>

Well, I guess I don’t really have to expect anything any more, since I am already thrilled: a couple days ago I found an awesome LaTeX package, Xy-pic, which allows typesetting precisely what I need: diagrams with grid-like layout. This Wikipedia page shows how easy it is do produce a commutative diagram with this package. My initial plan was to go with TikZ, which is also awesome, but it is much better for more general drawing tasks. With TikZ, it would have been necessary to manually arrange objects in the diagram in a grid, place text over arrows, and decide as to how the arrows should curve. This is not the most difficult part of the diagram drawing business, but it is always nice to use some stuff which someone else has already done (better).

In this post I will try to outline how I see the implementation of the diagram drawing functionality now, after I have went through the review process of my first large chunk of code in SymPy.

According to the proposal, the process of drawing a diagram includes two stages. After the first stage, the matrix which will serve as the outline of the visual representation of the diagram should be constructed. I plan to have the whole first stage done in the `DiagramGrid` class, which will be constructed from a `Diagram` and will act a lot like a matrix in that it will be possible to see its dimensions and what lies at a position given by rectangular coordinates. It will also be possible to find out which morphisms connect a certain node in the matrix to other nodes, and whether it is likely that it overlaps with other morphisms or not. Here the job of `DiagramGrid` ends. A minor remark is nevertheless due before proceeding to the actual drawing. In the proposal I stated that certain objects which don’t fit easily in the existing matrix will be arranged in a circle around the existing structure. I have abolished this, because it will break the idea of typesetting the diagram in a matrix, which makes the whole thing considerably harder to handle. Instead, these “unfitting” objects will be placed along one of the four edges of the frame of the diagram, while the morphisms going into these objects will be marked with the flag which shows that they may overlap with other morphisms.

The second stage of the diagram drawing process is actually typesetting the diagram matrix using Xy-pic. This part should be pretty straightforward, since it is basically about putting the matrix that has resulted from the first stage into an Xy-pic matrix. I plan to have the second stage of drawing implemented in the class `DiagramGridDrawer`. This class will contain the method `draw_outline`, which will return an Xy-pic representation of a `DiagramGrid`. The drawer class will have a dictionary of morphism name formatters, which will associate a property to a function of one string argument. For example, the property “exists” may be associated to a function which prepends its argument with the mathematical symbol “exists”. The drawer class will also have a dictionary of morphism styles, which will map string properties to arrow styles. I have also considered taking advantage of the fact that morphism properties are not enforced to be strings, and putting some additional formatting information into those properties. I am not yet sure that it is necessary, though, so I don’t include this into the plan.

Now, there are some changes to the timeline in the proposal, which are caused in part by the fact that I have spent so much time on bringing my first pull request up to scratch, and in part by the fact that I now have a slightly different vision on how to implement the drawing. Thus I plan to spend the coming week, June 18 – June 24, on implementing `DiagramGrid`. Then, in the next week, June 25 – July 1, I plan to implement `DiagramGridDrawer` and extensively test both classes. The week July 2 – July 8 I reserve for getting my changes merged. Not that I expect to spend a whole week on this; but I’d rather allocate slightly more time, with some reserve, than make promises which I may fail to fulfill.

I would like to explicitly remark the fact that the changes to the timeline do not delay the moment when I plan to have the drawing functionality ready. Therefore I’m still not too far astray from my planned timing

]]>

The most important change concerns morphisms. In my initial version, I had one class to represent any morphism. When fitting it into the architecture of SymPy, it turned out that distinguishing between an identity morphism and a non-identity morphism wasn’t quite that easy, because it is impossible to store a Python Boolean value in `Basic.args`. The suggested solution was to splinter identity morphisms into a separate class. Later, my mentor Tom Bachmann noticed that an even finer granularity was necessary. Indeed, according to the code defined at that moment, if a morphism was a composite, *and* had a name, then that name wouldn’t matter at all at comparisons or at printing. Therefore, composite morphisms don’t really seem to be the same kind of beast as named morphisms. And yet again, identity morphisms belong to a separate class of things.

According to this idea, I completely threw away the old `Morphism` and `IdentityMorphism`, and replaced them with `NamedMorphism`, `IdentityMorphism`, `CompositeMorphism`, and a different `Morphism` to serve as the base class. I have also removed the possibility to create anonymous morphisms. This has resulted in shorter, easier to use, more flexible, and less error-prone code. The experience was absolutely great

Besides this change, I’ve done numerous corrections and enhancements, which have hopefully brought my code up to scratch. I have received the relieving “almost good to go” comment from my mentor; sounds almost unbelievable

The downside of this is that I have spent on grooming my code *considerably* more time than I initially expected. This means that I have to hurry up with the next sections of my timeline.

This week I have also found something which will hopefully make implementing the diagram drawing functionality more piece-of-cakely: Xy-pic. My next bit of effort will therefore be directed towards mastering this package and adapting my initial plan to this (rather radical) change of strategy. This will be reflected in the next blog post, which is due to come soon. Very soonðŸ˜‰

]]>

First off, I have finished working on the first phase of the project, entitled “Base Classes”. Â In the course of this phase I have implemented the base classes (oh yeahðŸ˜‰ ) of the category theory module, which includes `Object`, `Morphism`, `Category`, and `Diagram`.

The names of the classes were meant to be self-documenting, but there are a couple gotchas which are determined by the pre-incipient state of the module. In the following paragraphs I will try to briefly overview the classes and point out the things which may be unexpected.

The first two classes in the enumeration are pretty straightforward. The class `Object` represents an object in an abstract category. Since we’re talking about abstract categories, an object is little more than its name. The class `Morphism` represents a morphism in an abstract category, which is little more than just an arrow from an object to another object. Correspondingly, a `Morphism`, has a string name, an `Object` which is the *domain* (the object where the arrow begins) and *codomain* (the object where the arrow ends). Now, morphisms can be *composed*. Thus if you have a morphism from to (which are objects in some (asbtract) category), and a morphism from to , then you can take their composition, which is a morphism from to . This composite is often denoted (mind the order). The morphisms themselves are often written as and . These two morphisms are called *composable* in this order.

While in some concrete settings like set mappings, group homomorphisms, etc. the composite function/homomorphism acts in a well-defined way, there’s no way to define the action of an abstract category theoretic morphism. In correspondence with this, compositions of `Moprhism`‘s yield other morphisms, which store the components they were obtained from inside themselves. Composing morphisms which were already composed is all right, since a `Morphism` always stores the flattened-down version of the list of components. Thus a `Morphism` representing , the composite of and , will store the list of three morphisms representing , , (again, mind the order).

A morphism of the form is called an *identity* if for any two other morphisms and one has and , that is, identity morphisms are identities with respect to morphism composition. Instances of `Morphism` which have the flag `identity` set, behave exactly as one would expect them, i.e., if you try to compose with them, nothing happens (of course, I’m talking of the situation when you take a *composable* morphism).

So far so good. Here come the gotchas of `Morphism`, however. Morphisms are compared by domain, codomain, and name. Thus for the representations `f1` and `f2` of and , `f1 == f1` is `True` and `f1 == f2` is `False`, even if `f1` and `f2` are actually the same morphisms with different names. Now, that’s quite understandable, since a `Morphism` cannot really know what you *actually* want However, with the implemented apparatus, you *can* state that `f1` and `f2` are actually the same thing. Read to the end to find out howðŸ˜‰

On a side note, `Morphism` is sufficiently clever to know that all identity morphisms of the same object are equal, no matter the name.

Next comes `Category`. Unfortunately, at the moment this class isn’t capable of doing much useful stuff. One of the reasons is that the notion of a category is based on the notion of a set-theoretical class, which is not implemented in SymPy yet. More importantly, though, for the purposes of this GSoC project, an essentially primitive `Category` is perfectly enough. A `Category` has a string name and a set of `Diagram`‘s which are asserted to be commutative in this category.

The last and the most interesting class in the context of this project is `Diagram`. A diagram is a very cool way to write a lot of stuff in category theory and in algebra in general. A diagram is basically a bunch of objects from a category and some of the morphisms between these objects. Â Diagrams are usually drawn, objects being represented as letters and morphisms as arrows between the letters. Â A diagram is said to be *commutative*, if all paths between any two objects and in the diagram yield the same morphism. Â For example, if the diagram in the figure is commutative, then .

The class `Diagram` is meant to represent such diagrammatic structures. It cannot be plotted as yet; what it can do is storing a bunch of morphisms. A `Diagram` does not know whether it is commutative or not; however, one can assert that certain `Diagram`‘s are commutative in a ceratain `Category`.

`Diagram` is actually meant to store something slightly more general than what is shown in the picture. Suppose that the author of the picture has wanted to say that, if is an isomorpism, then there exists a unique moprhism such that the diagram commutes. Authors often want to say such things, therefore `Diagram` contains *two* sets of morphisms: the `premises` and `conclusions`. Well, actually, those are not sets, but rather dictionaries, mapping morphisms to their properties (which are really just strings). Thus an instance of `Diagram` is read as follows: “If there exist such morphisms as in `premises` with corresponding properties, than there exist such morphisms as in `conclusions` with corresponding properties and the diagram is commutative”. You can also state simpler statements which don’t look like logical implications by not using the conclusions part of the diagram.

Now, `Diagram` is awesome enough to also include all composite morphisms in premises (and in conclusions, when necessary). If you specify that and are in the `Diagram`, then you don’t have to say that is in the `Diagram` as well. There’s a small thing to keep in mind here: you sometimes add morphisms *with properties* to a `Diagram`. When `Diagram` adds the composite to itself, the properties of the composite will be the *intersection* of the properties of and . You can always override this by explicitly adding the composite with a different set of properties.

And finally, as I promised, I’ll tell how to state that and are equal, despite different names. Well, just create a diagram with these two morphisms and assert it as commutative

And yet even more finally, I’d like to tell about a bit of programming experience I have found exhilarating this week. I’ve learnt a very cool lesson: write your tests before the implementation whenever possible! There’s no better formal way to write a specification than to write tests. I was totally amazed at how this practice streamlined my workflow!

Image source: http://en.wikipedia.org/wiki/File:Commutative_square.svg

]]>