Saturday, October 31, 2015

2013 Heartland 100

Run October 12, 2013

Watermarked photos by Mile90 Photography used with permission

Under the heading of truly bad advice is the maxim: "Shoot for the moon and you'll reach the treetops." Well, no, you won't. You'll waste all your time trying to raise several billion dollars for a rocket ship rather than doing something useful like buying a ladder. Dream big, but keep your actual goals realistic. That said, one never knows what realistic is without setting a few goals that call that into question. And it was with that in mind that I decided I would try to win the Heartland 100. I've never even won my age group in a 100, much less the overall, so this was definitely throwing one out there.

Of course, the feasibility of such a goal is highly dependent on who else shows up. Running a 100 well means tending to one's own progress and not that of others, so I build my strategy on the assumption that the winning time will be somewhere between 17:30 and 18:00. I'll run my pace to 75 and, if the leaders are in reach, join the fray. My PR is 17:50 at Mother Road which featured similar profile and slightly cooler conditions. The main difference is that all but a mile of this one is gravel, whereas MR100 was predominantly paved. I'm not sure if that's a big distinction. It's a stretch, but not crazy.


I don't know if this is unique to me or a common pattern, but in every 100 I've done, the third 25 has been my slowest, usually by a lot. I seem to hit a trough, both emotionally and physically, around 60 miles that takes a few hours to pull out of. After that, I can usually get back on pace to the finish. Rather than hope that doesn't happen, I decide to plan for it. Prior to the event, I do several runs on gravel at just over 10:00/mi to get myself used to the pace I'll run for the first half. Depending on how efficiently I get through aid stations and other vagaries of competition, that should have me at the turnaround between 8:30 and 8:45 which allows for a crappy third quarter without giving the game away.

I arrive in Cassoday, KS Friday afternoon in time to catch most of the pre-race briefing. The only item of note is that we should expect to see cattle on the course. We're told to just walk calmly if they are on the road and they shouldn't be any trouble. I have an uncle with a cattle farm and have enough experience with these animals to believe that, but I'm still hoping they leave me alone. Less of a concern are the prairie chickens, of which Cassoday is the self-proclaimed world capital. I generally don't dispute such assertions, but not seeing a single chicken of any type all weekend, I feel the good folks of Cassoday (all 39 of them) may be guilty of puffery.

The pre-race meal befits the race's "Spirit of the Prairie" tag line: hearty casseroles of meat and potatoes accompanied by rolls and rather tasty desserts served by cheerful women in homestead outfits. I assume the dress is intended to enhance the feel of the race, but it may be standard attire for these parts. At any rate, it's a darn good meal; far better than the typical fare of overcooked pasta and soggy bread.

I've only brought one drop bag and I churn a bit over which station to send it to. I have a change of shoes (which I don't intend to use, but it's always good to have the option), some warmer clothes for the night, and my brighter light. Since we're on roads the whole way, both my lights are tiny, but the one I'll start with (and carry the whole race) is an older LED that doesn't throw quite as much light. Teterville, at 25/75 miles seems the most logical since the forecast doesn't call for anything too cold prior to the 16th hour of the race. In contrast, David Stores, who traveled with me, has a box for nearly every station. Even though he doesn't plan to use them all, he likes having options. There is probably some merit to that; it's just not the way I've ever done it.

As Cassoday makes no claims about being the lodging capitol of anywhere, we have to drive a half hour back to Emporia for the night. Once settled in, we go for a short jog to loosen up during which we observe that we'll want headlamps starting at about 7:30PM, thirteen and a half hours in. We set multiple phones and watches to alarm at 4AM and get to bed early.

The hotel breakfast doesn't start until an hour after the race is on, so I make my own oatmeal in the morning. We drive back to Cassoday and collect our timing chips. There's no wind (yet), but the 46F temperature is enough for me to opt for a full sleeve shirt on top of my racing T. My gloves and warm hat are in my drop bag, but I figure I'll be OK without those. A Thunderstorm is raging to the east, but there's nothing but stars overhead. The forecast is for clear skies well into tomorrow. Shortly before 6, we are lined up, given some last-minute instructions (none of which I remember), and sent on our way.

Thanks to my pace training runs, I have no difficulty finding the correct pace (though it still seems crazy slow). There's a fair bit of shuffling positions early on, but by mile 2, I seem to be settled into around 30th place in the field of 120. David is running alongside me as is Amy Ewing from Fort Worth. We strike up a lively conversation during which we find that this is her first 100. She also drops that she's run the Pike's Peak Marathon in 6:20, so she's clearly got some fitness.

We are running straight east and as the sky begins to lighten, we are treated to the sort of natural display one is fortunate to experience once a decade. I've seen the sun come up over distant mountains before and it's all very pretty. And if one was to see a still photo of this sunrise, one could easily believe that's what one was looking at. However, these "mountains" are really thunderclouds that are lighting up in choreographed patterns as the discharge chains back and forth along the front. Then, just before the sun breaks above the clouds, eight perfectly-spaced beams of gold pierce the sky. The show concludes with the blinding appearance of the sun just as we arrive at the Battle Creek aid station (mile 8.3).

The next 8.4 miles to Lapland give us our first good look at the prairie countryside, but we spend a lot of time looking at our shoes because the sun really is blinding. At Lapland, I shed my long sleeves, leaving them in David's drop bag. The aid station is at a 3-way intersection and I pick the wrong road out. Fortunately, I only get a minute down the road before somebody corrects me. David and I continue to run together to Teterville, reaching the 25-mile station right on schedule at 4:20. Aside from a very urgent need to use the porta-pottie (although there's plenty of cattle poop along the road, the complete lack of vegetation cover discourages me from adding my own), everything is going just as planned.

We are now heading north and north east, which has us feeling the effects of an increasingly strong north wind. The locals insist this is their version of a light breeze, but anywhere else in the world it would be labeled "brisk" or even "howling". It's strong enough that I have to tighten the band on my cap to keep it from flying off.

While the hills are neither large nor steep, there are a lot of them. In reality, "Flint Hills" is something of a misnomer. This area is actually a huge (as in several hundred square miles) reentrant system carved out of the plateau draining to the west. Flint Valleys would be more apt. As such, at every crest we are rewarded with an expansive view of the prairie. I had worried that seeing the road stretch out for miles ahead might be somewhat mind-numbing, but in reality I find it inspiring to find myself such a small traveler in such a large place.

Knowing that the entire profile falls within a 300-foot band of altitude, it strikes me as odd that I seem to be running uphill a lot more than down. This is always true to some degree since you obviously cover ground quicker on the descents, but the disparity is larger than expected. I finally realize that it's an optical illusion created by the fact that the road extends all the way to the horizon line. Level ground appears to be slightly uphill. On one of the longer steady grades I look behind me and confirm that the road seems to rise in that direction as well. M. C. Escher would have loved this place.

The out and back course has 18 cattle guards each way. Most of them are between Teterville and the turnaround. They aren't particularly hard to cross, though it would be an insane risk to try it at a run. My feet are big enough that I can plant my heel on one rail and my toe on the next, which makes slipping through almost impossible. Amy has to do it on tiptoes and notes it's a bit nerve-wracking to try to be precise when your legs are getting tired.

By the Ridgeline aid station at 36 miles, I'm on my own (though the visibility is such that I can certainly see other runners). Shortly after leaving, I pass a runner who is hobbling terribly. I offer some encouragement and he responds cheerfully that he'll just try to walk off the cramp. The encounter brings back chilling memories of overheating at mile 40 at Kettle Moraine and the miserable six hours that ensued before I was saved by the cool of the night.


What I experience next takes chills to outright terror. To my left, I hear the rumbling of hooves that can only mean one thing: it's a STAMPEDE! Well, that's maybe overstating a bit, but when 40 head of cattle are coming right for you at full run, it's close enough. I'm sure they aren't after me, but that fact didn't save Mufasa. There's a cattle guard just 100 feet in front of me and I sprint up to it and turn to watch the herd cross the road behind me. Seems that I got them to look and, having done that, they noticed that there was fresh hay in their feed pen on the far side of the road being consumed by a smaller group. They all want some while the getting is good and there is much jostling around the rail of the pen as the larger group muscles in. You wouldn't think that hay would be such a treat in the middle of a million acres of prairie grass, but cattle aren't the brightest beings on earth.

The Matfield Green aid station at 43 miles is run by the Kansas Ultrarunners Society, the same folks that bring us Psycho Wyco twice a year. One of the workers notes that I'm looking a bit salty. Though the temps are now in the high 70's, I hadn't noticed myself sweating, but he's right: my gray shirt is caked white. Apparently, the stiff breeze has been doing a great job of evaporating it and keeping me feeling cool, but at a significant cost to my salt reserves. I take a couple S-caps and pocket a few more for later. A quick pee break verifies that I am running much lower on fluids than I realized. I decide to back off a bit in hopes of getting the levels restored without a big break.

About 20 minutes shy of the turn, I pass the first of the leaders coming back the other way. Eight more pass before I get to the Lone Tree aid station where I am enthusiastically greeted by Eric Steele of Epic Ultras. I arrive at 8:50 (nearly 3PM), which is only a bit slower than expected, but I'm concerned that my depleted fluid levels are going to make my typical third-25 trough deeper and wider than usual. It seems a stretch to hope that all nine runners ahead of me cave and I'm in no position to mount a surge, so I decide to put the thoughts of the win out of my head and just focus on getting myself back to full speed as quickly as possible.

The climb up from the turnaround is the largest on the course. I run most of it, albeit slowly. After refilling my bottles at the unmanned station at 53, I walk for a bit, sipping water and eating some potato chips. Amy passes me and is looking really good; probably well under 10:00/mi. Despite an easy shuffle back to Matfield Green, nobody else comes by.

At Matfield Green, I begin the expected wrestling match with my own demons. Because the course is shaped like a big horseshoe, I could run directly back to the finish in just a couple hours. But, even that wouldn't be necessary as many of the crew vehicles are headed back that way. With the win out of reach and even a sub-19 looking unlikely, the impulse to pack it in is almost overwhelming. Still, everything is currently working and I am able to keep fluids down (but not much else). It seems a bit premature to be throwing in the towel.

I shuffle back to Ridgeline, losing another position in the process. There, the aid station captain insists I eat some of his beans. I'm sure they're great, but I'm equally sure they'd come back up. Rather than accept that, he gets a bit pushy, explaining to me how important it is that I get some food in me. He was trying to be helpful, but arguing with a runner who's on the brink of emotional collapse is pretty much the opposite of that. I flee the aid station nearly in tears and am about a mile down the road before I realize that I failed to get my bottles filled. The sun is getting pretty low and the breeze is still providing some cooling, so there's no chance of overheating, but it means that I'm going to go further in the hole on hydration. I run another two miles until my water runs out and then walk the remaining two to Texaco Hill.

In stark contrast, the workers at Texaco Hill offer nothing but solace. As a competitive effort, my race is over, so I sit with them a bit and we talk softly and watch the western sky darken while I down several cups of noodles and broth. One of the workers even walks half a mile down the road with me while I finish a cup of hot chocolate. I pull out my little light and resume running.

It's slow at first, but the break has done the trick. Within a mile I'm back on pace. My stomach is settled, my legs are fine, and I appear to be gaining on fluid (though I'm still a bit in debt on that front). The only significant problem is my feet. During the day it was pretty easy to miss the bigger stones. Now that my light source is a wimpy LED mounted half an inch above my eyes, the road is just a uniform gray blur. I'm wearing my Montrails with the beefy rock plate in the midsole, but I'm still taking some bruises.

I arrive at Teterville (75 miles) at 14:31 (8:31 PM). While I'm feeling OK, I decide another long stop is in order. I have several more cups of noodles and broth and also dig out my hat, gloves, wind shirt, and good light from my drop bag.

Between the better light and the gravel being a bit finer grain, I have less trouble with my feet on the eight miles to Lapland. There are several other runners at the station in various degrees of distress. My stomach is still not completely back and I don't want to take another long break, so I just grab some pretzels and eat them while walking out of the station. The next few miles are hilly, but I don't find it necessary to walk much. The hill up to the water drop midway to Battle Creek is a lot longer than I remember from the morning. After refilling my bottles, I walk for a bit. I run for another three miles, almost to the aid station and go to pieces.

Anybody who's been doing endurance sports for more than a few years knows what it feels like to bonk. The mechanism is fairly well understood. The liver turns on the low fuel light and the brain, which unlike muscles has no alternative fuel source says, "If I go, y'all go" and pulls the keys out of the ignition. There's no real discomfort, you just don't go anywhere fast.

That's not what this is. I'm sure it's some sort of hypoglycemic shock, but both the suddenness and the severity are unlike anything I've experienced in 42 years of running and cycling. I stagger wildly from one side of the road to the other, barely able to keep my balance. My vision is wavy and tunneled. The feeling leaves my hands, ears, and feet (that last part I'm OK with). I force down a gel packet and try to make sure I don't turn around and start going the wrong way (a mistake that happens more frequently than you might think in longer ultras and I now understand why). At the aid station I can recover or I can drop, but out here on the road things can only get worse. It takes half an hour to cover the mile to Battle Creek and the reaction from the aid station workers indicates that I look every bit as bad as I feel.

Abandoning all pretense, I drop into a chair in the aid tent. The fire on the far side of the road is inviting, but it's also more exposed to the wind. I'm not at all confident of my body's ability to heat itself right now. This station doesn't have noodles and broth, but they do have a good potato soup which my stomach is happy to pass forward rather than back. Knowing it's over eight miles to the finish with only an unmanned drop en route, I need to be absolutely sure I'm stable before heading out again. I spend a full half hour in the aid station. Amazingly, the only runner that comes through in that time is the leader of the 50-mile event that started at 6PM. I start to leave but don't get more than 100m down the road before I begin to shake from the cold. My wind shirt does a fine job of blocking the wind, but doesn't offer much insulation. I walk back to the aid station where I'm offered a long-sleeved cotton T. If it was raining or I was sweaty, that would just make things worse. Since neither of those are true, I take it and it does help quite a bit.

I walk the first half mile to get loosened up again, then move into an easy jog. Then a firm jog. Then I'm running again. By the water drop at 95.3, I'm moving comfortably and decide to salvage a little dignity by finishing strong. Remarkably, the legs respond without complaint (actually, my legs never gave me any trouble this run - it was the rest of my body that was in outright revolt). I run the final 4.7 miles in 44 minutes, picking off a place right near the end.

My finish time is 20:48, almost three hours behind the winning time; the furthest from the front I've ever finished in any race of any distance. My 13th overall is the first time I've been outside the top 10 in a 100. So, cynics can certainly have their laugh at my aspirations to win this one. Not being one of those, I see it differently. Stretch goals, by their very nature involve risk. You may succeed or you may fail catastrophically. There isn't much room for middle ground. Further, the battle plan was pretty sound as evinced by Amy's strong second half. After ditching me at 54, she moved herself all the way into the lead before eventually slipping to fourth (first female). It's exactly the pacing I was trying to run. That's not to say I could have done it; just that it was doable.


Lessons? Well, the obvious one I already knew: little things become big things the longer the race goes. I simply missed that I was getting salt depleted. In a shorter event, I would have got away with it; in a 100, you pay. It also appears I took my recovery too much for granted. A longer stop for another cup of noodles at Lapland may well have been all that was needed to avoid the meltdown at 91. Never assume all your debts are paid until you cross the finish line.

Regrets? None whatsoever. That said, I think I'm going to step back from 100's for a while. They're just a bit too far for me to find them enjoyable. I know that most people would regard that as comically understated, but it's a distinction that matters to me. I simply find it much more interesting to be knocking out 8:30 miles in a 50 than 10:30's in a 100. Maybe I'd like the distance more if I backed way off so I didn't experience so much duress. Or, maybe it would be fun if I could run 8:30's for 100 miles. But those two options strike me as the ground and the moon. I'm still aiming for treetops.

Note 10/2015: now that I'm in grad school, the ground is sounding like a better target. As such, I've started running 100's again; not as races, but to stay connected with the sport and people who are such a big part of my life.

Friday, October 30, 2015

The switch

I may have just made my life more difficult, but I'm pretty comfortable with the decision.

As I noted a few weeks ago, I haven't been getting much traction with the CS faculty on my thesis topic. The math faculty has been much more interested. So today, since the departments are combined at UMSL, I switched my concentration from Computer Science to Statistics.

My life is now more difficult because, all modesty aside, I'm qualified to teach the majority of UMSL's CS courses, even at the graduate level. In statistics, I'll be taking in a lot more new material. Mitigating that is the fact that the norm in the Math program is to do a lot more directed study rather than formal classroom instruction. This is a much better paradigm for me and it should allow me to focus solely on the things I don't know rather than having to sit through lectures where I already get it. Also, directed study can be tailored to fit my thesis topic, so I may save some effort there as well.

At any rate, it's new and exciting, and I'm really glad I'm making this switch. I honestly feel like I can get through just about any course on my own. What I really need from the faculty is support for my research. Now I have it.

Thursday, October 29, 2015

Call by Name

This evening's lecture covered (among other more mundane things) the paradigm of Call by Name. Sebesta uses general purpose examples. Unfortunately, it's difficult to create good general purpose examples. It's very easy to create examples that make you think the whole concept falls under the heading of REALY BAD IDEA, which is why most general purpose languages don't support it. (And, please don't go the route of arguing that macro expansion is call by name - that's done at compile time which is pretty much the opposite of late binding).

I do most of my coding in PL/SQL these days. Granted, it's a oddball language and it doesn't fully implement call by name, but it sure does do a good job of demonstrating why someone would want it. Try writing a routine that tells Oracle to update statistics on a given table. Did you use the string functions to inject the table name into the SQL call to DBMS_STATS? Well, call by name would have done that for you. Want to create a temporary table, build some indices, add constraints on the fly, etc.? Sure, you can use sprintf in C++, or you can just write general purpose routines in PL/SQL and pass the identifiers in by name.

There are lots of proprietary languages that do this and they all do it for the same reason: databases are intentionally general and referencing items requires either 1) writing a whole bunch of special purpose routines that look basically the same, 2) cutting and pasting commands together, or 3) call by name. It's a great use of a niche feature. Why use tortured examples from general purpose code?

Wednesday, October 28, 2015

Directed study

This isn't a done deal, but it looks like I'm going to switch from the CS concentration to Statistics at UMSL. Odd as it may sound, one of the motivators is that there are fewer course offerings in stats. Why is that good? Well, I've already got a masters degree in statistics (technically Operations Research, but my thesis and nearly all my coursework was stats). So, I don't really need a bunch more courses. A masters degree is supposed to mean that you are qualified to learn things on your own.

What I need is research direction. And, because the course offerings in stats are a bit thin at UMSL, that's the normal pattern. Once you're through the core stuff, you just do directed readings and research. Perfect! I already know how to read a math text (note: that's not nearly the same thing as saying you know how to read). What I need is someone to provide guidance through the literature and offer feedback on my own findings.

Tuesday, October 27, 2015

Failover peformance

Spent some time at work with HP yesterday looking at Vertica, their scalable database. One of the things I liked about it was how it responded to losing a node.

Suppose you have six nodes, n1 - n6 responsible for data partitions d1 - d6, respectively. Each node stores its own data plus the data from its neighbor to the left. So, under normal operation, n2 stores d1 and d2, n3 stores d2 and d3, ..., n1 stores d6 and d1. Now, suppose node 3 fails. N4 can pick up n3's processing, but it has to do its own as well, so it will take twice as long to finish. Since everything waits on the longest node, this 1/6 loss will actually reduce throughput by 50%. Not so great.

But, there's no reason why n4 has to carry the full brunt of the failure. Sure, it's the only one with a copy of d3, but n5 has all of d4. So, on the first query, n4 does double duty, but on the next one, some other node gets tagged with that. If n6 wasn't busy, it could do n5's work as well, n5 could do n4's, and n4 could do n3's. By passing the assignments around, each node can be kept busy without having to actually redistribute the data (or, at least, not having to redistribute it right away; the system will certainly want to start moving stuff around in the background to keep itself fully redundant). Individual queries will still take twice as long, but throughput should be close to 5/6.

I think this is an excellent example of a simple solution that passes the "good enough" test. There are certainly more elaborate solutions in use which result in less degradation to individual query response, but most applications can take a hit to individual operations as long as throughput isn't suffering too greatly.

Monday, October 26, 2015

Back at it

Last week was pretty light as far as school went (not so much at work, where we are in what is always the busiest part of the year). It's a natural lull after midterms, but one can't relax too much. Right now, I'd say I'm even with coursework, but not ahead. I'd like to at least get a bit ahead on the reading. So, it's time to get study time back up to around 20 hours a week.

Sunday, October 25, 2015

Gruntwork

Edison is credited with the quote "Invention is 1% inspiration, 99% perspiration". Probably even more lopsided in his case, as most of his "inventions" were developments of ideas that others hadn't been able to materialize. At any rate, I've been cranking out extracts from our OLAP database to our new Hadoop cluster at work. I enjoyed this for about five minutes while I thought about why we normalized things in the OLAP world and didn't in the land of Big Data. Then, it was just tedious.

Still, there's a big difference between knowing how to do something and actually doing it. So, I took credit for it on my training log.

Saturday, October 24, 2015

Well, shoot.

I feel like Michael Corleone. My decision to step back from running isn't sticking very well. Kate's best friend, Kelli, is visiting from Texas. Her husband is thinking about running The Woodlands Marathon again in 2016. Last year I entered to offer a bit of moral support (it was his first marathon). Apparently, he really liked the fact that I was there. Kelli likes any opportunity to get with Kate, so now they are both pushing for us to come down.

It's a good race. Fast course, well organized, and good post-race (especially for me, since I was put in the elite field). As I took home cash prizes in two divisions (3rd Master, 1st Senior), I expect they'd stick me in elite again.

On the other hand, it's an expensive trip with all three of us flying and I don't know what kind of fitness I could bring. Certainly less than last year. I'll probably do it because I really am addicted to this stuff. I emailed the elite coordinator. If he puts me in, I'll do it and hope I don't embarrass him too much.

Friday, October 23, 2015

Possible new source

Getting back to thinking about my thesis topic, I had pretty much settled on using the Epidemiology literature as my primary source when I came across this paper. I hadn't really thought of image analysis because they are basically solving the inverse problem; using correlation to increase clustering, rather than using the clustering to estimate correlation. I think some of the same ideas apply. At any rate, image analysis is a MUCH more active field of study, so even if only the periphery touches on my problem, it might still be a fertile field.

Thursday, October 22, 2015

Then what is it?

I should probably be slower to criticize a textbook that's in its 11th edition. Clearly, quite a few scholarly folks think it's a good one. However, I'm really having trouble with the gap between the text and the reality of programming. Maybe that's not a gap that people teaching Language Theory care about, but they should. Programming languages are first and foremost tools. They have pretty much no merit in and of themselves. If they don't help you get the job done, they are useless.

Tonight's example is the definition of a subprogram. Among the criteria: the calling program is suspended and the called program returns control to the caller. Really? An asynchronous call isn't a subprogram? What the hell is it then? My prof didn't have a really good answer for that, either. He just said that these definitions weren't in the context of multithreaded programs. Well, that rules out just about every UI written in the last 20 years. Not a particularly useful working definition in my mind.

Wednesday, October 21, 2015

Second feedback

Yeah, not so much fun as yesterday. The only reason my Algorithms midterm grade even resembles an A (it's not an A, but it at least came in close) was because the whole class did so bad that the prof curved it a bit. Anyway, the problem in my case wasn't in knowing the material, but not being able to answer quick enough. So, that's what I need to work on. From now on, I'm adding a new category to my "Practice" time: drill.

Basically, drill will be solving problems as quickly as possible, even if the final answer isn't quite right. Obviously, I'll go back over my answers and correct errors after the fact, but drill will focus on getting something decent on paper as quickly as possible. Think of it as interval training for the brain. So, a typical drill session might be 5 section exercises (the section exercises are closer in difficulty to exam questions than the chapter problems), 5 minutes each with 1 minute rest between. I'll start with half-hour sessions like the one just mentioned and try to work that up to around 90 minutes.

I don't think the questions even need to be related to the course material (though, obviously, I'll use those questions first). If I run out of section problems in the Algorithms text, I'll just grab some from any one of my other 20 texts left over from Grad School v1.0.

Tuesday, October 20, 2015

First feedback

Well, it's hard to get to excited about it after last night's train wreck, but my first midterm in Languages came back today with full marks. A good way to start. Hopefully the Algorithms midterm wasn't as bad as it seemed.

Monday, October 19, 2015

Right about one thing...

... the Algorithms midterm was way too much for 75 minutes. At least everybody else in the class seemed to agree. Nobody turned in a paper early and quite a few students indicated that they simply couldn't get through all of it. I did answer everything, but a few of my proofs were pretty abbreviated and one was downright lame (though the instructions said to just indicate the general ideas and not worry about formal proof).

It was a little disappointing to turn in such poor answers when I knew that in another half hour I could have had rock solid responses for everything. Maybe I'll be able to redeem myself on the final, which I'm pretty sure is a standard 3-hour deal.

Sunday, October 18, 2015

Woodlands Marathon

This week's off-day race report takes us back to last spring's marathon. Run February 28, 2015.

Books on marathoning often stress the importance of carefully setting challenging, yet realistic goals. Then, there's the Facebook approach. A friend says they're going to run a marathon. You click "like" and say you'll run it with them. Then when you go to register, you see that the elite standard for your age is a time you can actually run. An impulse response has now become your major goal for the next six months.

The friend in this case was Adam Brown, a very likable guy who's married to one of Kate's best friends, Kelli. After running a leg in the relay at The Woodlands Marathon in 2014, he decided he'd like to take a crack at the whole thing. There's something about the glow of a first time marathoner that's almost incomprehensible, yet entirely captivating, to a crusty veteran such as myself. So there I was, staring at the registration page and asking myself, "do you really want to put this on yourself?" And, after some thought, I decided that if I really wanted to get a sub-3 as a 50+ runner, this was as good a time as any, so I fired my credentials off to the RD.

Those credentials weren't as squeaky clean as I'd like. Sure, I'd run under the 50+ elite standard several times, but not recently. I tell myself that's just because I haven't tried running a marathon hard since 2011. This is true, I've been focusing exclusively on ultras, but that's still a rather stale result as a qualifier. It turns out to be good enough and I'm placed into the elite field. So, now it's obligatory: I have to prep.

Prep goes exceedingly well. I get in all the workouts that matter and my total volume is almost exactly according to plan. At the start of the cycle, I win the Osage 50K and with six weeks to go, I post a PR (84:22) in the Frostbite Half Marathon, winning 50+. With no nagging injuries or undue work stress, this is shaping up to be a no-excuses race.

Kate, Yaya, and I all fly down to Houston two days before the race. I prefer getting there two days in advance because if anything goes wrong with travel plans, there's still time to adjust without getting all stressed. The trip goes without a hitch, so I get two relaxing days in at Adam's house before the race. He lives right on the race route, so I jog around a bit each day, checking out parts of the course. There's not much to see, really. It's very monolithic: tree-lined parkways, concrete surface, no hills of any significance. That's not to say it isn't pretty; just that there isn't much to make note of.

With Alan Lawrence
I attend the elite briefing at packet pickup the day before. They've singled out four Olympic hopefuls to share their thoughts on the race. That's interesting, but the high point for me is meeting coaching legend Alan Lawrence, author of the very first book I ever read on running. I knew he lived in Houston, but I never bothered to check that he might be a pre-race speaker.

I am up at 4AM without the help of the alarm. A chronic early riser, that's normal for me, though I usually lie awake in bed for another half hour or so. I quickly reheat the oatmeal I cooked last evening and have it with some coffee before donning my headlamp for a very easy 20-minute jog. It's only a 15-minute drive to the start, so we get there shortly after 5:30. We sit in the car and try to talk about anything other than running until 6:15 when we finally decide it's time to face the task at hand.

The temperature is 35, but I don't feel particularly uncomfortable with my warmups on. Adam has to find the gear drop and get to his corral. We've miscalculated the time required to do this and he has to scramble off. I've got a bit more time to wander around as the elite field gets to just walk up to the start line and drop our bag there. I check in, jog for about a mile and then come back to shed my warmups. One of the EastAfrican runners is doing likewise and comments that this is waaaay colder than he was expecting. Like most 2:10 marathoners, he's much better at radiating heat than retaining it. I've got half a foot and 40 pounds on him, so I think the temperature is just fine.

We're led to the line, but allowed to continue warming up by jogging back and forth along the first few hundred meters of the course. We get in position with a couple minutes to go. The true elites are on the front row, most of them shivering violently. I've been in elite fields for ultras before, but this is my first time lining up with world-class marathoners. I'm struck by how tiny they are. Without any stretching, I can look right over their heads. Most of them are from the marathoning powerhouse nations of Kenya and Ethiopia, but there's also a German and a few Americans hoping to qualify for Olympic Trials.

With me in the next row is the rest of the "elite" field who enjoyed a relaxed time standard due to our advanced years. I'm the only one over 50; the others are in their 40's. Altogether, there are fewer than 20 of us and it feels very much like we will get trampled by the 1500 or so stacked up right behind us (the 7500 in the half are at a different start line a couple blocks away).

Fortunately, the great mob seems cognizant of the task ahead and, while a few scoot by in the first 100 meters, most are content to settle into something slower than what I want to run. In less than a minute, the front of the field strings itself out as we all find our paces. The first mile arrives at 6:35, which is a few seconds quicker than I'd like, but not enough to be a concern. The next is dead on at 6:42 then we get a bit of downhill in mile three for 6:24.

I'm running in a little pack of five. Only one of the runners, Chris Weir, feels like talking much. We have a fair bit in common. His PR is nearly identical to mine, he likes hillier terrain (he moved to Houston from Atlanta a few years ago), and he's done some multisport races. The miles go by easily, but as we're still averaging a few seconds under my optimistic 6:40 pace, I decide to back off the just before 10K. I'm further slowed by a couple "hills" (gentle rises of 30 feet or so) and the fact that the course turns into the wind, so I hit mile 9 at 60:03, exactly 1/3 of a second per mile off best target pace. So far everything is going about as well as one could hope, but it's about to get better...

This really isn't schadenfreude. I wouldn't wish a mid-race meltdown on anyone; particularly not one of the best runners in the world. But, how often do you get to pass a guy who's been paid to journey halfway around the world for a race? One of them (the same guy who was commenting on the temperature at the start) is walking along the side of the road. Presumably, he's going to pack it in at the next aid station, but for now he's still on course and wearing his number, so it's a legitimate pass. Several others in front will also bail by the end so, I'm not sure who he was, but I don't really care. I won't be last in the elite field and that's good enough for me.

I hope he does stop at the next aid station because shortly after that I encounter pretty much the most tasteless fan display I've ever seen. (That includes the 6-foot paper mache penis that was thrown on the ice during a Cornell hockey game. At least some effort went into that stunt; it really did look like a giant penis with "Harvard Sucks" painted on it and the choreography of busting the emergency doors and running down through the stands to just the point where it could be thrown over the glass and getting back out of the rink before security realized what was going on had clearly been rehearsed.)

This one is just stupid. A cardboard sign in marker that says, "Run like the guy behind you has Ebola." Really? In a sport dominated by Africans? Classy. I consider saying something but decide this is not the best time for such a debate.

The course is now mostly into the wind, so I'm still giving back more of my opening pace. I hit the half at 87:50. I'm not too concerned about the fact I've lost another 15 seconds; I never really thought I'd run a 2:55 anyway.

At mile 16 the course does a short out-and-back to get the total distance to exactly 42195 meters (actually, 42237, since a certified course has to be measured to 100.1% the stated distance). The four that I was running with early on have split up, ranging from 1-2 minutes ahead of me. A couple minutes behind is a little cluster of runners following the 3-hour pacer. I hadn't realized there was a 3-hour pace group for this race. It's nice to know they are back there. If I run into problems in the late going, I might be able to latch onto that group and save a sub-3 finish. For now, I'm feeling pretty good about my current velocity and see no reason to adjust.

Mile 18: rain just starting
And then it starts to rain. Not hard, but given that the temps are still sitting in the mid-30's it's pretty chilly. I pass Chris who says he's fading. He's not alone; apparently Texans don't like freezing rain because despite running the second half 12 minutes slower, he hangs on to 26th place. Just past 18 (in 2:00:57, still in great shape though there's no denying the slowing), I'm happy to see that Kate, Kelli, and all the kids have still come out of the house to cheer me on. It's a much needed boost given the deteriorating conditions. Yaya runs across the street to hand me a gel pack. Not needing one, I just give her a high-5. Half a mile later, the course turns and I pick up a tail wind for a mile. When my split for 19 shows a 6:54, I know the "real" race has begun. I'm starting to tighten up in the cold and I'll have to fight for the pace from here on in.

I don't fight it very well; 20 is an even slower 6:58. The course turns again and it's back to a cross wind, but the rain has let up, so I'm no colder than I was. My stride is considerably shorter than it was an hour ago so I focus on keeping my turnover as high as possible. While slightly less efficient, the inefficiency is realized in the form of heat, something I can use right now. I'm very glad I didn't toss off my gloves and hat earlier in the race when I was feeling more comfortable.

The half marathon course has merged in and the 13.1-mile head start wasn't enough for a fair number of folks. Most are quick to get out of the way when they hear me coming, but these are obviously not serious runners, so many of them are wearing headphones and listening to music. There are a few near misses, but I manage to get through them without spending much extra energy or losing time. After running alone for the last 90 minutes, it's actually a nice stimulus.

At 23, it's my turn to get caught. Well, you can't slide off the pace forever and expect not to pay. Still, I hate getting caught late in a race. Worse is the realization that this guy is not a youngster. I may well be losing the 50+ win. I latch on for all I'm worth (resulting in my fastest mile split in the last six miles), but it's just too much. This dude ain't slowing down and I can't hold this for another 15 minutes. I back off for mile 25 to compose myself then get back on the gas for the final mile. Of course, there isn't a whole lot of gas left in the tank so the extra effort doesn't really change my speed very much.

The finish line does have a small crowd on hand and the announcer gets mighty excited when I come into view, telling everybody that he wishes he could run a sub-3 when he's 51. I take that as a good sign that the guy right ahead of me wasn't. The finish clock hasn't rolled over to 2:58 yet, so I come up with one last surge to scoot under it in 2:57:53. I'm not sure why I care about that, but somehow 2:57 sounds much more "comfortably under" three hours than 2:58 and dropping the seconds off your marathon finish is a time honored tradition.

Shortly after the line I find my late-race antagonist who is actually a 42-year-old on a relay team. He apologizes if he messed up my pace. I thank him for snapping me out of my slump before I started feeling sorry for myself. The next Grand Master (50+) doesn't show up for another six minutes. The Grand Master win was what I was really after, but it spilled over pretty nicely. I also picked up hardware for third in Masters (40+) and 16th overall is a nice slot in a field this size (well, actually 17th, I got chicked by the lead woman). And, of course, having been placed in the elite field on somewhat dubious credentials, I was glad to post a time well under the standard for my age.

The weather has improved somewhat, but it's still cold enough that I'm very happy to take refuge in the VIP tent with its heaters and unlimited supply of food and drink. Most of the East African runners are shaking with hypothermia, so much so that I wonder if perhaps some real medical attention is in order. None of them ran particularly well (if one can say a 2:20 is not running well). Still, they are a generally happy lot and from what I can follow of their conversations (they seem to switch in and out of English mid-sentence or maybe it's some sort of pigeon language), they are taking it all in stride. Perhaps when running is your ticket out of poverty rather than a first-world diversion you learn to look at the upside.

Double dipping on hardware
After about 45 minutes in the tent, I decide it's time to check on Adam. I head back to the car and collect my phone. The online results indicate that he's already finished! I hurry back to the finish area as best I can to congratulate him. He's taller and beefier than I, so it's no surprise that he held up fine in the conditions, but a sub-4 on your first outing is no small thing even in the best of circumstances.
That makes for a happy evening after, but doesn't leave me with much material for witty sarcasm. So rather than invent tragic facts, I'll just skip that part of the race report and close with some thoughts on why this race went so nearly perfect.

First and foremost, the training was spot on. I've used Daniels' as my template for the past few marathons and the correlation between how closely I follow it and how well I run is pretty near 1.00. The guy isn't hailed as a great coach for nothing. In particular (and this is hard for me to accept), I didn't do any over-distance runs. I had a few days where morning and afternoon combined were around 30 miles, but my longest single run after the Spirit of the Osage 50K at the very start of the cycle was 24 miles. Recovery becomes more problematic with each birthday and I'll have to concede that laying off the ultras really helped get all the quality work done. On the other hand, the 18-week cycle covered 1700 miles with several weeks over 100, so reasonably high volume still seems to work for me.

I've generally not done a lot of marathon pace training in the past. It's always struck me as junk miles: too fast to recover quickly but not fast enough to bring about improvements in fitness. This cycle I dutifully ran all the M-pace workouts, including several where I was on the gas for 15-16 miles (of 20-23 miles total). In retrospect, I think I was right that not much physiological improvement came from these, but totally wrong about their value. I've never felt so comfortable sliding into my target pace at the start of a marathon. It felt very natural and relaxed. I knew it would get hard, and it did, but I was never afraid of it. It really felt like just another training run up until 18.

While I remain a proponent of negative splits for sub-marathon races, I've embraced the fact that positive is not only to be expected in marathons and ultras, but actually optimal. Somewhere between 2:00 and 2:30 your stride shortens due to the natural tightness. The elites (real elites, not me) are close enough to the finish at this point that they just push through it, but for anybody running longer than 2:40, it's just a fact of life. In the three fastest marathons I'd run up until this point, my 9-mile times were 60:23, 60:50, and 62:07. The last one is what I would run if I was serious about running negative splits (I was and I did), but the other two were positive splits with a faster overall time. This one was even quicker through 9 (60:03) and, while the last 10K was a bit slow, I think that was more due to the cold rain than the early pace. At any rate, it was my second fastest ever, so the early pace couldn't have been off by much.

Finally, and this may come off as sappy but it is sincere, my family came out in the rain and watched me run by. That matters so much more than most people realize. I travel to most races alone, but in all of the abovementioned three fastest marathons, my family was there. Now, it's four for four.

So there it is: train long, but not too long, train fast, but not too fast, take it out firm but not too firm, and don't lose sight of what really matters. I think just about every book on marathoning gives similar advice. And, on those counts, they're right.

Saturday, October 17, 2015

No rest

No rest day today. I spent pretty much all day handling production support at work and studying for the Algorithms midterm. I will take tomorrow off.

Friday, October 16, 2015

Information as capital

One of the advantages of working for what is basically an information company (thought that's not really our product, it's how we make money), is that I get to meet some heavyweights in the information business. Today, HP set up a meeting between my group and Chris Surdak, author of Data Crush. If you're pinning your future on data architecture, it's a meeting you cancel everything else to get to.

Lots of interesting points made. I think the one that was most salient was the evolution of what constitutes wealth. Wealth here is used to connote power and influence, not simply a means of acquiring other things. For centuries, it was land. If you owned your own land, you were infinitely more enabled than those who merely worked the land for others. Wage earners had almost no opportunity to improve their status. Landowners did.

Then, a couple hundred years ago that changed to capital. Land was still a good thing, but if you wanted to move up, you needed capital. Now, that's changing again. Capital is fine, but the real power is in information. Control that and the rest will come. The barriers to entry are exceedingly low. A information gathering iPhone App can be written in a week. If you get people to use it, you are suddenly a player because you have their information (no, they're not stealing it; read the terms of use: you GAVE it to them).

Anyway, like just about everybody else who does this sort of thing for a living, I already knew all that. However, his examples of what is being done and how to do it really drove the point home. It was a bit of an eye-opener for me.

No, I'm not going to drop out of grad school and start an information company. I'm actually quite fine with not being a big player in this game. It is exciting though that my work is going right to the heart of the matter: how to actually get a decent answer back from all that information.

Thursday, October 15, 2015

Optimized response

We had a review session in Algorithms yesterday ahead of Monday's midterm. There's no one thing that has me worried, but I am a little concerned about time. The test is only 75 minutes and from the way the prof framed it, we'll have probably 15-20 minutes of "objective" questions followed by some problem solving. Algorithms problems take a while to get right. Producing a correct solution in 10-15 minutes is no small thing.

I was thinking about why I was uncomfortable with this. We work under serious deadline pressure all the time at work. There are a couple things that make it different. The biggest is the immediacy of the deadline. Having 50 hours of work to do in a week is a lot different than having an hour and a half of work to do in 75 minutes. In the former case, you figure you can probably cut out some fat from the rest of your day and if you have to stay late a couple evenings, big deal. In the latter, you either deliver or you don't.

And, that's why businesses generally don't operate that way. It's setting your staff up to fail. At work, you give the "right answer" as quickly as possible ("right answer" here means delivering something of acceptable quality, not perfect). On a test, you give the best you can within the time. While that distinction may be subtle, it is also fundamental. Staffed properly, the first strategy yields consistently good results. The second will at best yield very expensive results (by setting the due dates conservatively) but more often just causes delivery of crap to production.

So, I have to change my mindset a bit. I would never knowingly give my boss a wrong answer. If I wasn't reasonably sure, I'd just say I'd get back to him (and, I'd make sure I did that quickly). But, that response won't fly on the test. I'll just have to come up with the best I can and try not to wince when I write my name at the top of the paper.

Wednesday, October 14, 2015

Algorithms HW3

Jumping the gun by a few hours, but I don't think any of my classmates are trolling my blog for answers.

HW3

Tuesday, October 13, 2015

First test this century

Longer than that, actually. Unless, of course, you count the totally bogus GRE. Anyway, I had an exam in Languages today. I'm sure I messed something up, but there wasn't anything on there that I shouldn't have got right. I'm sure I did fine.

While it's nice to have a confidence builder, next Monday's midterm for Algorithms will likely be a significantly higher bar to clear.

Monday, October 12, 2015

Lost weekend

I had to tend to some production problems at work Saturday morning, so that wasn't the day off I was looking for. Sunday, I decided to go camping with Yaya since she didn't have school on today. It was a nice break, but now I'm really under the gun to get ready for tomorrow's Languages exam plus finish the homework for Algorithms. It was worth it.

Saturday, October 10, 2015

Milwaukee Lakefront Marathon

Run October 4, 2015.

It wasn’t love at first sight.

I ran my first marathon (Chicago) in 1993. Having just retired from pro cycling, I was plenty fit. But, I had no idea how to run long distances and, as I staggered across the line in 4:35, I was thinking I didn’t really need to do that again. Ever.

Since then, I’ve run marathon distance or further over a hundred times, but pinning on a number for a competitive road marathon still brings back anxiety from that first attempt. There are few things in life less pleasant than a marathon gone bad. It’s not like ultras where you have time to walk it off and wait for your body to come back. You can do that, of course, but it’s no longer a “competitive” marathon. If you care about your result, you have to keep digging, even when it’s obvious that you’re only going to suffer more as a result.

So, even though I have no qualms about running eight or nine ultras in a year, I usually limit my marathons to one. The training investment is too high and the recovery too long to justify many more. Frankly, I might not do them at all except that there is no other event that does such a good job of scaring me into decent training. Any time I feel like blowing off a tough workout, I merely need to conjure the memory of those six miles along Lake Shore Drive where the misery of staggering through the howling wind and sleet was compounded by the knowledge that those final few miles were going to take twice as long as they should.

All that said, I have come to love marathoning. Even with proper preparation, they are tough. But, doing a tough task reasonably well is a gratifying thing. So, knowing that this was the last year I’d have enough training time to prepare properly, I decided to do two. My spring effort at The Woodlands went exceedingly well, so I had pretty high hopes coming into the Milwaukee Lakefront Marathon in the fall.

This is a sufficiently emotional activity that I like to bring the family along, even though it significantly increases both logistics and expenses. Yaya has been at every one of my 3-hour marathons and Kate has only missed one. Knowing they are there makes a difference. We drive to Madison Friday and spend the night with my college teammate Tom Rickner. After lunch Saturday, we make the short trip to Milwaukee in time to pick up my number. An easy jog around downtown confirms that my legs have come back from a few too many races during the preceding weeks; my stride is fluid and relaxed. There’s a little tightness in the hips from sitting in the car for seven of the last 24 hours, but nothing alarming.

I’m up at 4AM on race day. The hotel breakfast won’t be set out for two more hours, so I reheat some oatmeal I cooked at Tom’s house. I follow that with a short jog to get my engine started and then walk the mile to the buses. The temperature is 47F and a light mist is falling, which makes it pleasantly chilly. The course is almost a direct line south from start to finish, so the bus ride is half an hour, mostly on interstate. It’s not quite the jolt you get driving two hours to the start of a point-point hundred, but it’s enough to underscore that we’re going long today. By the time we arrive at Grafton High School, the precipitation has stopped.

I’m on one of the first buses, so I take advantage of the fact that there’s no line for the indoor restrooms. Unfortunately, my body isn’t yet ready to cash in on this opportunity. I try again twenty minutes later (lines are still pretty short), but still can’t poop. Those who don’t run long distances may find reporting such details unnecessary or even unseemly, but very few things destroy a good run quicker than intestinal distress, so this is no trivial matter. Shortly before 7, I go for my warmup. 

After about a mile, I feel like I may finally be able to take care of business. There’s no hope of using an indoor toilet 20 minutes prior to start, but I only have to wait about five minutes to get a porta-john. The results are still less than hoped for given last night’s fairly robust meal, but it will have to do. I check my warmup clothes at the truck heading for the finish and jog over to the start.
It’s still pretty chilly, but I feel fine in just my technical shirt and shorts. I’m happy to find that people are doing a pretty good job of honoring the projected finish signs. There are fewer than a hundred of us standing between the 3-hour sign and the start line, which seems about right for a field of 3500. 

Among those up front is fellow SLUG and national team member John Cash. He’ll be running a whole lot faster than me, so I say hi, but then find the 3-hour pacer. While I’d like to finish two or three minutes faster than that, I figure running the first few miles with the pacer will relieve a fair bit of stress; I can just relax into the effort and not worry about whether I’m taking it out too fast.
Turns out this pacer is pretty good at his job, taking us through mile 1 in 6:54, just 2 seconds over 3-hour pace. The next mile is a downhill 6:35, followed by a 6:50. That puts me 19 seconds off intended pace, a price I’m happy to pay as insurance against over baking the early miles. I gently move ahead of the 3-hour group and am dealt my first unpleasant surprise of the day: the legs are not digging 6:40’s.

More specifically, my hips aren’t happy. That tightness apparently was worthy of some alarm (though I don’t know what I would have done about it). It’s shortening my stride just enough that I can’t get down to 6:40 without resorting to an unsustainable push off. I hate to force things this early in the race, but I don’t want to completely give up on this one, either. It generally takes something in my PR range (2:57) to win the Senior division here and I’d like to stay in the hunt. I spend the next few miles oscillating between 6:40 and 6:50, trying to find something that’s both fast and comfortable. By mile 9 (at exactly 61 minutes, 1 minute off target), I concede that it’s just not going to be that kind of day. A decent result is still possible, but there will be no cruising through the first twenty; it’s going to be a fight the whole way.

Trying to get the time back with a mid-race surge would be suicidal. Instead, I hold the pace I’ve got and hope that the slow start will help me limit the fade in the late miles. While it will require more discipline than usual, I’m sure I can run the next 9 in 61 as well. That still puts me in with a very outside shot at 2:57. The chances of this working out are augmented by the fact that mile 24 is something of an annuity on this course, dropping nearly 100 feet from the bluff to the lakefront. It seems a pretty safe bet that I’ll gain some time there.

Aside from the last two miles along the lake, the course is undulating everywhere. While the opening and closing miles are net downhill, the middle section offers no such compensation. My pace continues to bounce around, but it’s generally consistent with the terrain and never too far from 6:45. There’s a little shuffling of the field, but my position seems to be holding pretty steady. I’m not really sure what that position is, but it’s not changing much, so I conclude I must be running much better than I feel. While it’s been a frustrating hour, I get to 18 in 2:02:06, in line with my revised plan.

I hit the timing mats at mile 20 in 2:15:51. That split will be automatically posted on Facebook and I wonder what’s going through Kate’s mind. I had told her that I’d finish around 45 minutes after passing 20. If she takes that as 45:00, she’ll be bracing herself for an unpleasant ride home with me sulking over missing 3 hours on a day when course and conditions suggested far better. While there’s not much chance of saving a 2:57, breaking 3 is still very doable. A 10K is too much to fathom right now, so I focus on each individual mile, trying to stay around 6:50. Mile 21 is fine, but then the bomb goes off.

Astute readers may have picked up on the foreshadowing earlier in the story and seen this coming. Having gotten this deep into the race, I was starting to think I might get through this without my gut exploding. Now, it feels like I’ve been run through with a pike. This is hardly a unique condition and marathon organizers know to have plenty of porta potties along the route. However, such a stop would kill any chance of finishing under 3, so I have to try to run through this. I back off, but not too much (slowing to a jog can lead your body to believe it’s getting its way and then things really turn ugly). After about 5 minutes the pain has subsided. Mile 22 takes 7:15, but I’m still running, so there’s nothing to do but push on.
My distress has only cost me a couple places and I focus on pulling them back in. My stride is back and I feel like I can safely push at this point, which is a good thing because I only have half an hour for the last 4.2 miles. The downhill in mile 24 does help, yielding a 6:35 split. The last 2.2 are completely flat and I manage a bit of a surge to pass three more people and finish at 2:58:48.

Kate and Yaya are there; Kate seems visibly relieved that I came in under 3. Olivia is just happy that the girl at the chocolate milk tent is sharing her supplies with spectators as well as runners. The amenities at the finish are fairly good, but I’m glad we have time to zip back to the hotel for a quick shower before awards.

It wasn’t pretty but, as a competitive effort, it holds up reasonably well. Times were off across the board which probably means conditions weren’t quite as good as they seemed (though they sure seemed pretty good). I finish in 47th place, winning the my age group. Holding it together at the end mattered as second place was less than a minute back. I didn’t get the Senior prize (that goes to Chris Reed in 2:57:10), but 98 seconds back certainly qualifies as being in the hunt.

This is almost certainly the last time I’ll ever run a sub-3. The first two months of grad school have made it brutally obvious that serious running, doctoral studies, a full time job, and a family are at least one obligation too many. As I would rank those in the opposite order, serious running gets the heave-ho. Interestingly, my finish time was exactly the same as my first sub-3 marathon five years ago. In between were a handful of 2:57’s. There’s a nice symmetry to that and it probably indicates that no amount of training would result in big improvements. I’ll step back with no regrets.

Of course, I won’t stop running altogether. My time alone on the roads and trails serves needs that go far beyond being fit. Oddly enough, despite the decrease in training, it’s the shorter races that will get eliminated from my schedule. There’s not much to like about running a 10K slowly. But, longer events taken at a modest pace have a life far beyond finish times and age group trophies. Whether it’s reveling in the running community or introspective meditation, distance running takes you places physically and spiritually that are hard to get to any other way. It wasn’t love at first sight, but true love rarely is.

Friday, October 9, 2015

Cross training

Here's some good news I gathered at the PhD student discussion Wednesday: I'm not limited to UMSL courses. They have an agreement with Washington U, St. Louis U, and Southern Illinois Edwardsville where grad students in any one of those programs can take one course a semester at any one of the other schools. That's going to come in real handy because the UMSL faculty doesn't have anybody working on Big Data problems. I don't think SLU does, either, but I'm sure there's research being done at WashU and SIUE. I'll need to get their course catalogs and see what they are offering on Big Data Architecture.

Thursday, October 8, 2015

New advisor?

We'll see, but at least I've found a faculty member that seems genuinely interested in my topic. Yuefeng Wu is a Statistics prof in the department and thought it was worthy of pursuit. I think I need to hang more with the math guys. That's where I'm going to need more help, anyway. I already know how to handle databases.

Tuesday, October 6, 2015

Rats

I hope the grader is willing to put some effort into the really hard problem on the Algorithms homework. I don't believe there is a tight bound. My solution, , is a loose upper bound, but it's waaaay tighter than the one the prof gave on the answer key:  . That thing explodes instantly. I'd hate to have to get into a grade argument on the first assignment, but I spent a week on that thing, so I'd like to get credit for it.

Sunday, October 4, 2015

Plan for this week

Ran the Milwaukee Marathon today and just got back to STL. No PR, despite pretty good conditions. I think I was right about these grad school/racing things being incompatible. Still, a decent result: under 3 hours and an age group win. No need to apologize for that. I'll post a race report as next Saturday's off-topic post.

Meanwhile, I am really up against it this week. Work shouldn't be too busy; probably just a regular 40-hour week. But, I have assignments in both classes and an exam next Monday. I'll need to use my time wisely. Tonight is pretty much lost, so here's my plan for the rest of the week.

Monday: If I wake up early enough (hardly a sure thing the day after a long race), I'll work on my Algorithms assignment. Otherwise, that will push to lunchtime. Might get another hour in between dinner and class.

Tuesday: Finish the algorithms assignment. Hopefully in the morning. Otherwise, it will be a late night after class.

Wednesday: Turn in algorithms HW and finish up the languages assignment (it's mostly done already). If I have a chance, I'll touch up my thesis ideas because there's a discussion with all the grad faculty Wednesday afternoon on open topics and I'm hoping I can find someone interested.

Thursday: Get going on the next algorithms assignment in the AM and some review of languages topics covered so far before and after class.

Friday: AM studying for languages. Midday work on the algorithms assignment. Kate wants to do some stuff as a family in the evening.

Saturday: Off, as usual.

Saturday, October 3, 2015

Pheidippides and the Bar Bet

Since I'm running what will likely be my last competitive marathon tomorrow, I decided to use the off-topic Saturday post for an old blog entry on the subject rather than a race report.

Stop me if you've heard this one. Oh, wait, we've all heard the story about the guy who takes a bar bet the night before a major city marathon and manages to run it in three hours. As with all urban legends, the story is told with lots of details that no disinterested person would keep straight. The runner's name, the easiest part of the story to recall (and to verify), has somehow been lost.

Surely, there are people out there who have run a marathon on a whim. This most likely occurs in smaller races since the big marathons don't take race day entries. But that detail doesn't necessarily invalidate the story. The person could always run as a bandit. I expect that the vast majority of such attempts are unsuccessful, but a few manage to finish. Some might even arrive before the finish is closed down at five or six hours.

A finish time is a completely meaningless number to a non-runner. Most people don't even know how far a marathon is. You'd be hard pressed to find anyone outside the running community that could tell you that a 3-hour marathon requires stringing together 6:52 miles. Even running a single mile in 6:52 is an experience few people can relate to. The storyteller is just picking a number out of the air and 1 hour behind the winner seems both impressive and believable.


Of course, no such number exists. The rigors of professional competition have made it impossible in any sport for an untrained athlete to do something "impressive" by objective standards. If someone told me they knew someone who ran a marathon with no training and "did OK," I'd believe them. But when they throw out a time that would be a PR for 90% of the running population, it sounds a bit fishy.

By including the finish time, the storyteller is asking that the story be judged as an athletic achievement rather than one of personal triumph. And that's too bad, because as athletic achievement, a 3-hour marathon is not worth reporting. As personal triumph, merely finishing a first marathon certainly qualifies.

The original marathon legend is quite different. We hear all the details a normal person would remember - the victory over the Persians, the run back to Athens, the subsequent collapse and death, and the name Pheidippides. Nobody ever quotes a finish time despite it being a de facto world record.

The Pheidippides story does have some problems. The ending fits too conveniently with what the Greeks considered good theater. Perhaps if the Persians had won and Athens needed to organize a hasty defense such urgency would be called for. But why would a messenger see the need to run himself to death to tell people they had nothing to worry about? Perhaps he was concerned the Athens Gazette would run a picture of him walking through a feed zone.

Unlike our hero from the bar, Pheidippides was a trained professional runner. The honor of carrying the message of victory would be given to the best foot messenger on hand. My guess is that, aside from a few blisters and a sore set of quads, he came through it just fine. Later, when his running buddies questioned him about his newfound celebrity, he played it cool and described the run as an OK effort, but he was dying at the end. When the quote got into the media, the metaphor was lost. Fact checking wasn't a priority among Ancient historians.

Why do people embrace both of these obviously contradictory stories? How could an event that killed a professional be so easily conquered by a novice? I believe it is due to a fundamental misunderstanding about athletics in general and the marathon in particular. Most people believe that athletic prowess is as pre-ordained by genetics as hair color or a recessed chin. They reason that a marathon is impossible for most people and easy for a select few.

Both conclusions are wrong. Any reasonably healthy person can walk 26.2 miles in a day with no training at all. It won't be much fun, but it's possible. In less than a year, that same person can train themselves to actually run a marathon. This time, it might be fun, it might even take less than three hours, but it still won't be easy. Running a marathon at or near one's potential is brutally hard regardless of genetic gifts. That's why the world's top marathoners only do it a few times a year. If they could race more, they certainly would, since that's how they get paid.

Genetics does matter. No amount of training will make me a 2:10 marathoner. But training had everything to do with the difference between my first marathon (4:35) and my PR (2:57) twenty years later. And that's really the point. While it's nice to pick up a trophy here or there, most of us run not to be seen by others, but to get a better look at ourselves. As we run into perceived limits, we find those limits have much less to do with genetics, gender, or age and much more to do with how determined we are to move them.

Even if it was possible for an untrained runner to knock out a 3-hour marathon, the feat would merely indicate that with proper training, the person would probably be a decent runner. That's true of many people who don't run. We are not defined by the things we could do - it is the things we actually do that matter. We choose to run.

Friday, October 2, 2015

IT Value Measurement

I'm in a professional group that meets the first Friday of every month. This morning's discussion was led by Joe Lengyel, a senior manager at the STL Federal Reserve. He recently completed his PhD studying ways that IT value is measured and, more importantly, why it generally isn't.

You would think that companies that are spending hundreds of millions of dollars annually on IT would be at least a little interested in whether they are getting their money's worth. Yet, there is pretty low adoption of formal metrics for measuring IT value.

Many good points were raised. My take on all this is that, while it always makes sense to perform some introspective analysis, the real question of value should be put to the business. After all, they are the consumer and have the greatest interest in spending IT dollars wisely. In my experience, the best way to do this is to bill IT services back to the business. And, not in some amorphous blended allocation but in real dollars spent on work pertaining to specific business needs. This can be problematic for infrastructure since it's pretty much impossible to say exactly how much each business area is benefiting from having a decent network, but for applications development it's usually pretty clear.

Of course, this only works if the business has direct control over what's delivered (taxation without representation is tyranny!) We meet with our business users every week not merely to give status, but to get their direction on where we should be focusing our efforts. Technically, we chunk it out in 3-week iterations, but the mid-iteration feedback is useful, too. Macro-level budgeting is, of course, necessary to set staffing levels and have some idea of what the big deliverables are for a year. But, it's this regular contact directing our priorities week to week that allows us to give the maximum benefit to the business given the resources dedicated in the budgeting process.

Thursday, October 1, 2015

More TDD

As I mentioned a few weeks ago, Test Driven Design is definitely the way to go for small, well-defined problems. One of our homework problems in algorithms is to create an algorithm that chooses a sequence of babysitters to cover a given time period where each member of the candidate pool can cover some subset of the period. There are a bunch of edge cases that take some thinking through. Or, you could just write a bunch of test cases and code to each until you have a solution. As is so often the case in TDD solutions, the final version is actually a reasonably efficient implementation, but one could very aggressively tune it knowing that there is a reliable test suite to validate your tunings.

Here are the test cases (this is all C# if that isn't immediately obvious):

using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using AlgorithmHarness.Optimization;

namespace OptimizationTests
{
    [TestClass]
    public class BabysitterTests
    {
        private static BabySitter scheduler = new BabySitter();
        private static List<Candidate> result = new List<Candidate>();

        [TestMethod]
        public void ConstructorNonNull()
        {
            Assert.IsNotNull(scheduler);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void NullCandidateListShouldThrowException()
        {
            result.Clear();
            scheduler.Schedule(new DateTime(1), new DateTime(10), null, result);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void StartAfterFinishShouldThrowExectption()
        {
            List<Candidate> candidates = new List<Candidate>();
            result.Clear();
            scheduler.Schedule(new DateTime(10), new DateTime(1), candidates, result);
        }

        [TestMethod]
        public void EmptyListReturnsNoSolution()
        {
            List<Candidate> candidates = new List<Candidate>();
            result.Clear();
            Assert.AreEqual(false, scheduler.Schedule(new DateTime(1), new DateTime(10), candidates, result));
        }

        [TestMethod]
        public void ScheduleSingleInput()
        {
            List<Candidate> candidates = new List<Candidate>()
            {
                new Candidate(1, new DateTime(1), new DateTime(10))
            };
            result.Clear();
            Assert.AreEqual(true, scheduler.Schedule(new DateTime(2), new DateTime(9), candidates, result));
            ValidateCoverage(new DateTime(2), new DateTime(9), result, "Step 1");

            // shouldn't find a solution
            result.Clear();
            Assert.AreEqual(false, scheduler.Schedule(new DateTime(1), new DateTime(11), candidates, result));
        }

        [TestMethod]
        public void ScheduleSingleResult()
        {
            List<Candidate> candidates = new List<Candidate>()
            {
                new Candidate(1, new DateTime(1), new DateTime(2)),
                new Candidate(2, new DateTime(2), new DateTime(5)),
                new Candidate(3, new DateTime(2), new DateTime(7)),
                new Candidate(4, new DateTime(3), new DateTime(12)),
                new Candidate(5, new DateTime(4), new DateTime(8)),
                new Candidate(6, new DateTime(9), new DateTime(15)),
                new Candidate(7, new DateTime(16), new DateTime(20))
            };

            result.Clear();
            Assert.AreEqual(true, scheduler.Schedule(new DateTime(16), new DateTime(18), candidates, result));
            ValidateCoverage(new DateTime(16), new DateTime(18), result, "Step 1");
            Assert.AreEqual(1, result.Count, "Step 1 count");

            result.Clear();
            Assert.AreEqual(true, scheduler.Schedule(new DateTime(4), new DateTime(12), candidates, result));
            ValidateCoverage(new DateTime(4), new DateTime(12), result, "Step 2");
            Assert.AreEqual(1, result.Count, "Step 2 count");

            // no solution
            result.Clear();
            Assert.AreEqual(false, scheduler.Schedule(new DateTime(3), new DateTime(18), candidates, result), "Step 3");

            result.Clear();
            Assert.AreEqual(false, scheduler.Schedule(new DateTime(3), new DateTime(25), candidates, result), "Step 4");
        }

        [TestMethod]
        public void ScheduleSitters()
        {
            List<Candidate> candidates = new List<Candidate>()
            {
                new Candidate(1, new DateTime(1), new DateTime(2)),
                new Candidate(2, new DateTime(2), new DateTime(5)),
                new Candidate(3, new DateTime(2), new DateTime(7)),
                new Candidate(4, new DateTime(3), new DateTime(12)),
                new Candidate(5, new DateTime(4), new DateTime(8)),
                new Candidate(6, new DateTime(9), new DateTime(15)),
                new Candidate(7, new DateTime(16), new DateTime(20))
            };

            result.Clear();
            Assert.AreEqual(true, scheduler.Schedule(new DateTime(1), new DateTime(10), candidates, result));
            ValidateCoverage(new DateTime(1), new DateTime(10), result, "Step 1");
            Assert.AreEqual(3, result.Count, "Step 1 count");

            result.Clear();
            Assert.AreEqual(true, scheduler.Schedule(new DateTime(1), new DateTime(12), candidates, result));
            ValidateCoverage(new DateTime(1), new DateTime(12), result, "Step 2");
            Assert.AreEqual(3, result.Count, "Step 2 count");

            result.Clear();
            Assert.AreEqual(true, scheduler.Schedule(new DateTime(1), new DateTime(15), candidates, result));
            ValidateCoverage(new DateTime(1), new DateTime(15), result, "Step 3");
            Assert.AreEqual(4, result.Count, "Step 3 count");

        }

        private void ValidateCoverage(DateTime start, DateTime finish, List<Candidate> candidates, string test)
        {
            Assert.IsNotNull(candidates, test + ": Null return");
            foreach (Candidate candidate in candidates)
            {
                Assert.AreEqual(true, candidate.Start <= start, test + " start: " + start.Ticks + "Id: " + candidate.Id);
                start = candidate.Finish;
                if (start >= finish) return;
            }
            Assert.Fail(test + " failed to cover finish");
        }
    }
}

and here's the resulting algorithm:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AlgorithmHarness.Optimization
{
    public class Candidate
    {
        public Candidate(int id, DateTime start, DateTime finish)
        {
            Id = id;
            Start = start;
            Finish = finish;
        }

        public int Id { get; set; }
        public DateTime Start { get; set; }
        public DateTime Finish { get; set; }
    }

    public class BabySitter
    {
        public BabySitter() { }

        public bool Schedule(DateTime start, DateTime finish, List<Candidate> candidates, List<Candidate> result)
        {
            if ((null == candidates) || (null == start) || (null == finish)) throw new ArgumentNullException();
            if (start >= finish) throw new ArgumentOutOfRangeException();
            if (candidates.Count == 0) return false;

            Candidate best = null;
            List<Candidate> next = new List<Candidate>();

            foreach (Candidate candidate in candidates)
            {
                if (candidate.Start <= start)
                {
                    if (candidate.Finish >= finish)
                    {   // this one can cover the remaining time
                        // so that's good enough
                        result.Add(candidate);
                        return true;
                    }
                    else if ((best == null) || (candidate.Finish > best.Finish))
                        // best we've found so far
                        best = candidate;
                    //else - they can't go as long as one we've already got,
                    // so there's no reason to consider them further
                }
                else
                    // this one can't start early enough to use now,
                    // but might work out later
                    next.Add(candidate);
            }

            if (best == null) return false;  // nobody available at this start time

            // try to find an optimal solution for the remaining time
            // using just the sitters with later start times
            result.Add(best);
            return Schedule(best.Finish, finish, next, result);
        }
    }
}

It looks like more than it is because of the exception trapping and comments. The actual algorithm is a mere 11 lines of code.