Saturday, February 27, 2010

Here’s a version with simple certainty factors, which are based on categories. It seeks to prove hypotheses until it finds one that is at least “Likely.” I changed some of the names to be more consistent with common usage. I also cleaned up the F# a bit.

Standard disclaimers and caveats apply: a weekend fun project, not thoroughly tested, use at your own risk.

open System

// See previous post for additional comments.
// Formatted for blog width.

// Certainty factors based on categories.

type Certainty =
| Impossible = 0
| Disproven = 1
| Unlikely = 2
| Possible = 3
| Likely = 4
| Proven = 5
| Certain = 6

// Likely and Unlikely define the boundaries for
// acceptance and rejection.

let Likely (c) = c>=Certainty.Likely

let Unlikely (c) = c<=Certainty.Unlikely

// Custom Min and Max.

let Min c0 c1 =
match (c0<c1) with
| true -> c0
| false -> c1

let Max c0 c1 =
match (c0>c1) with
| true -> c0
| false -> c1


// I cleaned up the Consider functions quite a bit.

let ConsiderBase s (b:Lazy<Certainty>) =
printfn "Considering <-- %s" s
printfn "Concluding --> %s is %s" s (b.Value.ToString())


let Consider s (b:Lazy<Certainty>) = lazy (
ConsiderBase s b
b.Value)


let ConsiderImmediate s (b:Lazy<Certainty>) =
ConsiderBase s b
b


// Conjunction functions converted to certainty.

let Conjoin a (b:unit->Certainty) =
match Unlikely(a) with
| true -> a
| false -> Min a (b())


let rec ConjunctionPossible (l:Lazy<Certainty> list) =
match l with
| [] -> Certainty.Certain
| h::t ->
match h.IsValueCreated with
| false -> ConjunctionPossible(t)
| true ->
Conjoin
h.Value
(fun unit -> ConjunctionPossible(t))


let rec ConjunctionEval (l:Lazy<Certainty> list) =
match l with
| [] -> Certainty.Certain
| h::t ->
Conjoin
h.Value
(fun unit -> ConjunctionEval(t))


let Conjunction (l:Lazy<Certainty> list) = lazy (
let possible = ConjunctionPossible(l)
match Unlikely(possible) with
| true -> possible
| false -> ConjunctionEval(l))


// Disjunction functions converted to certainty.

let Disjoin a (b:unit->Certainty) =
match Likely(a) with
| true -> a
| false -> Max a (b())

let rec DisjunctionPossible (l:Lazy<Certainty> list) =
match l with
| [] -> Certainty.Impossible
| h::t ->
match h.IsValueCreated with
| false -> Certainty.Certain
| true ->
Disjoin
h.Value
(fun unit -> DisjunctionPossible(t))


let rec DisjunctionEval (l:Lazy<Certainty> list) =
match l with
| [] -> Certainty.Impossible
| h::t ->
Disjoin
(h.Value)
(fun unit -> DisjunctionEval(t))


let Disjunction (l:Lazy<Certainty> list) = lazy (
let possible = DisjunctionPossible(l)
match Unlikely(possible) with
| true -> possible
| false -> DisjunctionEval(l))


// This function will evaluate all hypotheses.

let rec Maximum (l:Lazy<Certainty> list) = lazy (
match l with
| [] -> Certainty.Impossible
| h::t -> Max h.Value (Maximum(t)).Value)


// Sample data.

let black =
Consider "black" (lazy Certainty.Possible)

let blue =
ConsiderImmediate "blue" (lazy Certainty.Likely)

let orange =
Consider "orange" (lazy Certainty.Unlikely)

let white =
Consider "white" (lazy Certainty.Likely)

let blackAndOrange =
Consider
"blackAndOrange"
(Conjunction [
black;
orange ])

let blackAndOrangeOrBlue =
Consider
"blackAndOrangeOrBlue"
(Disjunction [
blackAndOrange;
blue ])

let whiteAndBlack =
Consider
"whiteAndBlack"
(Conjunction [
white;
black ])

let color =
ConsiderImmediate
"colorIsKnown"
(Disjunction [
blackAndOrange;
blackAndOrangeOrBlue;
whiteAndBlack ])

Console.ReadLine() |> ignore

Looking at the tiny expert system in the previous post reveals some obvious problems. Perhaps worst among them, the system will continue to ask for values even when it is obvious that a conjunction will fail. Most of these problems could be solved by the clever use of intermediate hypotheses and by paying careful attention to the ordering of the hypotheses. However, there’s a better way: construct a tiny inference engine.

Before I show that, let me say some things about what this is not and what it is. First, this is not necessarily the best way to build an inference engine; it is not even necessarily the best way to build a toy inference engine. Second, it is not a compendium of F# design patterns or best practices. Third, it is not thoroughly checked for quality or errors, it is a bit of weekend fun – use it at your own risk. Here’s what it is: it was a fun exercise in learning some things about F#. In particular, it shows how F# can easily be used as a framework for constructing domain and application-specific languages.

The tiny inference engine is made up of three things:

Consider and ConsiderImmediate – functions which define and instantiate hyptheses. Note that these are functionally very simple; most of the code in them is for readability and reporting.

ConjoinPossible, ConjoinEval, and Conjoin – functions which combine hypotheses conjunctively (i.e. using “and”). The first two functions are helpers. ConjoinPossible determines whether a conjunction is still possible given the current state of the evidence. ConjoinEval performs an actual conjunction. Conjoin groups the previous functions into a neat package.

DisjoinPossible, DisjoinEval, and Disjoin – equivalents of the conjunctive functions which combine hypotheses disjunctively (i.e. using “or”).

There is also a small sample set of rules which reason about the color of a thing. Rather than query the user, I hard-coded the values for the root hypotheses. This simplifies testing. Also, please note that the code is specially formatted to fit the narrow blog window.

// Note: formatted for blog width.

// Lazy evaluation of an hypothesis.
// Everything except the return
// is just for information.
let Consider s (b:Lazy<bool>) = lazy (
printf "Considering: "
printfn s
match b.Value with
| false -> printf "Rejecting: "
| true -> printf "Accepting: "
printfn s
b.Value)

// Immediate evaluation of an hypothesis.
// Everything except the return
// is just for information.
let ConsiderImmediate s (b:Lazy<bool>) =
printf "Considering: "
printfn s
match b.Value with
| false -> printf "Rejecting: "
| true -> printf "Accepting: "
printfn s
b

// This set of functions handles conjunction.

// True on all true or unknown.
let rec ConjoinPossible (l:Lazy<bool> list) =
match l with
| [] -> true
| h::t ->
if (h.IsValueCreated)
then (h.Value && ConjoinPossible(t))
else ConjoinPossible(t)

// Conjoin with short-circuit on false.
let rec ConjoinEval (l:Lazy<bool> list) =
match l with
| [] -> true
| h::t -> h.Value && ConjoinEval(t)

// Conjoin if possible.
let rec Conjoin (l:Lazy<bool> list) = lazy (
ConjoinPossible(l) &&
ConjoinEval(l))

// This set of functions handles disjunction.

// True on at least one true or unknown.
let rec DisjoinPossible (l:Lazy<bool> list) =
match l with
| [] -> false
| h::t ->
if (h.IsValueCreated)
then (h.Value || DisjoinPossible(t))
else true

// Disjoin with short-circuit on true.
let rec DisjoinEval (l:Lazy<bool> list) =
match l with
| [] -> false
| h::t -> h.Value || DisjoinEval(t)

// Disjoin if possible.
let rec Disjoin (l:Lazy<bool> list) = lazy (
DisjoinPossible(l) &&
DisjoinEval(l))

// Here are some test hypotheses.

// This first block contains hard coded values.
// In real life, these would be input data.
// They are hard-coded here to simplify testing.

let black =
Consider "black" (lazy true)

let blue =
ConsiderImmediate "blue" (lazy true)

let orange =
Consider "orange" (lazy false)

let white =
Consider "white" (lazy true)

// This second block is the logic.

let blackAndOrange =
Consider
"blackAndOrange"
(Conjoin [
black;
orange ])

let blackAndOrangeOrBlue =
Consider
"blackAndOrangeOrBlue"
(Disjoin [
blackAndOrange;
blue ])

let whiteAndBlack =
Consider
"whiteAndBlack"
(Conjoin [
white;
black ])

let color =
ConsiderImmediate
"color"
(Disjoin [
blackAndOrange;
blackAndOrangeOrBlue;
whiteAndBlack ])

// Run the system.

open System

Console.ReadLine() |> ignore


So what’s next? I’m not sure. For one thing, I’d like to add certainty factors. This may entail a more complex record type. In the interests of exercise particular F# features, I will likely base this on records or discriminated unions rather than classes. Stay tuned.

Friday, February 26, 2010

Bit of a gap, what with holidays, learning some XNA, learning some F#, etc.

As a restart, I present for your amusement a tiny expert system written in F# using lazy evaluation. The entire thing is written declaratively, with the exception of a bit of syntactic sugar in the IO (GetResponse and PrintResult). It mirrors the kind of simple expert system examples typically found in entry-level Prolog books, etc.

open System

let GetResponse q =
printf q
printf " "
let rtn = (Console.ReadKey().KeyChar='y')
printfn ""
rtn

let PrintResult s =
printfn s
true

let black = lazy (
GetResponse "Does the animal have black color?")

let fins = lazy (
GetResponse "Does the animal have fins?")

let orange = lazy (
GetResponse "Does the animal have orange color?")

let spots = lazy (
GetResponse "Does the animal have spots?")

let stripes = lazy (
GetResponse "Does the animal have stripes?")

let white = lazy (
GetResponse "Does the animal have white color?")

let blackAndOrange = lazy (
black.Value &&
orange.Value &&
PrintResult("(Asserting: black and orange.)"))

let blackAndWhite = lazy (
black.Value &&
white.Value &&
PrintResult("(Asserting: black and white.)"))

let isAFish = lazy (
fins.Value &&
PrintResult("(Asserting: is a fish.)"))

let dalmation = lazy (
spots.Value &&
blackAndWhite.Value &&
PrintResult("The animal is a dalmation."))

let leopard = lazy (
spots.Value &&
blackAndOrange.Value &&
PrintResult("The animal is a leopard."))

let tiger = lazy (
stripes.Value &&
blackAndOrange.Value &&
PrintResult("The animal is a tiger."))

let zebra = lazy (
stripes.Value &&
blackAndWhite.Value &&
not isAFish.Value &&
PrintResult("The animal is a zebra."))

let zebraFish = lazy (
stripes.Value &&
blackAndWhite.Value &&
isAFish.Value &&
PrintResult("The animal is a zebra fish."))

let animal =
dalmation.Value ||
leopard.Value ||
tiger.Value ||
zebra.Value ||
zebraFish.Value ||
PrintResult("Must be a sasquatch!")

Console.ReadLine() |> ignore

Monday, October 5, 2009

Here's a first cut at another Halloween poem. I reserve the right to revise it.

Their Woods

There in the dark
Everything seemed older than me
My uncle, my cousins, the woods
But especially the woods

After a day of fishing at the creek
We gathered on the road to the barn
At the place by the henhouse
Where it forked and went down
To the pond in the woods

A small expedition
Launched at night
To carry the bait trap
Down to the pond
Where the crawdads
Would keep fresh

I didn’t want them to go without me
I was worried they might come back changed
Bonded in some way I could not know
Or caught and replaced by monsters
And I would never know

But I was scared
And the white circle of light
From the hissing gas lantern
Seemed too small and fragile
To keep back the woods and the dark

Or perhaps I was afraid
That they might change
Down there in the woods
And I would not

So I stayed behind
And I’ll never know
What the pond was like
In the woods that night
And whether they changed

Thursday, October 1, 2009

For a Departed Swimming Pool

The man we hired to fill the old pool
Got the backhoe through the fence, but
To get his dump truck into the yard
Had to uproot a burning bush
Which proved to have a nest of bumble bees
In its roots

And now they swarm there
Awaiting Diaspora from the from the only home
They’ve ever known
A world of shade and green
Become a wasteland of mud and straw

Milling about not enraged but hapless
Longing for the promised land
Waiting for their Moses
To lead them across the dirt filled pool
Away from pharaoh and his backhoe

But until they depart
We must go quietly
And put on our shoes
As though crossing holy ground

Tuesday, September 29, 2009

Here's a Halloween poem, a bit early.

The Dark Orchard

I used to live in a old house
Perhaps sixty or seventy years old
From the 1910’s or 1920’s
And it had an orchard

Almost as old and gone to seed
Almost as long
Grown up with low limbs
And brush, and small trees
The ground was spongy with
Rotting apples
Smelling of
Rotting Cider
Full of the sound of
Wasps

There was a hostility about the place
As though, having been abandoned by Man
Man was no longer welcome

And the trees seemed to watch
And to whisper among themselves
As though waiting
For some Man to go there alone
In the dark
Or in a storm

To the point where
I worried for the deer
That browsed there at night
That the trees might sense them
And decide to get in
A bit of practice

Monday, September 28, 2009

I've been studying to have my poetic license renewed, so I will post a series of poems. The first has two versions, because I can't decide which I like the best. The first version has a quality like transliterated haiku, which I like, but the second version flows better:

Embrace

I saw a glove
Stomped into the parking lot
Of an old warehouse

The fingers spread like wings
At first I thought
It was a bird

It grasped the asphalt
To its palm
The way a dead bird
Clutches the earth
To its breast


(Alternate Version)

I saw a glove
Stomped into the parking lot
Of an old warehouse

At first I thought
It was a bird

The fingers spread like wings
And grasped the asphalt
To its palm

The way a dead bird
Clutches the earth
To its breast

Monday, July 6, 2009

Pause

Code to follow soon. In this meantime, this copied from a letter to a friend:

The hamburgers on the fourth were good, but the fireworks were somewhat rained out. Small loss, though, since various neighbors let off fireworks all summer long every year, and there's still a lot of summer left.

This morning I am mourning the loss of five ripening green peppers, which met an untimely end last night at the paws of a raccoon. He ate most of two fancy Italian peppers, but only picked and scattered the three common green peppers (presumably they were beneath his taste). The miscreant in question is well-known in the neighborhood; he cruises through periodically like a biker hoodlum in a 1950’s film, wreaking all sorts of havoc with the innocent townsfolk. To this point, however, he has largely confined his attention to chewing and scattering small plastic objects, etc., and has left the plants alone.

It’s an interesting comment on the universe that one of the first acts of incipient intelligence in the animal kingdom is apparently the desire to pull Halloween-style pranks characteristic of a small-town hood. I’m not certain it bodes well. Perhaps not, but perhaps so, since not a few delinquents do go on to become productive, upstanding members of the community. In any case, as in so many things in the universe, we see the large mirrored in the small, the universal in the particular.

So I am able to recover some of the loss of increase of my garden by reflecting on the idea that I have exchanged five peppers for a good story. Was it worth it? Well, I think I would rather have traded one pepper for not quite as good a story. But life is about extracting meaning from events, and not the converse (which is art).

I hope in the meantime, however, that raccoon doesn't get his hands on fireworks...

-Neil

Tuesday, June 30, 2009

Enumerators for Dependency Injection

A situation came up where I needed to select elements based on dependency injection. The elements were portions of a larger bitmap that were being used as tiles in a 2D graphics engine. Selection might be sequential, random, fixed, etc., but needed to be hidden from downstream processes. In particular, I needed to inject not the enumerators themselves, but enumerator factories.

At first I was going to use a custom interface. After some thought, however, I decided that the .NET IEnumerator<> interface fit the bill nicely. Technically an enumeration is some kind of ordered or unordered sequence from a collection. But a randomized sequence fits that bill, and it’s not too much of stretch to think of an infinitely looping sequence as an enumerator. (For example, think of the original collection as specifying the set of allowable items of an infinite sequence.)

So I came up the following helper functions:
static IEnumerator<TOutput> MakeEnumerator <TInput,TOutput,TState> (
TInput inputIn,
TState stateIn,
Func<TInput,TState,TState> funcMoveNext,
Func<TInput,TState,bool> funcMovedNextOk,
Func<TInput,TState,TOutput> funcCurrent)
{
while (true)
{
stateIn = funcMoveNext(inputIn,stateIn);

if (!funcMovedNextOk (inputIn,stateIn))
break;

yield return funcCurrent(inputIn,stateIn);
}
}


static Func<TInput,IEnumerator<TOutput>> MakeEnumeratorFunc <TInput,TOutput,TState> (
TState stateIn,
Func<TInput,TState,TState> funcMoveNext,
Func<TInput,TState,bool> funcMovedNextOk,
Func<TInput,TState,TOutput> funcCurrent)
{
return
(i)=> (
MakeEnumerator(
i,
stateIn,
funcMoveNext,
funcMovedNextOk,
funcCurrent));
}

The first helper is a generic enumerator builder that takes three functions and a state which control the enumeration. The functions transition from state to state, determine whether a transition has exhausted the enumerator, and select an enumerated item. (I separated the move next functionality and inverted its typical order because it makes things a lot more convenient.)

The second helper uses this first helper to build an enumerator factory function.

Below shows how this could be used to build an enumerator factory for canonical list enumeration. (You wouldn’t want to use these functions for this in a typical scenario; the traditional way would suffice there. They are mainly useful in dependency injection situations.)

Func<List<int>,IEnumerator<int>> xMakeEnumeratorFunc =
MakeEnumeratorFunc<List<int>,int,int>(
-1,
(i,s)=>(s+1),
(i,s)=>(s<i.Count),
(i,s)=>(i[s]));

List<int> xList = new List<int>() { 1, 3, 5, 7 };

IEnumerator<int> xEnumerator = xMakeEnumeratorFunc(xList);

// Inject xEnumerator here.

Fun, func, function!

(Tomorrow: I find a situation where a tradition boolean MoveNext is superior and post the overloaded functions.)

-Neil

Thursday, June 11, 2009

Enumerating Bits

OK, so the enumerating the set of subsets of non-zero bits is not a common task. But what about enumerating the set of non-zero bits in an integer? That’s something that tends to happen at least one or twice in any large project. Here’s how that can be done use a related function.

Given an integer (i), the least significant non-zero bit (b) can be found using this equation:

b = (i & -i)

(This is discussed as equation (37) in Donald Knuth’s The Art of Computer Programming, Volume 4, pre-fascicle 1A, page 8.)

It is easy to turn this into a loop which enumerates the bits in an integer:
while (xInteger>0)
{
int xBit = (xInteger & -xInteger);
xInteger &= ~xBit;
// Do something with xBit here.
}

(This is probably a case where one wouldn’t want to use a generic “yield return” enumerator, since if one is working at this level of detail, efficiency is probably the main concern.)

This can also be made to work in C# with unsigned integers by using various types of casting. But if efficiency is paramount, pay attention to the generated MSIL, since casting at some points generates more efficient code than does casting at other points.

Tests in release mode show that this construct is nearly four times faster in C# (.NET 3.5 version) than is shifting! But it looks arcane at first glance, so be sure to document the code well.

Tuesday, June 9, 2009

Power Set of a Bitmask

Here’s a cute trick for enumerating the power set of an integer bitmask. It’s based on equation (84) in Donald Knuth’s The Art of Computer Programming, Volume 4, pre-fascicle 1A, page 18, available in an "alpha test" version at:

http://www-cs-faculty.stanford.edu/~knuth/taocp.html

The idea is that, given a subset (x) of a mask (M) the next largest lexicographic subset (x') is:

x’ = (x – M) & M

Combined with the C# "yield return" statement, this allows a simple enumeration of the power set of a mask. You simply seed the subset with zero, and iterate until it is once again zero.

public static IEnumerable<int> PowerSet (
int maskIn)
{
int xSet = 0;

do
{
yield return xSet;
xSet = (xSet - maskIn) & maskIn;
}
while (xSet!=0);
}

For example, calling PowerSet(0x19) returns an enumerator which yields (in binary):

00000
00001
01000
01001
10000
10001
11000
11001


I can’t think of a specific use for it right off hand, but if a project uses enough bit manipulation, I’m sure something would arise.

Code Generator Oddity

The following is a exerpted example of my implementation of a well-known permutation algorithm. Note the code generation oddity flagged by the comment. This occurs in .NET 3.5 and Visual C# 2008. I leave the solution to the mystery to readers who like to disassemble and read MSIL, and think about what the JIT compiler may do to it.

protected static void Permute <TDatum> (
int beginIn,
int endIn,
TDatum[] dataIn,
Action<TDatum[]> dataActionIn)
where TDatum : IComparable
{
TDatum xDatumBegin;

if ((endIn-beginIn)<=1)
{
dataActionIn(dataIn);
}
else
{
Permute(
beginIn+1,
endIn,
dataIn,
dataActionIn);

for (int i=beginIn+1; i<endIn; i++)
{
xDatumBegin = dataIn[beginIn];

dataIn[beginIn] = dataIn[i];
dataIn[i] = xDatumBegin;

Permute(
beginIn+1,
endIn,
dataIn,
dataActionIn);

// Believe it or not, the compiler/loader
// will optimize the first block below
// to be almost 10% faster than the second.

#if thisIsFasterInDotNet
xDatumBegin = dataIn[beginIn];
dataIn[beginIn] = dataIn[i];
dataIn[i] = xDatumBegin;
#else
dataIn[i] = dataIn[beginIn];
dataIn[beginIn] = xDatumBegin;
#endif
}
}
}

Sunday, May 24, 2009

Zen Dream

Here’s something I once posted in a newsgroup.

Last night, I was practicing with some water-colors and I painted a series of concentric black and white circles, kind of like an archery target. Later, while I was asleep, I dreamt I was in a store. I saw that there were bows and arrows for sale, and I realized I had a consuming desire to practice archery. I picked out a bow, but I couldn’t find any arrows. Then I realized that they were haphazardly scattered about the floor, intermixed with long-handled paintbrushes. The arrows were missing feathers, and then other difficulties began to intervene, until I despaired of ever putting to together a decent archery set.

Then I woke up and realized I wasn’t interested in archery at all; I wanted to paint.

I had intended to end this story with the Zen saying "The skilled archer does not aim for the center of the target,” but I wanted to look it up in Yahoo to see if I could find the original reference. The first Yahoo hit I found was a newsgroup thread where I had quoted it earlier without reference. And if that's not some kind of koan, I don't know what is.

Monday, April 27, 2009

LINQ

It would not take even a Dr. Watson to notice that this blog has been idle for over a year. It might, however, take a Sherlock Holmes to discern the reason why. So I will sum it up with a word:

LINQ

Shortly after the last post, I began playing around with the new version of Microsoft Visual Studio, which included LINQ and all the new lambda programming goodies. I realized they made obsolete many of the issues I had discussed in the previous entry.

Concurrently, I decided to port a professional expert system engine I wrote and maintain to the new version of Visual Studio. It was written mainly in C++, with .NET interface code in C#. As I went along, I found myself thinking: “Perhaps I should just re-write the whole engine from scratch, using the newest C# technology.”

And so I did. And interspersed with other projects, etc., it took the better part of nine months to complete the engine, and another couple of months to work out the kinks and get it hooked up to the external components (UI, etc.). It was a lot of fun, but it did interfere with my blogging, to say the least.

In retrospect, it was a good decision. I learned the new lambda elements of C# in a way that would have been tough using a less whole-hearted approach. I also learned possibly more than I ever wanted to know about C# generics, lol. I want to share some of the things I discovered in subsequent posts in this blog, but for now I’ll just share what I consider the most important discovery:

Every programmer, it seems, hates exception handling, and I am no exception. So, when I started the re-write, I decided that I would, for once in my exception handling life, be good and pay attention to it from the ground up. So I started my re-write by crafting a set of classes to let me handle and pass exceptions and returns. They were not intended to replace the existing .NET exception handling, but rather to work hand in glove with it. Also, I began a discipline of handing errors and exceptions fully and correctly in the code at the exact moment I was writing the code. No more “I’ll save error handling for a rainy day.” It took a few weeks, but it stuck; it’s now a habit and I don’t fear error handling any longer.

Best programming discovery I ever made.

Thursday, March 20, 2008

Hierarchical vs. Relational

Some Thoughts About Hierarchical vs. Relational Representation
Part 1 – Rationale

As a rule of thumb, I like to design things so that each instance has three possible representations: in-memory object, hierarchical (e.g. XML), and relational. This tends to work out well because these are the three media of exchange in most computer architecture. Thus, in-memory for quick manipulation, hierarchical for static storage and communication via remoting or clipboard, and relational for dynamic storage.

This tends to work seamlessly except in one particular area: referenced objects (i.e. indexed objects in relational systems). Which is unfortunate, because referenced objects are a key paradigm in most computer languages and are the backbone of relational databases. This problem of coordinating referenced objects comes up in virtually every large program or code library, from e-commerce databases, to 3D graphics systems, to spreadsheets, etc.

I’ve tried several generic solutions to this problem. Most worked, but most became unwieldy as the code grew and special cases were considered. Because of this, I’ve decided to accept the fact that generic solutions here are difficult, and decided that instead, hope lies in the design patterns approach.

So, over the course of the next few blog entries, I will be presenting a series of design patterns aimed at tackling this problem. I don’t presume to think that any of these techniques are novel. The point is to arrange a series of rules-of-thumb and ad-hoc solutions into a more coherent set of design patterns.

-Neil

Saturday, January 12, 2008

Pine Board is Flawed

The pine board I was planning on using to make my first goban turned out to be irredeemably flawed on the bottom side. So I guess it’s back the attic floor with that one, and I’ll start with trying to make a goban from cherry! Maybe the value of the wood will drive me to do a good job, lol.

Wednesday, January 9, 2008

Opening Game Study


One thing I’ve noticed in my play against SmartGo is that my closed moyo tend to develop too early. So, although I securely capture some area, I allow SmartGo to capture large segments of the remaining board and so I get crushed.

My game is too “chunky” and lacks the “integrated” look one sees in most games.

At first I wondered whether this was because of the computer style of play vs. a human style of play; was I learning bad habits? However, I decided it must be because I was not fully developing the opening game before proceeding to closed moyo.

To that end (or beginning, lol), I bought “In the Beginning” by Ikuro Ishigure. I have to say that with just one day of reading, it has solved a lot of the problems I was having with the opening. The example here, though riddled with mistakes and lacking good joseki, does show more of an integrated pattern. And, though I got stomped in mid game, I did do significantly better through the opening game than I have been (based on computer analysis of the game).

-Neil

p.s. And I retrieved the pine board for goban number 1 from the attic flooring (yes, I did replace it with other boards, lol). I still need to mark it for size and decide on how to cut it for minimal warping.

Sunday, December 30, 2007

Goban R&D

Scrounging about the house and yard, I have located sufficient wood for three gobans:

One in 3/4" furniture-grade pine with nice grain and figurings. (I can possibly double it to 1.5", depending on knot holes.)

One in 3/4" high-grade cherry.

One in 2" high-grade cherry! (If I sacrifice some turning stock, which I'm loathe to do.) If I decide to use this, there will also be enough left over to make legs for it as a thin floor board.

I think the cherry boards, though darker than traditional boards, would look awesome with Yunzi jade-luster stones.

So I will start with the pine and work my way up, teaching myself the process as I go.

Pictures to follow, I hope.

-Neil

Saturday, December 29, 2007

My Best Game to Date Against SmartGo


This is my best game to date against SmartGo.

-Neil

Friday, December 28, 2007

Learning to Play Go

My first experience of Go was in high school in Hawaii. My social studies teacher was of Hawaiian/Japanese ancestry and she kept a Go set in the classroom. It was a really large, heavy floor goban and a set of stones that (if memory serves) were of some really nice intermediate grade material like marble. I seem to remember the goban as having incised lines, but I may be mistaken about that. Unfortunately, Go was not in the revival that it now experiences, so none of us took the opportunity to learn how to play.

Later in life, I decided I wanted to learn to play, but I kept putting it off. I don’t know exactly why I chose this time in my life to start playing Go, but I think it has a lot to do with my interest in the aesthetic of wabi-sabi. Of all the games I’ve encountered, Go seems to best embody the concept of wabi-sabi. This is certainly true of the equipment, but it is also true of the game itself.

About a six weeks ago, I decided to take the plunge. Being a computer programmer (and living in a very small town), it was natural that I should decide to use my computer to help me learn. So I made a promise to myself: “When I can learn to beat Igowin freeware, I’ll buy a nice software learning package.” It took about two weeks to beat Igowin, and – after looking around – I decided to try the 15-day trial of SmartGo. After 15 days with SmartGo, I decided that I liked it enough to pay and register it, so I did. It’s not perfect, but it seems to be a great learning tool and I am enjoying it.

My next goal is to beat SmartGo at least once. When I can do that, I’ve promised myself, I will buy a nice goban and some stones. In honor of my high school memory of Go, I have decided on a Japanese size goban and biconvex stones in the size 33 range.

Also, as part of my pursuit of wabi-sabi, I have decided to make my own goban someday. It may be a while, though, since I want to wait for just the right piece of lumber. I’m not sure running down to the local “wood-r-us” store and picking up lumber by the board-foot will give me the aesthetic I desire, lol. I want the goban to mean something to me as a work of art and a personal process. In art and craft, as in Go, the first and last moyos to be claimed lie within. As the Zen saying goes: "The skilled archer aims not at the target but at himself."

-Neil