Tuesday, February 4, 2020
I eventually got around to asking what the gentleman did for a living (I understand that in some countries asking about someone's work is considered rude, but not here). To my surprise, it turned out he is working for the same company I am. He was visiting from North Carolina where he worked out of the Durham office. He was one of the early employees of the company and knows a lot about the architecture of the product and was out here to train new sales engineers about how the product worked. Although he was in sales, he was an engineer, so we had a lot in common. We talked late into the evening about work, college, cars, music, mathematics, and other various topics. I got a lot of good background information on the company and the product from him.
I suppose there's no real point to this story. It's just interesting how chance meetings sometimes turn out.
Saturday, January 25, 2020
Case in point, I just added a column to a table. The problem: the column isn't wide enough to hold the data it displays, so the data runs out of the column and into the next one, overwriting the text there. Simple problem. Simple solution? No. It was easy enough to add a style element to the column making it wider. But now the column header didn't line up with the column. I added the same style element to the header, but it was completely ignored. In fact, nothing I could think of would make the column header simply be wider than it was. There were 12 columns, and each header took 1/12th of the space. That was written in stone.
Well, almost. I made there be 13 columns, and set that one particular header to span 2 columns. I had to do the same to the data and make it span 2 columns as well. It does not look good, but that particular column is now wide enough to hold the data, and the header lines up above the data like it should. Unfortunately, each of the other columns are just that much narrower to spoil the layout. There are some columns that would naturally be nice and narrow and give me lots of extra room to play with, but no, there are now 13 columns, each taking 1/13th of the space, except for one that's twice as wide.
This is why I don't like UI. Why does the table data pay attention to the "width" directive and the table header ignore it completely? I don't know. Will anyone complain that my "solution" is ugly? You bet. I even think it is ugly. I've already wasted enough thought and energy trying to make it prettier, but to no avail.
Tuesday, January 21, 2020
Even if no one takes me seriously, though, at least they get some cheap entertainment watching me try to muddle through my confusion.
I'm starting a new job today, so blog posts will likely be shorter and less frequent. With luck, however, I've gotten back into the habit of posting regularly.
Please keep the feedback coming. I read every comment, though I don't answer many (most don't require an answer).
Sunday, January 19, 2020
In a previous post I discussed how the elements of a group could be seen as “acting” on other elements directly as if they were functions. There's a more direct way of getting at this, but it is so simple, it might be a bit of a disappointment. But we'll take things a bit further.
First, let's consider the group with the element 0, 1, and 2 where the binary operation is addition modulo 3. It is closed, associative, 0 is the identity element, and 1 and 2 are inverses of each other. It is a group.
;; save the real multiply > (define real-multiply *) real-multiply > (define (* a b) (modulo (+ a b) 3)) * > (* 0 1) 1 > (* 1 1) 2 > (* 2 2) 1But the elements of the group aren't functions, they are integers. They cannot directly act on other elements:
> (1 2) Error -- application of non-procedure object 1
There's a simple trick to get directly at the “action” of an element on another element. Just “curry” the
> (define (get-action operator element) (define (action other-element) (operator element other-element)) action) get-action > (define action-of-1 (get-action * 1)) action-of-1 > (action-of-1 2) 0 > (action-of-1 1) 2See, that's almost disappointingly simple. Of course the other elements in the group will have their own actions obtained in the same way:
>(define action-of-0 (get-action * 0)) action-of-0 >(action-of-0 1) 1No surprise that the action of the identity element leaves things unchanged.
Let's consider a different group. This group also has 3 element,
'(a b c),
'(b c a), and
'(c a b). The operator is a funny sort of list rotation: if the first argument is
'(a b c), it doesn't rotate the second argument at all. If the first argument is
'(b c a), it rotates the second argument left by one position. If the first argument is
'(c a b) it rotates the second argument by two positions:
> (define (funny-rotate first second) (cond ((equal? first '(a b c)) second) ((equal? first '(b c a)) (rotate-left second)) ((equal? first '(c a b)) (rotate-left (rotate-left second))))) funny-rotate > (funny-rotate '(a b c) '(b c a)) (b c a) > (funny-rotate '(b c a) '(c a b)) (a b c)You've probably noticed by now that this second group is a disguised version of the first group with
0 <=> (a b c) 1 <=> (b c a) 2 <=> (c a b) (modulo (+ a b) 3) <=> (funny-rotate first second)This is an example of an isomorphism between two groups.
Suppose, for the sake of argument, that this second group is just like it currently is, but it had a few more elements that funny-rotate knew how to handle. But otherwise everything else is the same. Then there would be elements that didn't have a one-to-one mapping. This wouldn't be an isomorphism but a monomorphism. These are both kinds of homomorphisms between groups. (The wall of terminology appears.)
Let's back away from the wall of terminology for a moment and go back to the action of an element. Notice that the action of an element is a function. It maps elements to elements. The action is actually a bit more abstract than that. We can swap out the elements with the elements of an isomporphic group. So the
action-of-1 which carries
2->0 can be considered the same action that carries
'(a b c)->'(b c a),
'(b c a)->'(c a b), and
'(c a b)->'(a b c). Even though
1 doesn't even belong to the same group as
'(a b c), we can consider
action-of-bca to be the same thing.
The action is even a bit more abstract. We can swap out the operator of the action, too. Here we have to be careful to make sure we don't ruin the group structure when we do that. To give an example, consider the conjugate of some action on some argument:
(conjugate (f g)) = (h f) where we've found the
h that makes
(h f) equal to
(f g). Recall that
h is equivalent to
fgf-1. We can, without ruining the group structure, give each element in the group the action of conjugating it's argument. (Just to throw out a little more terminology, when a group element acts on other elements in the same group, it's called an automorphism.)
We can, if we are careful not to ruin the group structure, swap out both the operator and the elements of the action of an element. But let's not do that. Let's return to simply getting the elements of the group to act on each other by currying the operator. This is a nice, easy to understand automorphism. In our examples, our groups have three elements. You can imagine them as sitting on the corners of a triangle. One element is the identity element, it leaves everything alone. One element bring
2->0 or the equivalent, and the final element undoes it, bringing
2->1. If they were sitting on the corners of a triangle, one element rotates clockwise, one elements rotates counterclockwise, one element does nothing. These automorphisms simply permute the elements of the group. And it has to be so. Because each element has an inverse, we have to be able to determine what the “input” element was associated with the “output” element, so each unique input must lead to a unique output, which makes it a permutation.
Ok, one more thing. Permutations are associative. If you have a set of permutations that are closed, includes the identity and all the inverses, then you have a group of permutations (called the symmetric group, even though there are many because it depends on how many items you are permuting. Better to parameterize by the number of items and call it symmetricn.) Cayley's theorem says that every group is a subgroup of the symmetricn group acting on the elements. That is, every group has some symmetries associated with it. The symmetries can help you gain insight into the group. This is pretty remarkable: we started with foldable sequences with identity elements and inverse elements, and we ended up with deep connection to symmetries.
I just wanted to get to as far as Cayley's theorem, so I'll end this now. I hope there wasn't too much terminology, but I'm afraid there was enough abstraction to make me dizzy.
Monday, November 25, 2019
It's a vulgar saying, but true. It is one of the primary reasons I don't blog much about work. But I don't work for Google anymore, and my consulting gig at Blue Origin is finished. So I think I'll be blogging a bit about working at Google and a bit about consulting. Of course I'm obligated to not deliver the “real dirt”, so I won't say anything you couldn't find out through public sources, and everything I say will reflect the past, not the present. Things may have changed.
I stayed at Google several years longer than I should have. It left me a bit ill-prepared for the real world. At Google, we used mostly custom, in-house software development tools. Google's build tool, Blaze, was released to the outside world as Bazel, and it does a lot of what Maven and Artifactory do for building and tracking build dependencies. There was a way to use git with the source control, but it was optional and I preferred to use the Perforce-like interface directly. We didn't use a tool like gitlab for code reviews, we had our own in-house tool. We used protocol-buffers for inter-process communication, not JSON generated by Swagger. Google's internal cloud was built long before Kubernetes. The tools provided were all decent tools, but they aren't the “industry standard”, and when I started consulting I was a bit at sea with a tool set that was similar, but not exactly the same thing. The fact is you have to be familiar with a lot more tools than you used to be: autoconf, make, and GCC don't cut it anymore.
The consulting gig was a trial by fire. I prefer programming the back-end and systems level to programming the front-end and user-interface, but out of necessity I got to write Angular, and typescript, use node.js, and write GraphQL queries to support the UI. I got to store things in MongoDB rather than in Bigtable. I even used IntelliJ instead of Emacs (somewhat. I still used Emacs for serious editing.) And although both jobs made use of Java, even it has changed a fair bit.
So I'm looking forward to the my newest job and I expect the learning curve to be not quite as steep. No doubt there will be some new tools but probably not all new tools.