Friday, April 29, 2011

Considering a gas-powered standby generator

I've been wearing my Bo Williams Risk Analysis™ cap a fair amount for the past couple of days, and this post started life as a comment on his post Friday miscellanea, post-Alabama tornado super-outbreak edition.

Our house has gas heat and a gas set in the fireplace. I've been letting the latter slide in a state of disrepair. I recognize and accept this BWRA™ Demerit. It will be ready before winter 2011, which will mean redundant sources of heat. You ought to see my related GTD project list!

The option is obvious now, but it took a conversation with my dad to learn about permanent standby generators that run on natural gas and periodically test themselves. I priced them online and may be able to purchase a unit that would power most of my house, perhaps in staggered operation for heavy loads such as HVAC and dryer, for around $5k with no headaches of managing a gasoline reserve or just-in-time fuel purchases.

The last week-long outage in the area was nearly forty years ago, but sidestepping even hours-long outages due to storms, ice on power lines, drunks hitting poles, and so on is awfully appealing too. I emptied the refrigerator and freezer, and temperatures in the Huntsville area are projected to be mild. My one power-related worry is my 55-gallon cichlid tank. I turned on a battery-powered air pump, but that's about the best I could do. I think I was a week overdue for a water change when we lost power, so staying on top of aquarium chores in the future will help there too, assuming optimistically that these hardy critters make it.

Other questions:
  • Where can I find comprehensive lists of electrical and gas outages to find whether I'm trading more-or-less equivalent problems?
  • How expensive would backup mode be?
  • Fossil fuels in general aren't getting any cheaper, so at what gas price does such a generator become a total dud?
  • What about purification of, say, rain water?
  • I expect a crazy run on generators when we're no longer part of the third world. What are good value metrics?
  • What other issues do I need to consider?

Saturday, April 23, 2011

Are coaches to blame for the awful new taunting rule?

In What if you were an SEC Official For a Day? (Part One), Clay Travis blames NCAA coaches for the new rule that allows officials to take points off the board and even eject players for behavior deemed to be taunting.
But officials believe that the coaches, who are the ones who actually make the rules, have foisted the enforcement of taunting onto the officials to relieve pressure on themselves. That is, coaches can point to the officials as the bad guys who are keeping the players from taunting. Effectively, multi-million dollar coaches are ducking the obligation to discipline their teams onto part-time officials. 
As Steve Shaw notes, “Coaches write the rules. They want it. They control it.” … 
The outrage should go to the coaches who implemented this rule. They did it because they don’t want to be the sheriffs. They want to blame the officials for not letting the players celebrate. And, by the way, do you know who will lead the charge in criticizing officials when this call is made to his team’s detriment? 
Yep, the head coach who voted to make this a rule in the first place.
I don't buy this for a second. I'd like to see a rollcall vote from head coaches of major NCAA programs on whether they want this awful rule. These guys risk permanent facial disfigurement screaming at players who invite stupid showboating flags in critical situations—hardly a consensus endorsement.

In defense of players, controlling emotion can be really difficult. Any fan has been in the situation of hugging the guy next to him after a big stop in a tense situation. Now for the player sweating and bleeding in the trenches who breaks the go-ahead TD or comes up with a pick deep in his own territory, of course he's going to be elated and especially in big, high-pressure games. The players' passion is a wonderful distinguishing feature of NCAA football.

The biggest flaw of the rule is that it conflates celebration and taunting. Yes, there are cases were players have engaged in unsportsmanlike taunting meant to demean opponents, but I'd be surprised if these were anything other than a tiny minority. A study segregating celebration flags into piles of behavior intended to deride the guys on the other side versus spontaneous joy of accomplishment, although highly subjective, would be an interesting result. Anyone interested in collaborating on tauntingornot.com?

This looks like another hook to give officials even more influence over games' outcomes. Some pencil-necked geek on the make at the corrupt NCAA is behind this.

Monday, February 28, 2011

Extracting comma-separated integers with Perl

A friend writes asking whether
my @data = ( $data =~ m|(-?\d+),(-?\d+),(\-?\d+)\r| );
or
($data) = (split "\r", $data);
my @data = split ',', $data;
would be better for extracting integers from a line of input, and my reply is below.

The best approach depends on a few factors. Who generates the data you're processing? How much slop in the input format do you need to accommodate? How flexible do you need to be with respect to future changes in the input, e.g., extra fields, different types, and so on?

The CR (\r) in your input is a red flag. Are you running on a Unix platform with input generated on Windows? Can you be more specific about “possibly some other stuff” after the comma-separated numbers?

Perl's $/ special variable can handle oddball line endings. Its default value varies with what makes sense for the current platform: e.g., \n on Unix and \r\n on Windows. Macs introduce another twist (see Newlines in the perlport documentation), but I assume you're not using that platform.

On Windows for files opened in text mode (the default), the C library silently transforms CR followed by LF into LF, so if this matches your setup, I'm surprised you're seeing the \r at all.

Say your input is plain text generated on Windows, and you're running on Linux. Then you'd process it with code of the form
$/ = "\r\n";

while (defined($data = <>)) {
  chomp;
  ...;
}
Remember that chomp removes the value of $/ from the end of the target.

As for extracting the data, Randal Schwartz (author of Learning Perl, a.k.a. the llama book) has a rule of thumb:
Use capturing or m//g when you know what you want to keep.
Use split when you know what you want to throw away.
I first saw this useful guideline in “Regular Expression Mastery” by Mark Dominus.

If this is a quick-and-dirty utility, I'd be inclined to write
@data = split /\s*,\s*/, $data;
This allows for and removes any whitespace around the commas.

If it's important to nail down the format (maybe as a sanity check that you're in the section of the config file where you think you are), you could write
if ($data =~ /^\s*(-?\d+)\s*,\s*(-?\d+)\s*,\s*(-?\d+)\s*$/) {
  my($x,$y,$z) = ($1,$2,$3);
  ...;
}
else {
  die "$0: $ARGV:$.: unexpected format";
}
Note the use of $1 and friends inside the conditional only. Always, always, always protect uses of capture variables with conditionals.

The pattern is just at the annoyance threshold of repetition and illegibility. Perl version 5.10 opens up nice possibilities with named capture buffers:
#! /usr/bin/perl

use strict;
use warnings;

use 5.10.0;

my $record = qr/
  ^
  (?&ws)
  (?<num>(?&n)) (?&sep) (?<num>(?&n)) (?&sep) (?<num>(?&n))
  (?&ws)
  $

  (?(DEFINE)
    (?<n> -? \d+)
    (?<ws> \s* )
    (?<sep> (?&ws) , (?&ws))
  )
/x;

while (<DATA>) {
  if (/$record/) {
    my($x,$y,$z) = @{ $-{num} };
    print "got: x=$x, y=$y, z=$z\n";
  }
  else {
    warn "$0: line $.: no match\n";
  }
}

__DATA__
1,2,3
4,5,6
7,8
Its output:
got: x=1, y=2, z=3
got: x=4, y=5, z=6
./prog: line 3: no match
Notice its use of the special %- hash that records all captures named “num” in this case. With (DEFINE), subpatterns get meaningful names, and the /x modifier allow for judicious use of whitespace inside the pattern.

Friday, December 31, 2010

Checkers game-over in Haskell

The programming subreddit recently had a discussion about testing a checkers board for game-over. I wondered how specifying the rules for legal moves would look with Haskell's pattern matching, and this post is a study of that technique. In fact, you can run yourself. Copy-and-paste the post body to a file named Checkers.lhs to get a working program!

The game is American checkers or English draughts, played on an eight-by-eight checkerboard, of all surfaces.

> {-# LANGUAGE ViewPatterns #-}
> module Checkers where
> import Data.Char (toLower,toUpper)
> import Data.List (tails,transpose)
> import Test.HUnit
> data Board = Board [String] deriving (Show)
> size :: Int
> size = 8

For a rough idea of the punchline, I was hoping for code along the lines of

move ('w':' ':_)     = 1
move ('W':' ':_)     = 1
move (' ':'W':_)     = 1
move ('w':'b':' ':_) = 1
move ('w':'B':' ':_) = 1
move ('W':'b':' ':_) = 1
move ('W':'B':' ':_) = 1
move (' ':'b':'W':_) = 1
move (' ':'B':'W':_) = 1
move _ = 0

and eventually

> gameOver :: Board -> Bool
> gameOver b = blueMoves b == 0 || whiteMoves b == 0

The OP on reddit chose white and blue for the sides' colors, and above we have more-or-less declarative rules for legal white moves. A pawn or king (w and W respectively) can move to an empty space before it. Kings are special in that they can move backwards. The list ends with legal jumps, and everything else is invalid.

The code is repetitive, but I'll clean that up later.

An immediate problem is the patterns are linear, but all legal moves in checkers are along diagonals. I kicked around ideas such as using IArray or nasty double-applications of !!. Then I realized I could rotate the board by 45° with a shear, a transposition, and removal of placeholders.

-- diagonals with positive slopes
posdiags = map reverse . filter used . transpose . map shear . zip [0..]
  where shear (i,s) = (replicate i              '#') ++ s ++
                      (replicate (k - size - i) '#')
        k = 2 * size - 1
        used = not . all (`elem` "#.")

Getting the other diagonals is similar, but again brings too much repetition.

negdiags = map reverse . filter used . transpose . map shear . zip [0..]
  where shear (i,s) = (replicate (k - size - i) '#') ++ s ++
                      (replicate i              '#')
        k = 2 * size - 1
        used = not . all (`elem` "#.")

Having Board values to play with is trivial:

> board :: String -> Board
> board s = Board $ go s
>   where go [] = []
>         go xs = let (a,bs) = splitAt size xs
>                 in a : go bs

It chops one long string into rows, but with Haskell's usually-awkward multiline strings, it's not so bad. For example

startBoard =
  ".b.b.b.b\
  \b.b.b.b.\
  \.b.b.b.b\
  \ . . . .\
  \. . . . \
  \w.w.w.w.\
  \.w.w.w.w\
  \w.w.w.w."

An early cut at blueMoves and reducing the repetition in the rules for moves was

blueMoves :: Board -> Int
blueMoves (diagonals -> (p,n)) =
  sum $ map move $ concatMap tails $ p ++ n
  where move ( b :' ':_) | b `elem` "Bb" = 1
        move (' ':'B':_) = 1
        move ('b': w :' ':_) | w `elem` "Ww" = 1
        move (' ': w :'B':_) | w `elem` "Ww" = 1
        move _ = 0

Sticking with the theme of repetition, whiteMoves is nearly identical with little breadcrumbs of differences. That was all good because I wanted to have a testsuite before I started refactoring.

tests :: Test
tests = test
  [ assertEqual "white must have piece to move"
      0 (nw ".b.b.b.b\
            \b.b.b.b.\
            \.b.b.b.b\
            \ . . . .\
            \. . . . \
            \ . . . .\
            \. . . . \
            \ . . . .")
  ]
  where nw = whiteMoves . board

Not bad for a start, but each testcase will have a dual for the other side—way too much copy-and-paste.

*Checkers> runTestTT tests
Loading package HUnit-1.2.2.1 ... linking ... done.
Cases: 1  Tried: 1  Errors: 0  Failures: 0
Counts {cases = 1, tried = 1, errors = 0, failures = 0}

Whee!

To wring out the duplication in the code for each side's moves, I considered using Template Haskell—a cousin of Lisp macros for Haskell. I decided to push lexical closures as far as I could, and the result is below.

> blueMoves, whiteMoves :: Board -> Int
> [blueMoves, whiteMoves] =
>   let blueOrder = id  -- diagonals emerge in blue's perspective
>       whiteOrder = map reverse
>       count (direction,side) (diagonals -> ds) =
>         sum $ map sideCanMove $ concatMap tails $ direction $ ds
>         where sideCanMove ( p :' ':_)     | same p = 1
>               sideCanMove (' ': k :_)     | king k = 1
>               sideCanMove ( p : o :' ':_) | same p && opponent o = 1
>               sideCanMove (' ': o : k :_) | king k && opponent o = 1
>               sideCanMove _ = 0
>               same p     = piece p && toLower p == toLower side
>               opponent p = piece p && toLower p /= toLower side
>               king p     =  same p &&         p == toUpper side
>               piece p    = p `elem` "BbWw"  -- filter empty spaces
>   in map count [ (blueOrder, 'b'), (whiteOrder, 'w') ]

The code in count (notice the view pattern?) is a skeleton to be customized for the blue side and the white side, and it distills the repeated code. The definition of sideCanMove generalizes the rules for legal moves on either side. We have to reverse the diagonals to make them usable on the white side.

To get both sets of diagonals, the only difference is how to shear the board: bottom-away for positive slopes and top-away for negative.

> -- positive slopes slice from NW to SE
> -- negative slopes slice from SW to NE
> -- both extend in blue's direction (north-to-south)
> diagonals :: Board -> [String]
> diagonals (Board rows) = positiveSlopes rows ++ negativeSlopes rows
>   where positiveSlopes = go $ \(i,xs) -> (i, k - size - i, xs)
>         negativeSlopes = go $ \(i,xs) -> (k - size - i, i, xs)
>         k = 2 * size - 1
>         used = not . all ignored
>         go order = filter (not . null)
>                  . map (filter $ not . ignored)
>                  . transpose
>                  . map (shear . order)
>                  . zip [0..]
>         ignored = (`elem` "#.")
>         shear (l,r,s) = (replicate l '#') ++ s ++ (replicate r '#')

Finally come the tests that I added as I went. To factor out duplication, each board becomes two testcases. The first is as-is, and the same condition should hold for the other side. See the definition of invert in the where clause.

I had hoped for a more elegant result, but it was an interesting exercise and a fun problem!

> tests :: Test
> tests = test $ concat
>   [ checkMoves "must have piece to move"
>       0 ".b.b.b.b\
>         \b.b.b.b.\
>         \.b.b.b.b\
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . ."
>   , checkMoves "one move"
>       1 ". . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \w. . . ."
>   , checkMoves "one king move"
>       1 ". . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \W. . . ."
>   , checkMoves "two moves"
>       2 ". . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ .w. . ."
>   , checkMoves "king can move back from end"
>       2 ". . .W. \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . ."
>   , checkMoves "can jump opponent pawn"
>       1 ". . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \.b. . . \
>         \w. . . ."
>   , checkMoves "can't jump blocked opponent"
>       0 ". . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ .b. . .\
>         \.b. . . \
>         \w. . . ."
>   , checkMoves "can jump opponent king"
>       1 ". . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \.B. . . \
>         \w. . . ."
>   , checkMoves "king can jump trailing opponent"
>       1 ". . . .W\
>         \ . . .b.\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . ."
>   , checkMoves "king can't jump protected opponent"
>       0 ". . . .W\
>         \ . . .b.\
>         \. . .b. \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . ."
>   , checkMoves "king can't jump onto own piece"
>       1 ". . . .W\
>         \ . . .b.\
>         \. . .w. \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . ."
>   , checkMoves "king has four moves"
>       4 ". . . . \
>         \ . . . .\
>         \. . . . \
>         \ . .W. .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . ."
>   , checkMoves "cannot displace opponent on king row"
>       0 ". . .b.b\
>         \ . . .w.\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . .\
>         \. . . . \
>         \ . . . ."
>   ]
>   where nw = whiteMoves . board
>         nb = blueMoves  . board
>         checkMoves name expect b =
>           [ assertEqual ("white: " ++ name) expect (nw b)
>           , assertEqual ("blue: "  ++ name) expect (nb $ invert b)
>           ]
>         invert = reverse . replace [('W','B'), ('w','b'), ('B','W'), ('b','w')]
>         replace tbl = map (\c -> maybe c id $ lookup c tbl)

Monday, October 18, 2010

Healthy weight loss diet the CrossFit way

The CrossFit Journal published an easy guide to starting the Zone diet, and it's available as a free download.

Check the chart on page 2 to find how many blocks per day you should eat. You could also tinker with this Zone block calculator. You'll need to know your weight and have an idea of your body-fat percentage. The recommended activity level is 0.7 for Crossfitters, so select “Light to medium 2-3x per week.” Yes, I share your likely indignation at that unjust description!

Page 3 gives a block chart with columns for proteins, carbs, and fats—plus a small combo section. The next page lists unfavorable carbs that earn this designation due to their tendency to rapidly spike your insulin (also known as having a high glycemic load). This doesn't mean you can't have them—you can Zone just about anything—but that you want to limit how often you eat them. Being from 2004, the table is a bit dated, and the Dr. Sears people have since promoted carrots to favorable status, for example. I'm not aware of other changes.

The inset picture is a cellphone snapshot of my 4-block breakfast: 4 eggs scrambled in 1⅓ teaspoons of butter, an orange, half a cup of salsa, and a cucumber.

I keep a copy of the block charts above my refrigerator at home. To put together a meal with the chart, you need to know how large it will be, i.e., how many blocks, and then you pick that many blocks of protein, carbs, and fat. The chart on page 2 suggests five 2-block meals for a ten-block day, for example, but size your meals in a way that works best for you: maybe three 3-block meals and then a 1-block snack before bed.

Let's walk through my thought process for today's 4-block “first lunch.” I wanted chicken breast, and the chart tells me an ounce is one block. That means I get four ounces of chicken breast. I like pears, and a pear counts for two blocks, leaving me with two more to go. A half-cup of carrots is a block, so a whole cup makes two blocks. For fat, about three pistachios constitute a block, so I had 12 (= 4 blocks × 3 pistachios/block). In summary,
  • Protein: 4 ounces of chicken breast (4 blocks)
  • Carb: a pear (2 blocks); 1 c. carrots (2 blocks)
  • Fat: 12 pistachios (4 blocks)
After doing it a while, you'll memorize your frequent choices, and I put together the above meal without having to consult the chart. Pistachios aren't listed, so I must have looked it up on the web. For other examples (with pictures!), read Jeff's “The Zone Diet Explained” blog post. For tips on eating out, read “Top 10 Zone-Friendly Meals in Huntsville.”

If you'd like a more exciting meal, the number of ingredients is entirely up to you. Remember that you don't necessarily have to use whole-block portions, so you could make a salad with several different ingredients. Just be sure that the totals add up correctly. The rest of the article has tasty and easy recipes, separated into 2-, 3-, 4-, and 5-block meals and also 1-block snacks. The chili is delicious!

It does take a week or two of getting used to. Some suggest that many of our food cravings are due to hormonal imbalance, and Zone is designed to level them out. I no longer have the ups and downs from spiking my blood sugar with carb overload, and I'm leaner than I've been in 10+ years. Don't go crazy either: let yourself cheat now and then. Among many other benefits, fish oil will cut you some slack on your diet. A common recommendation is to start off eating strictly for a month and then, after seeing the great results this will produce, maintaining on an 80/20 cycle—strict during the week and relaxed on the weekends.

Thursday, June 24, 2010

Hard-boiled eggs in a microwave

I found instructions at eHow for making hard-boiled eggs in a microwave. I tried it this morning, and it worked!

The tl;dr version of the steps is

  1. fill bowl with enough water to cover eggs
  2. remove eggs
  3. bring water to a boil
  4. carefully place eggs in hot water
  5. cover with a plate and cook on low power for 8 minutes
  6. let stand for another 6-8 minutes

I cooked the eggs in a GE Profile JES2251SJ microwave. I unintentionally left out the salt and vinegar. I cooked four eggs, and it took the water about 4 minutes to come to the initial boil. This particular model has power settings from 1 to 10, and I used setting 2 on the fifth step. The instructions say the plate is for limiting the mess in case an egg explodes, but I used an upside-down paper plate. I doubt it would have been great for containment.

After all this, I poured out the hot water and ran cold water over the eggs a couple of times. Then I added ice and waited a few minutes for them to cool off.

At this point, I was relieved that none of the eggs had exploded, but—as you might imagine—I was worried that I hadn't cooked them enough. I picked up the first, and it felt pretty solid. Then a gentle tap-tap-tap. No runny mess!

The yolks were well done, but the whites were a touch runny in places on the outside. Next time, I'll either try a slightly less-low low-power setting or let the eggs stand a bit longer.

Thursday, May 13, 2010

Intel WiFi 6000 on Ubuntu 10.04

A fresh install of Ubuntu 10.04 on a Dell Studio XPS 16 didn't want to enable its Intel Wireless WiFi Link 6000. Pressing the wifi touchkey didn't help.

Running rfkill list gave

0: phy0: Wireless LAN
             Soft blocked: yes
             Hard blocked: no
NetworkManager Applet reported wireless as disabled or device not ready.

I read that removing the dell_laptop kernel module might help, but it did no good in my case.

What finally did the trick for me was

sudo rfkill unblock wifi