Saturday, May 21, 2011

Introducing Clark Robert Eisler

Clark Robert Eisler, born 1:21 am May 17, weighing 6lb 11oz.

Thursday, February 17, 2011

Using a SQL Table of Numbers

An application that we work with has certain fields where the user is able to select multiple values for a single record. For example, for a contact's interests, the user might select Golf, Poker, and Tennis, and for a contact's groups, the user might select Customer and Friend. These values are stored as a list in the appropriate contact field, as in:
CustID  CustName       GroupList
1 Joe Smith Customer,Reseller
2 John Doe Competitor,Prospect,Reseller
3 Jane Doe Customer,Friend
4 Guy Incognito Competitor
This works well from a data-entry perspective, but from our point of view in reporting, it causes some trouble. First, filtering on these values is a bit of an issue. If we want to find everyone who is marked as a Customer, we need to use a contains operation, rather than equals. With this, we need to be sure to account for the case where one of the options is a substring of another. If one of our group options is Former Customer, we don't want it showing up in a search for Customer. This is easy enough to work around, but it is an extra step to deal with.

The larger issue is that users will often want to use these fields to group or summarize a report. In this case, the only real solution is to split the list of values for each contact, and treat them as a child table.

There are a number of approaches that will accomplish this. We can scan through the contact table, creating child records for each contact one by one. We can create a few select statements to retrieve each contact's first group, second group, etc, and then union them together. However, a simpler approach is to use a table of numbers.

A table of numbers is just that - a table containing a list of numbers. For our example, we only need a few:
num
1
2
3
4
...
That's it - probably the simplest table you'll ever use. With this table, splitting our value lists to create a child table is easy.
select cust.custid,
padr( GetWordNum( cust.grouplist, ton.num, "," ), 20 ) as OneGroup
from cust inner join ton on GetWordCount( cust.grouplist, "," ) >= ton.num
custid  onegroup
1 Customer
1 Reseller
2 Competitor
2 Prospect
2 Reseller
3 Customer
3 Friend
4 Competitor
This is made particularly easy by VFP's GetWordNum and GetWordCount functions, but a similar idea can be used without these functions.

Another trick with a table of numbers is to "fill in" a range of discrete values, such as a range of dates. Consider the following table of sales totals.
dDate        amount
02/15/2011 1500.00
02/16/2011 4000.00
02/18/2011 750.00
This table might be the result of aggregating the sales records for the week of Feb. 13 - 19. Dates where there were no sales do not show up, but we might want to include them with a zero in the amount field. A table of numbers makes it simple to generate the list of dates:
dStart = {^2011-02-12}
dEnd = {^2011-02-19}
nDays = dEnd - dStart

select dStart + ton.num as dDate from ton where ton.num <= nDays
We simply outer join this to our sales table to complete our date range.
select AllDates.dDate, nvl( sales.amount, cast(0 as Y) ) as amount
from ( select dStart + ton.num as dDate from ton where ton.num <= nDays ) as AllDates
left outer join sales on AllDates.dDate = sales.dDate

dDate amount
02/13/2011 0.00
02/14/2011 0.00
02/15/2011 1500.00
02/16/2011 4000.00
02/17/2011 0.00
02/18/2011 750.00
02/19/2011 0.00

Wednesday, February 16, 2011

Super Bowl Notes

A couple items came up during the Super Bowl that touch on posts I've made here in the past. First, it was repeatedly mentioned during the game broadcast that although Green Bay ended up with a somewhat mediocre record of 10-6, all their losses were extremely competitive. Green Bay never trailed by more than 7 points during any game at any point in the season, and their 6 losses were by 3, 3, 3, 3, 4, and 4 points, for an average of 3.33. This average is one of the all-time lows, and compares well to the teams mentioned in my Close But No Cigar post from a year ago.

The second item has to do with the endgame strategy surrounding Green Bay's field goal attempt at the end of the game. Holding a three point lead, Green Bay had fourth down from the Steelers' 5 yard line with just over 2 minutes left in the game. This is a classic situation where statisticians claim teams are routinely too conservative. Kicking the field goal hands the ball back to Pittsburgh, while going for it either wins the game with a touchdown, or pins Pittsburgh deep in their own end of the field.

That kind of analysis is not too unusual; similar arguments about 4th downs come up many times each season. However, on the Advanced NFL Stats site, an interesting addition to this argument appeared. That site has a "win probability" engine - for any given game situation, it provides the probability of each team winning, based on historical game outcomes from similar situations. For the game situation after the Green Bay field goal (~2 minutes left, in their own end of the field, down 6), the trailing team is expected to win 25% of the time. For the same situation, but with the team trailing by 3 instead of by 6, they are expected to win 21% of the time.

This looks like something along the lines of my 13 is worth more than 14 post from 2009. How can it be that teams trailing by 3 in this situation are less successful than teams trailing by more? It may be that teams trailing by 3 put too much value on reaching overtime, so they play to tie the game rather than to win it outright. When teams are further behind, they are forced to avoid this bad strategy. Also, on the other side of the ball, defenses may play differently as well, when they feel they have a safer lead. This may also be a poor strategy.

In any case, it's another interesting example of a counterintuitive statistic.

Monday, February 14, 2011

Owen

Here are a few recent pictures of Owen.

Watching the Super Bowl.

Showing mom his iPad skills.

Playing ball on Christmas.

Saturday, January 22, 2011

Reading List Again

Owen decided to get up at 3:30 this morning, so I thought I might as well write a post while I watch him play. It's a little early to try to write anything complicated, so I'll just do a reading list again.

Currently Reading:

The Drunkard's Walk, Leonard Mlodinow
This is a nice non-mathematical discussion of randomness and probability. It has a good description of a few of the common counterintuitive probability questions, like the Monty Hall Problem and the Two Child Problem.

Anton, Dale Eisler
See the previous entry.

The Princeton Companion to Mathematics
Ditto.

Recently Read:

American Gods, Neil Gaiman
Great. I really enjoyed this one.

Gödel's Proof, Ernest Nagel and James Newman
Kurt Gödel's Incompleteness Theorem is a great landmark in mathematical thought. While Gödel's actual paper is quite technical, the ideas are not too difficult to understand without getting too deep into the technical details. This book is a nice explanation of Gödel's proof and its implications.

In the "To Read" Pile:

A Spark at the End of Summer, David Glen Kerr
This is the first book in the Creation Myth series. I went to school with the author, and I'm looking forward to getting into this one.

Neverwhere, Neil Gaiman
Room, Emma Donoghue
Full Dark No Stars, Stephen King
Lisey's Story, Stephen King
Shalimar the Clown, Salman Rushdie
A Mathematical Nature Walk, John Adam

Also, recently I've been reading a lot of Curious George for some reason :).

Thursday, August 19, 2010

Reading List Update

I posted a reading list a few months ago, and I thought I'd post an update.

Currently Reading:

Anton, Dale Eisler
This is my uncle's third book and first novel. It's a fictionalized account of the events surrounding my grandmother's family during the Bolshevik Revolution after the first world war - Anton, the main character, is based on my great-uncle Tony. The full synopsis and other information is given on the book's website.

I'm a couple chapters in, and enjoying the writing so far. It's a bit tough for me to read, since it's very personal for me, and there are some really tragic events that happen in the story. It's going to be an interesting experience to read this.

The Princeton Companion to Mathematics
I've read a few sections here and there, which have been uniformly excellent. It's quite slow going, though, as the topics require full attention and can't really be read casually.

The Dark Tower: The Gunslinger Born
I've only read the first chapter of this, but I'm enjoying it so far.

Recently Read:

Logicomix, Apostolos Doxiadis & Christos Papadimitriou
This is a book that I almost can't believe exists - it's a graphic novel about the life of Bertrand Russell and his involvement in the development of the modern philosophy of logic and mathematics. It's difficult to describe, so I'll just link to the Amazon page.

Under the Dome, Stephen King
I thought this was one of the better recent King books, and was a quick read for a thousand-page book. It was nothing earth-shattering, but I quite enjoyed it. 4/5.

The Book of Basketball, Bill Simmons
I generally like Bill's writing style and share his sense of humour, and this book was no exception. On the other hand, I'm only a casual basketball fan, so the topic itself wasn't great for me. I'd say 5/5 for writing and 3/5 for subject matter, so I guess 4/5 overall.

In the "To Read" Pile:

Shalimar the Clown, Salman Rushdie
Godel's Proof, Ernest Nagel & James Newman
A Mathematical Nature Walk, John Adam

Monday, March 15, 2010

Chess Query Language

It's amazing how many tools are available on the web for seemingly obscure tasks. Recently, a friend of mine was writing a short story, and he needed an answer to this question: In high-level chess games, how often do the different pieces survive through the game without being captured (ignoring kings)? In the context of this question, each of the 30 starting pieces is treated as distinct; we want to know how often the pawn that starts on the a2 square survives, how often the b2-pawn survives, etc., rather than how often general pawns survive.

I think this qualifies as an obscure question. It seems simple enough to answer in principle - just get a database of games, and write something to play through each game, tracking which pieces survive. Simple enough, but a fair bit of work. Luckily there's a tool that will do this type of thing: Chess Query Language.

CQL is quite powerful, and it's pretty straightforward to set up a CQL query. For example, to answer the above question about survival rates, I started by creating a query to see how often the white queen's rook survives:

:forany Rook R
(:position :initial $Rook[a1])
(:position :terminal $Rook[a-h1-8])

That's it. The first line creates a Rook piece designator; the second and third lines specify positions that have to exist in a game for the game to match the query. Thus the query will match any game where a rook is on the a1 square in the initial game position, and that same rook is somewhere on the board in the terminal game position.

This query took about 45 minutes to run through a database of about 2.5 million games, and found that this rook survived in about 1.4 million of them. I just had this repeat for all pieces and pawns to generate the final answer.

So, I can advise that if you're ever involved in a Harry Potter-style human chess game, you should volunteer to be one of the wing pawns. Don't allow yourself to play as a knight, whatever you do.

Friday, February 12, 2010

A Few More

Here are a few more photos of Owen.

All ready for the opening ceremonies tonight.


Having fun looking out the window.


Preparing for the new season of Lost in his Dharma Initiative onesie.

Thursday, February 11, 2010

Owen at 9 Months

Owen is over 9 months old now, so here are a few new photos.

Playing with the wrapping paper on Christmas morning.


Getting ready to watch the world junior hockey game in his new Canada olympic sweater.


Jumping into the pool!


It took Owen less than a year to abandon daddy's Chargers. Smart kid.

Friday, January 15, 2010

Reading List

I received a few new books over the Christmas holidays. They total somewhere in the neighbourhood of 3,500 pages, so I should be finished reading them all roughly around the end of time. Here they are briefly, and hopefully I'll post some comments as I finish each of them. Don't hold your breath, though.

The Princeton Companion to Mathematics
This is a wonderful thousand-page book that would seem to have an incredibly narrow appeal. It's essentially a survey of current thinking across all mathematical disciplines, written to be as accessible as possible. The original goal for the book was that it could be handled by anyone with high school-level math, but the authors weren't able to meet this for all sections. I find this incredibly interesting, and pretty much everyone else I know would not find it interesting at all :).

Under the Dome, Stephen King
I'm a reasonably big fan of King, although I haven't read some of his more recent stuff. This one has been getting reviews in the range of good to great, and drawing comparisons to The Stand, which is a favourite of mine.

The Book of Basketball, Bill Simmons
Bill Simmons writes for ESPN; he's also known as The Sports Guy. This book is essentially just all of his opinions about basketball, including a few hundred pages ranking the best players of all time.

The Dark Tower: The Gunslinger Born
Stephen King wrote a seven-novel series called The Dark Tower over a period of about 30 years. Recently, Marvel has been publishing comics in the Dark Tower universe. This book is a collection of the first few issues.

A Mathematical Nature Walk, John Adam
I hadn't heard of this one prior to receiving it for Christmas, but it looks to be the kind of thing I like.

Thursday, January 7, 2010

Close But No Cigar

A friend of mine, who cheers for the Pittsburgh Steelers, has been talking about how close their losses have been this year. The Steelers finished 9-7, but the 7 losses were by a total of only 28 points, so a couple plays one way or the other could have produced a very different result. I'm quite familiar with this line of thinking, since my team is the Chargers, and last year they lost 8 games by a total of only 34 points (including a 1-point loss on a terrible blown call in a game I drove 1000 miles to see. But I digress.) I have my trusty database, so I thought I'd take a look at how these two seasons stack up historically. The following items all consider the years from 1978 through 2008.
  • Among all teams that finished at 9-7, the 2009 Steelers' total margin of defeat (28) was the lowest. The next closest were the 1993 Broncos (30) and the 2002 Saints (35).
  • The 2009 Steelers' average margin of defeat (4.0) is the lowest among all teams that lost 7 or more games.
  • Among all teams that finished at 8-8, the 2008 Chargers' total margin of defeat (34) is tied for the lowest with the 1999 Raiders.
  • The 2008 Chargers' average margin of defeat (4.25) is the lowest among all teams that lost 8 or more games. The 2009 Steelers are the only team with 7 losses to have a lower average margin of defeat.
It looks like these two seasons were in fact quite unusual. Here are a few other interesting facts I came across while tabulating these results.
  • The 16-0 2007 Patriots are a bit of a special case, but you might say that they hold the record for smallest average margin of defeat, at zero.
  • The 1983 Redskins finished 14-2, and their two losses were by one point each.
  • The next best average margin of defeat (2.33) was by the 2000 Titans, who finished 13-3 and whose losses were by a total of 7 points.
  • The team with the worst average margin of defeat (24.7) was the 1989 Steelers. They actually made the playoffs at 9-7 (unlike this year's Steelers), but had several huge losses, including a 51-0 game against Cleveland. In the playoffs, the Steelers won their first game, and then lost to the Broncos... by 1.

Tuesday, December 29, 2009

DateTimes Through OLEDB in VFP

For some time, we've been running queries against a SQL Server database through an OLE DB connection. Recently, I came across some strange behaviour when retrieving datetime values.

In one location, the application populating the SQL database allows for an empty date value. However, SQL Server doesn't allow for an empty datetime value (though it does support a null datetime). The application handles this by using the maximum SQL Server datetime value of 9999-12-31 23:59:59.997 to represent an empty date. The data looks something like this:

This is maybe a bit unusual, but not too strange. However, when querying this data through an OLE DB connection in VFP, this is the result:

That's curious. Why is the date appearing as a blank? Doing some quick investigating on the retrieved record, both Empty(ONDATE) and IsNull(ONDATE) return false. Even more curious. What would make a datetime value display as blank, but still evaluate as not empty and not null?

Ok, let's try connecting to the database using an ODBC connection instead. Here are the results of the same query:

Curious again. The data is appearing correctly here. Something must be different in the way that OLE DB and ODBC are handling these datetime values. Let's add a couple more testing values, and then retrieve them both ways, to see if that sheds any light on the situation.



This shows what's going on. The OLE DB connection is using the milliseconds to round the value to the nearest second, while the ODBC connection is just truncating the milliseconds. The weirdness with the blank value is coming from the fact that 9999-12-31 23:59:59 is also VFP's maximum datetime value, and the rounding is forcing the value past this maximum.

I generated a VFP table using the results of the OLE DB query, and opened it with a hex editor. Sure enough, there is data in the "blank" datetime value. VFP stores a datetime value in two pieces: the date as a Julian day, and the number of milliseconds past midnight. The problem value has a number of milliseconds that evaluates to slightly more than 24 hours. The Empty and IsNull functions are correctly reporting false, based on the fact that there really is a value stored there.

All in all, this is not too much trouble to work around, since we can just use an expression with CASE or DATEADD/DATEPART to have SQL Server adjust the value for us before sending the query results. It's good to understand this behaviour though, since it will also appear in other situations where milliseconds are included in datetime values, and it will be much less noticeable that any rounding is happening.

Tuesday, November 17, 2009

Pumpkin Carving Madness

For the past few years, we've held a pumpkin carving contest for Halloween. People come over and carve their pumpkins, and then the trick-or-treating kids & parents vote for their favourite. I won the first contest in 2006, but I haven't been able to repeat. Kathleen has won the past two contests.
Here are a few pictures from this year.

Pumpkin Carving Madness 2009 underway


Owen inspecting one of the pumpkins


My entry for this year, good for second place in the voting


Kathleen's winning entry

Saturday, October 24, 2009

Owen at 6 Months

Here are some new photos of Owen. He's six months old now!



Wednesday, October 21, 2009

SQL Subqueries with Null Values

Null values in data can often cause unexpected results. Recently I came across a case where the field in a NOT IN subquery contained null values, and I didn't get the behaviour I was expecting. After spending some time with this, I have it worked out, and the behaviour does make sense. It's worth having a look at.

We commonly use a NOT IN subquery to retrieve records that do not have a related record in another table. The common example of this type of query is to retrieve all customers that do not have any orders. Here's a simple example of a Customers table and an Orders table:
Customers                Orders
CustID FullName OrderID CustID OrderDate
1 John Doe 1 2 1/1/2009
2 Jane Doe 2 3 1/2/2009
3 Jack Smith 3 3 1/3/2009
4 Jane Smith
There are four customers, and two of these customers have placed orders. We can use IN and NOT IN subqueries like these:

select * from Customers where CustID in (select CustID from Orders)
2 Jane Doe
3 Jack Smith


select * from Customers where CustID not in (select CustID from Orders)
1 John Doe
4 Jane Smith

This is as we would expect. However, let's add a fourth record to the Orders table, with a null value for the CustID:
OrderID   CustID    OrderDate
4 null 1/4/2009
Now, when we run the IN query, the results are unchanged; we still get customers 2 and 3. However, when we run the NOT IN query:

select * from Customers where CustID not in (select CustID from Orders)
No records returned


Why are there no records returned? Shouldn't we still be getting customers 1 and 4, since these CustIDs do not appear in the Orders table? Well, let's look at how this gets handled. The subquery generates a list of CustIDs, like this:

select * from Customers where CustID not in ( 2, 3, null )

Logically, the NOT IN is treated as a series of not equals expressions, like this:

select * from Customers where ( CustID <> 2 and CustID <> 3 and CustID <> null )

Now, we can consider how this evaluates for our customer records. For customer 1, the where clause becomes:

1 <> 2 and 1 <> 3 and 1 <> null
= true and true and null
= null

This is why record 1 doesn't appear in the result set; for records to appear, the where clause must evaluate to true, not to null.

Now that I've gone through the logic on this, it's not really correct to say that customers 1 and 4 don't have any orders. The null CustID value in the Orders table means that the customer for that order is unknown, so we can't guarantee that this order doesn't belong to customer 1 or 4.

Tuesday, August 4, 2009

Stonefield Article on SoftwareCEO

Stonefield Software is the subject of an extensive article on SoftwareCEO.

Wednesday, July 22, 2009

Stonefield Profile in the Financial Post

The Financial Post published an article profiling Stonefield Software yesterday.

Prairie firm finds its markets

Monday, July 13, 2009

Stonefield Profile

An article profiling Stonefield Software, the company I work for, was on the front page of the business section in the Leader Post. The article is available on the Leader Post website.

Stonefield Software the little Regina company that could

Wednesday, June 17, 2009

Exposition Problems

Recently, there was a blog post on my feed reader, referencing a recent paper on the topic of Open Exposition Problems in mathematics. To introduce this term, I'll use the same quote from the paper as was given in that blog post:

All mathematicians are familiar with the concept of an open research problem. I propose the less familiar concept of an open exposition problem. Solving an open exposition problem means explaining a mathematical subject in a way that renders it totally perspicuous. Every step should be motivated and clear; ideally, students should feel that they could have arrived at the results themselves.

This is an interesting idea, and I think it has applications in software development as well. The normal approach when explaining an algorithm is to just explain its steps. For any reasonably complex algorithm, it's also required to give some justification for why these steps achieve the desired result. Generally, the idea is that the student obtains enough of an understanding of the logic to produce a working version of the algorithm, and to extend it if need be.

That's fine, but the quoted text above goes further. It talks not only about the problem itself, but also about the motivation behind the steps of the solution, and about the student's feeling they could have constructed the solution themselves. This is something else entirely. We're now talking not just about explaining an algorithm, but explaining the process through which the algorithm was devised.

When writing code, we are always encouraged to add comments explaining how the code works. When the code needs to be maintained later, it's helpful to have these comments rather than having to work out what the code is doing. But, if someone's maintaining the code, it seems likely that they may be needing to write some similar code of their own. Maybe they need to extend this piece of code, or write a similar method in another language. In such a case, "exposition" comments might be useful as well, talking about how the code came about, other options that were rejected, and so on.

In any case, it's interesting to think about, both in terms of mathematics and software development. If nothing else, I learned the word perspicuous, and got a bit of a laugh that it was the word chosen to explain about making ideas completely clear.

Tuesday, June 16, 2009

Owen at 2 months

Here are a couple recent photos of Owen. Yesterday was his two-month birthday!