Everybody loves a puzzle

A few months back Zee Spencer started think­ing about using evo­lu­tion­ary algo­rithms of var­i­ous sorts (notably GP) to solve Sudoku puz­zles—and more par­tic­u­larly to evolve solvers.

Inter­est­ing idea, not least because Sudoku solv­ing is a “solved prob­lem”, and noth­ing sets me off like one of those. There are well-known constraint-satisfaction meth­ods for con­struct­ing and solv­ing Sudoku grids; there are branch-and-bound and inte­ger pro­gram­ming approaches; you can even cre­ate, solve and type­set Sudoku grids by just typ­ing a lit­tle LaTeX code. And of course Peter Norvig has shown us all how to do it in his excel­lent and clear ped­a­gogic essay.

But of course all of those approaches make sense. Which is to say they’re ele­gant and no doubt ever so effi­cient and ratio­nal, but… well, they’re bor­ing, for lack of a bet­ter term.

Zee and I paired a few months back on a pre­lim­i­nary exper­i­ment he’d designed, in which he was evolv­ing solu­tions to fixed Sudoku puz­zles. And some­thing he said reminded me of an old unex­plored note­book ques­tion regard­ing constraint-satisfaction puz­zles gen­er­ally, which I brought up. This week I’m in Cleve­land work­ing with him on his inter­pre­ta­tion of that approach.

Cel­lu­lar Sudoku

All the extant Sudoku solver algo­rithms I’m aware of rely on what you might call “ser­ial atten­tion” and a tra­di­tional dynamic pro­gram­ming archi­tec­ture. That is, they scan over the ini­tial grid in some way look­ing for any of a num­ber of pat­terns: a block or row or col­umn that has almost every­thing filled in, or a cell where two or three con­straints over­lap to make a num­ber choice cer­tain, and they fill those num­bers in and start look­ing at the con­se­quences. The fancy ones keep a lit­tle “stack” of what-if explo­rations in mind, look­ing not merely at the currently-obvious constraint-overlaps but also check­ing for con­flicts and effects two or more steps into “the future”. This is in some sense the way many peo­ple actu­ally work Sudoku: a cycle of scan­ning for pat­terns, mak­ing judi­cious asser­tions, and maybe back­ing out if those asser­tions are “tricky” (as they can be in dif­fi­cult puz­zle exam­ples). And — at least in my case — prob­a­bly there’s some guessing.

Very nice. We’re not doing that.

In this exper­i­ment we’re look­ing for dis­trib­uted algo­rithms, a lot more like cel­lu­lar automata rules, that simul­ta­ne­ously update the choices avail­able to every cell in the Sudoku grid accord­ing to an (undis­cov­ered) deter­min­is­tic rule.

Here’s the way our hypo­thet­i­cal alien cel­lu­lar fel­lows will “solve” a given puzzle:

  1. Every cell in the grid is assigned a choice vector, which indi­cates which of the avail­able dig­its (1 – 4 for small Sudoku, 1 – 9 for stan­dard grids, and so on) that given cell might be at any given instant. The vec­tors aren’t prob­a­bilis­tic, just Boolean val­ues indi­cat­ing whether a cell could take a given value. If I rep­re­sent these Booleans with 1 and 0 for brevity, then for exam­ple in a 9x9 grid the ini­tial choice vector for any empty cell will be 111111111, and if the cell is a known hint (say a 5) the choice vector is 000010000—that is, that given cell’s choices are lim­ited to being 5.
  2. An Answer is a script of any num­ber of lines, each line con­tain­ing exactly one command. Com­mands have two parts: an argument and an operator.
  3. The argument is a string that refers to the rel­a­tive posi­tion of some other cell within the Sudoku grid: left, right, up, down, and also clockwise (cw) and counterclockwise (ccw). A cell’s left neigh­bor is the cell in the same row, one step to the left, mod­ulo the grid width; that is, the left neigh­bor of a cell in the left col­umn is the cell in the same row on the right col­umn. Sim­i­lar toroidal con­di­tions apply to right, up and down. The clockwise neigh­bor of any cell in the grid is its pre­ced­ing neigh­bor within its block, num­ber­ing in top-left-to-lower-right posi­tional order, row-first. So for exam­ple, in a stan­dard 3x3 block within a 9x9 Sudoku puz­zle, the cw neigh­bor of the cell in the upper right cor­ner is the left­most cell in the next row. The cw neigh­bor of the cell in the lower right cor­ner is the first block in the upper left, as well.
  4. The operator rep­re­sents a bit­wise boolean oper­a­tion to be car­ried out between the choice vector of the cell in ques­tion and that of the indi­cated argument cell. For exam­ple the com­mand "left and" applied to a given cell in the grid will replace that cell’s choice vector with the result of apply­ing bit­wise AND to its cur­rent choice vector and that of its left neighbor.
  5. For each line in an Answer, the choice vector of every cell in the grid is syn­chro­nously updated based on the cur­rent val­ues, start­ing from the ini­tial setup.
  6. After the last com­mand in the Answer has been applied, the result­ing grid is inter­ro­gated. That is, every cell is sent a decide! mes­sage, and emits (with uni­form prob­a­bil­ity) one of the choices encoded in its final choice vector. Cells that have ended up with no remain­ing choices emit a ? or 0 answer, indi­cat­ing they’re unable to respond.

Need­less to say by this time, this is an exploratory project, not an “opti­miza­tion” prob­lem. It’s not a case of “find the most effi­cient algo­rithm to do that”, but rather “is it even fea­si­ble that this might get closer to a solu­tion”? Our sus­pi­cion is that it might, but aside from a bit of hand-wavy dis­cus­sion of “infor­ma­tion prop­a­gat­ing across the grid” we have no frack­ing idea how a general-purpose Sudoku solver might work, if it can.

We’ll see.

In the mean­time, you might already sense a few places where this scheme can be relaxed or expanded. Yes, we thought about prob­a­bil­ity vec­tors instead of choice vec­tors. Yes, we’ll start with a sim­ple suite of operators like and, or, not, but we could get fancy with all 16 pos­si­ble binary oper­a­tors, or spread out into mul­ti­ple argu­ments. Yes, we’re start­ing with a local neigh­bor­hood around each cell to begin with, but we could let the argument of any com­mand be a phrase of con­sec­u­tive moves like "left up left ccw". We could include access to the past state of a cell in the neigh­bor­hood def­i­n­i­tion as well. We could apply dif­fer­ent rules to dif­fer­ent cells at each time-step.

We have no clear idea what might hap­pen until we give it a shot. Which will prob­a­bly be the next thing we talk about.

How do we know what’s hap­pen­ing, and whether we think it’s good or bad?

Pizza Eating Strategies, Part 2

In the pre­vi­ous episode, I spent a few min­utes jot­ting down some sto­ries that describe what I’m inter­ested in learn­ing in this project: I’m using GP to develop play­ers of Peter Winkler’s “Pizza Eat­ing Game”, and the algo­rith­mic part of those GP Answers will use a novel archi­tec­ture called Tag Space Machines from Lee Spec­tor. And as a kata for myself (and a bit of a tuto­r­ial for the occa­sional per­son I encounter who hasn’t done test-driven design before) I’ll be using rig­or­ous BDD, record­ing all the lit­tle messy details here.

So. I think I’ll start with some low-hanging fruit, not least because I’m wrestling with learn­ing a new text edi­tor, and try­ing to get all the fid­dly bits hooked up is prov­ing chal­leng­ing. So I think I’ll build a Pizza class first.

Look­ing over the sto­ries, I’m going to assume the pizza is just some kind of wrap­per around an Array of slice sizes, with some fancy meth­ods that per­mit initialization/reset and “eat­ing”. Let’s start with initialization/reset.

# pizza.feature
Feature: Pizza

  Background:
    Given I have a new pizza

  Scenario: pizza slicing
    Given a list of slice sizes [1,0,7,9,3,12,33,0,0,0,2.88,2.12]
    When I slice the pizza
    Then there should be 12 slices
    And the pizza should weigh 70
    And the pizza should be whole

The pizza is “whole” because Alice hasn’t eaten the first slice, and it’s going to be treated as an array with “wrap­ping” bound­aries by her yum­mi­ness function(s).

Cucum­ber reports that the first pend­ing spec is Given I have a new pizza, so I cre­ate the appro­pri­ate step definition.

# pizza_steps.rb
Given /^I have a new pizza$/ do
  @pizza = Pizza.new
end

This fails, since I have no Pizza class.

#pizza.rb
class Pizza
end

And it passes. The next pend­ing step is Given a list of slice sizes [1,0,7,9,3,12,33,0,0,0,2.88,2.12].

# pizza_steps.rb
Given /^a list of slice sizes (\[.+\])$/ do |slices|
  @slice_list = eval(slices)
end

That passes, since it’s not invok­ing the library at all, just set­ting a vari­able within the scope of the test. When I slice the pizza is next.

# pizza_steps.rb
When /^I slice the pizza$/ do
  @pizza.slice(@slice_list)
end

This calls for a tiny bit more struc­ture in the Pizza class, but not too much.

#pizza.rb
class Pizza
  attr_accessor :slices

  def slice(size_array)
    @slices = size_array
  end
end

Next pend­ing step is Then there should be 12 slices.

# pizza_steps.rb
Then /^there should be (\d+) slices$/ do |count|
  @pizza.slices.length.should == count.to_i
end

Which passes already. And the pizza should weigh 70

# pizza_steps.rb
Then /^the pizza should weigh (\d+)$/ do |weight|
  @pizza.weight.should == weight.to_f
end

That calls for another bit if Pizza struc­ture. But is it an attribute, or a method? I’m think­ing method; the slice weight array itself is already stored, and I assume the play­ers will have some sort of #eat(left_slice) method that mod­i­fies that Array directly on each turn. I’ll return the sum of all slice values.

#pizza.rb
class Pizza
...
  def weight
    @slices.inject(0) {|sum,w| sum+w}
  end
end

Last step is And the pizza should be whole.

# pizza_steps.rb
Then /^the pizza should be whole$/ do
  @pizza.should be_whole
end

Inter­est­ing ques­tion: when is Pizza#whole? going to be true? As soon as my pizza is first sliced, surely. But maybe also when it’s ini­tial­ized (“baked”)? Then again, the ini­tial­iza­tion method (which I haven’t needed yet) might be more use­ful to set up partially-eaten un-whole piz­zas for test­ing or train­ing. I’m all for postponing.

#pizza.rb
class Pizza
  attr_accessor :whole
  ...
  def slice(size_array)
    @slices = size_array
    @whole = true
  end

  def whole?
    whole
  end
end

All steps pass.

So Alice and Bob will be eat­ing par­tic­u­lar ele­ments of Pizza#slices. And the sto­ries make it clear there are two modes: the first slice, and then the left_slice vs right_slice. I sup­pose I should start with the first slice. In addi­tion to mak­ing the pizza no longer whole?, this ought to “unwrap” the cir­cle to cre­ate the left_slice and right_slice linearity.

# pizza.feature
...
Scenario: eating the first slice unfolds the circle
  Given the pizza is sliced into [1,2,3,4,5,6,7,8]
  When I take out piece 6
  Then the pizza should not be whole
  And the left slice should weigh 7
  And the right slice should weigh 5

I’ve made a new step here.

# pizza_steps.rb
Given /^the pizza is sliced into (\[.+\])$/ do |slices|
  @pizza.slice eval(slices)
end

That passes already, from work done in the pre­vi­ous sce­nario. Now When I take out piece 6 is the next pend­ing step.

# pizza_steps.rb
When /^I take out piece (\d+)$/ do |which|
  @pizza.eat_first_slice(which.to_i-1)
end

I need to add Pizza#eat_first_slice to the library, though this step doesn’t actu­ally call for it to do anything.

#pizza.rb
class Pizza
...
  def eat_first_slice(which)
  end
...

Then the pizza should not be whole

# pizza_steps.rb
Then /^the pizza should not be whole$/ do
  @pizza.should_not be_whole
end

Seems a sim­ple thing to make that pass.

#pizza.rb
class Pizza
...
  def eat_first_slice(which)
    @whole = false
  end
...

And the left slice should weigh 7. Basi­cally the “left” slice is the stub-end of the unwrapped cir­cle I get when I snip out the eaten piece, and the “right” slice is the piece remain­ing to its left. First the steps I need (both at once, just because the sym­me­try is so clear):

# pizza_steps.rb
Then /^the left slice should weigh (\d+)$/ do |weight|
  @pizza.left_slice.should == weight.to_f
end

Then /^the right slice should weigh (\d+)$/ do |weight|
  @pizza.right_slice.should == weight.to_f
end

And the library code to make these pass. I fid­dle a bit with the bounds-checking, but I think this will do.

#pizza.rb
class Pizza
...
  def eat_first_slice(which)
    open_circle = @slices[which+1..-1] + @slices[0...which]
    @slices = open_circle
    @whole = false
  end
...

And that seems to have done the trick.

Pizza Eating Strategies, part 1

This is the first in a (hope­fully short) series in which I’m prac­tic­ing my BDD in a Ruby-based exper­i­ment where I want:

Some sto­ries

I’m start­ing from an empty can­vas: I’ll need to think about the rep­re­sen­ta­tion of the prob­lem domain, not just the archi­tec­ture of the TSM answers and GP sys­tem. I spend some time read­ing over the arXiv paper that sparked my curios­ity and Lee’s descrip­tion of TSMs. I come up with a few sto­ries, and some notes as I jot them down.

Eat­ing the first piece isn’t like later pieces:
Before the first game move (when the pizza is whole), Alice can pick any piece at all. After she does, Bob and Alice can only pick one of the two neigh­bors of the grow­ing gap.

As I men­tioned when I launched this side-project, I’m think­ing about the way these agents play the game as being some kind of “field gen­er­a­tion” process. Their cal­cu­la­tions impose some kind of “yum­mi­ness field” on the (cur­rent) set of pizza slices, and then when that cal­cu­la­tion is done they eat the slice with the high­est yum­mi­ness value. Fur­ther, I think I want to try a local process, a sin­gle cal­cu­la­tion con­ducted with “this piece of pizza” as the focus, with ref­er­ences to the traits of other pieces being spa­tially relative.

The inter­est­ing thing of course is the topo­log­i­cal dif­fer­ence between the whole pizza and the partially-eaten one. The whole is cir­cu­lar, with “left” and “right” being well-defined all the way around. But once a piece is eaten, the thing becomes “lin­ear”, and the only choice before the agents is between the two “end” pieces of that ordered set of pieces.

In deter­min­ing the “yum­mi­ness field”, this feels like it might be impor­tant. But it’s also lim­it­ing the set of agent behav­iors: the first move is some kind of eat_first_piece, and all sub­se­quent moves are eat_left_piece or eat_right_piece.

Pizza slices have weights:
every pizza slice has a numer­i­cal weight, which can be 0

This seems pretty straight­for­ward: the goal of the play­ers is to con­sume a max­i­mum pro­por­tion of the total pizza, and “weight” seems as good as any­thing for tal­ly­ing this up. Bet­ter than “crust”, surely… though of course they will sort in the same order.

Agent decision-making:
Agents have two yumminess func­tions, one for pick­ing the first piece, and the other for later moves. The yumminess func­tion is invoked with a ref­er­ence to a spe­cific index of the cur­rent pizza, and returns a float value. One yum­mi­ness value is cal­cu­lated (in par­al­lel) for each slice.

I’m think­ing the basic yumminess cal­cu­la­tions might include some boolean logic and arith­metic; we’ll work our way up from there as needed. The index of a slice is the input, but the algo­rithm can have instruc­tions to inter­ro­gate the attrib­utes of slices, things like its index, its weight, that sort of thing. Heck, maybe the yumminess of one slice can refer to the yumminess of its neigh­bors… but that may end up being complicated.

Because of the clear topo­log­i­cal (and strate­gic) dif­fer­ence between the first slice and the later ones, I’m will­ing to start with a lit­tle extra com­plex­ity and have two sep­a­rate func­tions. This seems to imply I’m think­ing that every agent can play “Alice” or “Bob” roles in what­ever scor­ing tour­na­ment I come up with. Why not? Let’s see what happens.

Yum­mi­ness ties are bro­ken randomly:
When the max­i­mum yumminess is assigned to mul­ti­ple avail­able slices, one is picked at ran­dom with uni­form probability.

In other words: when in doubt, flip a coin or draw straws.

Yum­mi­ness func­tions are Tag Space Machines:
One for each. The appro­pri­ate ref­er­ences to exter­nal val­ues are set up based on the slice index, the TSM is run, and then the top­most [num­ber] is emit­ted as the output.

I’m not sure which “num­ber” this might be. Do I need to dif­fer­en­ti­ate between int and float? Really? I don’t have a lot of infor­ma­tion yet about what the TSM lan­guage is going to be like. Maybe this will become more appar­ent as I work on that.

TSM math instructions:
The TSM should rec­og­nize float val­ues, and have basic math instruc­tions: add, subtract, divide, multiply, min, max, maybe a few more.

Do I really need integer as a type? After all, the notion of an “index” in the tag space itself depends on the math­e­mat­i­cal “floor” func­tion. Why not use floats for indices as well, tak­ing the floor (or ceil­ing) as needed? Maybe this is just reals, and we’ll skip the dif­fer­ence until we need it.

TSM pizza instructions:
The TSM should be able to get the index and weight of the slice on which it’s applied. It can use weight_of and index_of with a numeric argu­ment (pos­i­tive or neg­a­tive) to obtain val­ues of neigh­bor­ing slices.

I have an intu­ition this may not be enough. But we’ll see. It’s not that hard to imag­ine run­ning the cal­cu­la­tions for each slice in lock-step, and let­ting one TSM inter­ro­gate its neigh­bor­ing TSM’s state, like with real_of to copy over a real from a neigh­bor­ing slice’s stack into its own. But no need to over-design yet.

TSM log­i­cal instructions:
The TSM should have basic Boolean logi­cian func­tions: and, or, not, that sort of thing.

Makes sense, because we’ll have com­par­isons to make.…

TSM com­par­i­son instructions:
The TSM should have com­par­isons like less_than, greater_than, equal and so on for reals and any other types for which they make sense.

These will cre­ate bool outputs.

TSM dynam­ics:
When the TSM is acti­vated, it pops one item from its x stack; if it’s a con­stant it’s pushed to the appro­pri­ate stack, and if it’s an instruc­tion it exe­cutes that instruc­tion imme­di­ately. This con­tin­ues until the x stack is empty.

This is just the def­i­n­i­tion of how TSMs run. But it does raise the ques­tion (from expe­ri­ence): Will there ever be TSM “pro­grams” that don’t ter­mi­nate? Will I need a step counter, and some sort of dead­line? We’ll see, I guess.

TSM tag spaces:
The tag_space stack holds tag_space instances. TSM instruc­tions for stor­age and lookup exist, and refer to the top tag_space in the stack based on numeric index. Each tag_space is a key-value pair store, sorted by numeric key. Lookup is inex­act, return­ing the value for the small­est key larger than the search tag, or the first key of no key is larger. No value is returned if the tag_space is empty.

Feels as though I’ll need to cre­ate a sub­class of Ruby’s Hash for this, main­tain­ing the sort order and deal­ing with the inex­act lookup. Shouldn’t be too com­pli­cated, but will demand some care­ful checks.

TSM tag­ging instructions:
There are instruc­tions store, store_pair and lookup for writ­ing and read­ing from the top tag_space. (see update below)

Based on Lee’s descrip­tion, it sounds as though his ts_tag imaps arise some­how from the “genome” of a TSM: that is, they appear fully-formed in the x stack before we start run­ning the code. This feels strange but inten­tional, and so I’ve asked him if I’m miss­ing something.

In the mean­time, I’m more com­fort­able hav­ing instruc­tions that make those asso­ci­a­tions from argu­ments just like other instruc­tions would use, except that the argu­ments for store and store_pair come from the x stack rather than the typed stacks. For instance, I’m imag­in­ing store pulls a “tag key” from the reals stack, and the next item from the x stack, and stores the item as a value asso­ci­ated with that key in the top­most tag_space.

What am I missing?

Well, of course I’ve not defined any­thing about how these sup­posed pizza-eating experts are going to be scored, nor how many and what kind of pizza they’ll be asked to eat, or any of that. But it feels like enough to get started with, espe­cially as I’m wait­ing for Emma Tosch and Lee to help me out of the con­fus­ing bits.

In the mean­time, I’ll start on the pizza first….

Update (later that day):

After a cou­ple of clar­i­fi­ca­tions from Lee, I’ve got a bet­ter han­dle on how the tags and tag­ging instruc­tions should work.

TSM tag­ging instructions:
There are three kinds of what I’ll call macro instruc­tions: store_at(N), lookup_at(N) and store_pair_at(N), where (N) is a fixed floating-point num­ber, not an argu­ment. These numer­i­cal val­ues can (and prob­a­bly will) vary between instances of these instruc­tions, but not over the “life” of the indi­vid­ual instruc­tion instances.

So basi­cally what’s hap­pen­ing here is that the stor­age and retrieval of items in a tag_space always includes a par­tic­u­lar address, not a numeric argu­ment. This is a design deci­sion from Lee, and seems per­fectly valid to work with.

I think I can get away with a bit of abbre­vi­a­tion when writ­ing TSM code, and use >8.2 to indi­cate the macro instruc­tion store_at(8.2), use <-3.9 to indicate lookup_at(-3.9), and >>991.55 to indicate the macro store_pair_at(991.55).

Applying GP to Winkler’s Pizza Eating Game

(Code to be posted at github as I move forward)

A recent arXiv preprint enti­tled “How to eat 4/9 of a Pizza” caught my eye. It’s an inter­est­ing lit­tle answer to a chal­lenge from game the­ory (and geom­e­try, I sup­pose) posed by Peter Win­kler, who’s a con­stant source of inspiration.

Hun­gry, Hun­gry Alice & Bob

Sup­pose we have a cir­cu­lar pizza, already cut into wedge-shaped slices (from the cen­ter to the crust). These are extremely pre­cise slices, and in fact they can have “0 width”, or some small epsilon close enough to 0 to be entertaining.

There are two hun­gry play­ers, Alice and Bob. Alice chooses a piece to eat first. Bob and Alice alter­nate eat­ing pieces of pizza after that, until it’s gone, but they must both always choose one of the two pieces adja­cent to the grow­ing gap.

The arXiv preprint describes a strat­egy by which Alice can eat at least 4/9 of the pizza, regard­less of the slices or how smart Bob’s strat­egy is. She may be able to eat more than 4/9, depend­ing on the slices and Bob’s mis­takes. And of course she’s only guar­an­teed to get that much if she’s fol­low­ing a prov­ably opti­mal strategy.

Agents: Rep­re­sent

See, I’ve been writ­ing this book, and there are a num­ber of lit­tle side-projects like this one that have come up, but prob­a­bly won’t make the cut for the final edit. The six large-scale projects I’m work­ing on keep me busy enough, but at the same time I’m try­ing to pol­ish and refine my “sim­pli­fied” approach to GP project management.

So this is me think­ing in Ruby about one of those lit­tle side-projects.

I’ve also recently been watch­ing Lee Spector’s expla­na­tions of Tag Space Machines unfold. Tag Space Machines (TSMs) are a rep­re­sen­ta­tion scheme for GP lan­guages he’s imple­mented in his lab’s work. I think I may work with TSMs here.

Pizza

The pizza is mod­eled as an Array of “slice weights”. An uneaten pizza is con­sid­ered to be cir­cu­lar, and the first player (“Alice”) can eat any piece she wants. Eat­ing the first piece “unfolds” the pizza, restruc­tur­ing the array so that the start and end val­ues are the pieces on the “right” and “left” of the gap. After that, play­ers can only choose to eat one of the two end pieces.

In other words, the player agents have only three actions (besides “plan­ning”): eat_first_piece, eat_left_piece and eat_right_piece. And they don’t even get free choice among those three, since the first is mutu­ally exclu­sive with the last two.

How to think about eat­ing pizza

The big design ques­tion here is, how do play­ers think about the pizza?

A slightly more tra­di­tional approach might have them han­dling arrays and iter­at­ing and stuff. But hav­ing mod­eled game-play before, I know there’s also more dis­trib­uted (if less intu­itive) approach I’m won­der­ing about here: since there are so few choices in the game, what if a “think­ing” or “strat­egy” were a scalar field cal­cu­lated locally for each of the pizza slices indi­vid­u­ally, and which slice is cho­sen by a given agent was deter­mined by the highest-scoring pizza slice accord­ing to that agent’s slice field algorithm?

In other words, sup­pose Alice has eat_first_slice field def­i­n­i­tion that is a func­tion applied to each ele­ment of the pizza slice array (treat­ing it as cir­cu­lar). The argu­ments are the weight of “this” slice, and weights and dis­tances of slices to the rel­a­tive left and right of “this” slice, and the num­ber of slices over­all. Maybe her eat_first_slice field is the weight of a slice plus the aver­age weight of its six neigh­bors on either side.

Alice’s first turn begins with her cal­cu­la­tion of this field for the given pizza, and then she selects the highest-scoring slice. If Bob and Alice then have a (pos­si­bly dif­fer­ent) func­tion for scor­ing the slices of the non-circular pizza, the same dynam­ics can apply to their sub­se­quent choices of left_slice over right_slice. In cases of ties, we pick at random.

Might this approach work? I have no idea. It feels as though it has some flex­i­bil­ity. We’ll see.

I’ll post updates as I make progress.

Update

[cross-posted to Notional Slurry]

I real­ize I’ve turned quiet as far as the blogs are con­cerned. I’ve been work­ing on trans­lat­ing the draft con­tent for the Answer Fac­to­ries book into pub­lished man­u­script. Mark­down is lovely, but talk­ing in detail about the process of soft­ware devel­op­ment still requires an awful lot of cutting-and-pasting, it turns out….

I recently updated the pub­lished draft; if you’re behind, feel free to go update your copy now. New con­tent includes a descrip­tion of the iPad game Cargo-bot, and a detailed test-driven re-implementation of the game logic in an emu­la­tor we’ll use for GP in forth­com­ing chap­ters. I spent a lot of time on the test-driven devel­op­ment, so I’d like some feed­back if you’re willing.

Help me pick the programming language for the second project?

Over at the Google group I’m solic­it­ing advice on what pro­gram­ming lan­guage I should use to imple­ment the sec­ond project for the book.

Also: Do you pre­fer the blog or the Google group for this sort of thing?

One of the deep­est philo­soph­i­cal qualms I’ve had about the struc­ture of the book is the neces­sity to show code in some par­tic­u­lar pro­gram­ming lan­guage, with­out imply­ing that if an algo­rithm were writ­ten in some other lan­guage it would be “bet­ter” or “worse” or in any sense func­tion­ally dif­fer­ent. If I pick Ruby, things not only devolve into “Genetic Pro­gram­ming in Ruby” (which is mis­lead­ing), but Python and Clo­jure and J pro­gram­mers are left unable to fol­low along.

Tra­di­tion­ally com­puter sci­en­tists have use pseudocode as a solu­tion to this prob­lem, but to be blunt pseudocode sucks: the accept­abil­ity of runnable code should not be dri­ven by struc­tural fea­tures pseudocode enforces (loops, branches, argu­ments) but the behav­ior it exhibits. As far as I’m con­cerned it’s not only mis­lead­ing but dan­ger­ous to hand out pseudocode, if noth­ing else because I’ve watched peo­ple treat the text as if it were a form to fill out, replac­ing every line of the pseudocode with an “equiv­a­lent” line of code-in-some-language, expect­ing the result to run as intended.

Of course in a big chunk of the read­er­ship, those famil­iar with test-driven and behavior-driven devel­op­ment, tests do the trick hand­ily. But in the other big chunk of read­ers, that sen­si­bil­ity and suite of habits is miss­ing, and even alien.

So here’s what I decided: I’ll write code myself, and in the begin­ning project show all the code I write, but only in a behavior-driven way. The Cucum­ber tests will be there for read­ers to use (or kludge along with) in their own lan­guage of choice. I’ll be work­ing in Ruby for the first project because peo­ple who are com­fort­able with Ruby are the first audi­ence I hope to reach.

But there are six projects planned, and so I’d like to grad­u­ally set the explicit code aside, and come to rely more grad­u­ally on the Cucum­ber fea­tures and sto­ries, or per­haps “more generic” (?!) state­ments of accep­tance tests the reader’s libraries should pass.

So the pro­gram­ming lan­guage I use in the sec­ond project is up for grabs. Clo­jure? Python? Javascript? Objective-C? In any case it must be some­thing with a sta­ble and usable accep­tance test­ing frame­work on hand; I’m not sched­ul­ing any time to write my own test­ing libraries here.

The sec­ond project’s sub­ject mat­ter will either be “evolv­ing geo­met­ric algo­rithms and proofs” or “data-mining and stock-trading and related crap”. So any lan­guage I’ve listed will work fine, and per­haps a few oth­ers I could learn rel­a­tively eas­ily. (But not Java.)

Your input would be appreciated!

On sensibility

GECCO is one of the largest con­fer­ences in the field of evo­lu­tion­ary algo­rithms, and I’m told there are some­thing over 400 peo­ple attend­ing this year in sul­try Philadel­phia. The first two days are often the calmest, bro­ken up into a “mere” seven or eight simul­ta­ne­ous tracks, about equally work­shops where a half-dozen topic-specific papers are pre­sented and dis­cussed, and tuto­ri­als in which intro­duc­tory and advanced tech­niques are reviewed. Before the early starts, dur­ing the two-hour lunch break (if there is one), and after hours we par­tic­i­pants self-assort and chat and catch up, like any tech­ni­cal con­fer­ence I suppose.

It’s an inter­est­ing thing to watch from the inside. The social net­works, the cliques and com­po­nents form­ing and re-forming. I can’t help but feel I’m watch­ing turf wars on the ground: all of us old influ­encers with our var­i­ous Schools of Mar­tial Arts vying for atten­tion, revis­it­ing old scores and rem­i­nisc­ing about which thing hap­pened when, jok­ing about In the Old Days at the same time we eye the young bloods keenly and try to steer them towards or away from Right Thought and Practice.

This is a dilute field, if it’s a field at all. One or two peo­ple in each insti­tu­tion, with a couple-three grad­u­ate stu­dents each. In the old days, there was still a defen­sive air about it, like we used to hear at Com­plex Sys­tems research con­fer­ences. We’ve moved (a bit) past that stage of jus­ti­fy­ing the approach as such, con­vinced our­selves and our peers there’s some­thing use­ful to be done with “biased ran­dom guess­ing”, so now the tribes are split­ting along not-unexpected lines as they think about what they should seem like. Should this thing I’m doing sound like Oper­a­tions Research, clad in for­mal prov­able cor­rect­ness and rig­or­ous the­o­ret­i­cal jus­ti­fi­ca­tion? Should it sound like Arti­fi­cial Intel­li­gence, with agents believ­ing and intend­ing and desir­ing to move blocks and iden­tify spam? Should it be a form of gen­er­a­tive art, a way of inspir­ing and pro­vok­ing me to new works? Should we con­sol­i­date our resources, like the Machine Learn­ing peo­ple did, and start bench­mark­ing so we can “bet­ter com­pare” results, or build tools that make it “eas­ier” for “non-technical peo­ple” to “solve problems”?

And of course the lump­ing and split­ting goes on, as ever: But this is just another exam­ple of that, a spe­cial case. This is new (it must be, if you’re pre­sent­ing it); this is old (it must be, if you are to be given credit); that is this (it should be, if we’re to under­stand one another); this is not that — noth­ing is ever any­thing else. Where “this” and “that” are works, tech­niques, expe­ri­ences, guide­lines, rules, habits, terms.

Nobody talks about the com­mu­nity in which they work. Not this com­mu­nity of conference-goers, but the com­mu­nity of peo­ple who might some­day actu­ally want their can­cer cured, or their stocks traded. The aca­d­e­mic habits of the Cold War — deep resource depri­va­tion, the Arti­fi­cial Intel­li­gence par­a­digms, the ram­pant cul­ti­va­tion of Lone Genius as the one route to great­ness — they drive so many into their own work and away from help­ful col­lab­o­ra­tions. There are col­lab­o­ra­tions within the fam­i­lies (the MIT fam­ily, the Vir­ginia fam­ily, the Illi­nois fam­ily, the Stan­ford fam­ily, the Michi­gan fam­ily with its wide-ranging limbs), but still I never see peo­ple talk­ing about how a prob­lem becomes a project, nor how a “result” becomes a use­ful fur­ther­ing of some conversation.

There’s dis­cus­sion of sub­jec­tive expe­ri­ence, of course. Some nice ones. But even these lie within the bound­aries of the Tech­ni­cal Works: I was sur­prised to see it doing this; I tried X but even­tu­ally Y was better.

For whom?

What I’ve found so far is that my old col­leagues work as though pro­vid­ing self-contained soft­ware were of use to any­body. They talk as though pub­lish­ing self-contained repos­i­to­ries of data and algo­rithms were of use to any­body. They think, I’m afraid, that the places human beings inter­act with their work should be lim­ited to the pro­duc­tion of “require­ments” and the accep­tance of “results”.

They do not speak of human context.

I hope they get over it. I would like them to find some­thing out­side them­selves and their par­tic­u­lar School of Mar­tial Arts and their own turf that brings them together in a “track”. How do we cope with fear? With hubris? How does one work, when one is work­ing in ser­vice of some other person’s aim?

I have stan­dard ques­tions I ask in almost every talk I attend: Why do you ignore the other objec­tives? Why do you use that habit, that library? Why do you mea­sure that thing, and not the real thing you’re doing?

I don’t ask these ques­tions to find out their tech­ni­cal jus­ti­fi­ca­tion. I’m not quizzing them on how well they’ve learned to write a mul­ti­ob­jec­tive non-domination algo­rithm, or read and write from a data­base. I’m ask­ing them because I’m still wait­ing for one to say, “Because when we dis­cussed it with our col­leagues, the peo­ple whose ques­tion this is, they wanted to try this. It was best at the time. It was some­thing so we could deliver results and learn together.”

I want some­body to say, “The cus­tomer saw value in it.”

But so far I fear the “cus­tomer” is rep­re­sented in this work as a mere trades­man, or worse a “lay­man”. Some­body you help only after tak­ing their prob­lem away from them, Being Very Smart, and giv­ing the Right Answer back to them so they can use it.

Such a Water­fall world. So con­fi­dent, even in the face of hun­dreds of hours of talks dis­cussing why things are hard and com­pli­cated and slow.

These are excuses for fail­ing to deliver some­thing to a per­son who can use it. Of course they’re cul­tural excuses, Cold War excuses, Aca­d­e­mic excuses based on “sig­nif­i­cantly advanc­ing the field”. But they jus­tify a view in which work is yours, and prob­lems belong to other people.

Sketch of an “artificial scientist” project

One of the things you real­ize after a while is that projects drop into your lap faster than they can be com­pleted. Some sources of inspi­ra­tion are things you encounter all the time: your work (I know a lot about mol­e­c­u­lar design and phar­ma­ceu­ti­cal lead com­pound dis­cov­ery), your hob­bies (I know a lot about image recog­ni­tion and seg­men­ta­tion for OCR of dig­i­tized books), and things you see other folks doing and just want to try (I’ve enjoyed my years doing Sym­bolic Regres­sion because so many other peo­ple have paved the way, while leav­ing other paths less trav­eled and thus more interesting).

I’m find­ing that writ­ing the intro­duc­tory mate­r­ial for the book is dif­fi­cult. In fact I’ll prob­a­bly post­pone releas­ing the intro until more of the core guts are writ­ten. Mainly the intro­duc­tory mate­r­ial has been about that peren­nial ques­tion, “How do I find and pur­sue ideas?” My core argu­ment is that GP is use­ful for accel­er­at­ing the fruit­ful inves­ti­ga­tion of your ideas, but the chal­lenge for many folks is rec­og­niz­ing the heuris­tics I per­son­ally take for granted. Some of this means I’m revis­it­ing Polya’s How To Solve It: A New Aspect of Math­e­mat­i­cal Method, but I find that it’s not philo­soph­i­cally com­pat­i­ble with the agile stance I per­son­ally pre­fer, so I’m actu­ally find­ing Andrew Abbott’s Meth­ods of Dis­cov­ery: Heuris­tics for the Social Sci­ences more use­ful, not least because he sug­gests Aristotle’s four causes and Kant’s schema as inter­est­ing “kicks to the head”. And there’s Michalewicz and Fogel’s excel­lent How to Solve It: Mod­ern Heuris­tics, which goes in a more tech­ni­cal direc­tion (and closer to GP) tan Polya was able to do.

But I look over all that good advice, and I find it trou­bling. So I’m up in the air about it.

I decided more than a month back to change some­thing impor­tant in the book. I still think Learn­ing by Doing is cru­cial and impor­tant. But I can’t see a way to pro­vide accep­tance tests alone (with no pseudocode or worked-out exam­ples) in an enticing-enough way that pro­vokes rea­son­able responses from the read­ers. That is, I got a lot of push­back from poten­tial audi­ence mem­bers who don’t actu­ally know how to write their own code based on accep­tance tests.

Le sigh.

So I’m try­ing what Ron Jef­fries did in his Extreme Pro­gram­ming Adven­tures in C#: describ­ing what I am think­ing, what moti­vates me, what I actu­ally do, and as a result I hope to make the process itself more trans­par­ent, not just the exter­nally vis­i­ble steps. As Ron pointed out a few weeks back when we chat­ted about it, this smacks of arro­gance. Who am I to think other peo­ple care about the mis­takes I’m mak­ing, or want to be mis­led by watch­ing me do stuff I sub­se­quently undo? Just to prove I “learn some­thing” from it?

Them’s the breaks. The alter­na­tive would be the crap one already has: pseudocode pre­sented as if it were the one “right” way to do stuff, and the inclu­sion of idiomatic (or worse, generic) libraries that the reader should re-create them­selves for every project, not bor­row and re-use indis­crim­i­nately just because it hap­pened to be in a book. In other words, bet­ter sorry than unsafe.

So inspi­ra­tion is a thing I’ll set aside and talk about sub­jec­tively, not in terms of heuris­tics which (as Abbott points out in his excel­lent account) can quickly become fos­silized and rit­u­al­ized as though they were “cor­rect” instead of use­ful.

So I picked up a book

I seem to like math­e­mat­i­cal recre­ations. Just the other day I sketched a lit­tle game thing that some­body should pick up and run with. If it sits around long enough, maybe I’ll do it myself, but not until the book is far­ther along.

In the pile of inter­li­brary loans that I picked up the other day was a trea­sure trove in one vol­ume: Geo­met­ric Fold­ing Algo­rithms: Link­ages, Origami, Poly­he­dra. Now the math­e­mat­ics of origami and stuff is all mod­ern and weird and “advanced” to my gen­er­a­tion; most of the actual math­e­mat­i­cal results came after I grad­u­ated from Uni­ver­sity, and appeared in fancy eso­teric math­e­mat­ics jour­nals even then. But there’s a con­stant cho­rus in New Sci­en­tist and Sci­ence News and stuff about new results, and there’s this other thing I used to do when I was a struc­tural biol­o­gist that involves fold­ing and abstrac­tions of phys­i­cal real­ity sur­pris­ingly sim­i­lar to those in origami. Which is the Holy Grail of a multi-trillion dol­lar indus­try at the moment, by the way.

I’m try­ing to put my fin­ger on what it is about some books— Mar­tin Gardner’s or Cliff Pickover’s or Ivan Moscovitch’s, for exam­ple — that makes them so inspir­ing. Is it the den­sity of open ques­tions? A tone that makes you won­der before dis­clos­ing any­thing? Some­thing inher­ent in this semi-abstracted recre­ational game stuff that makes it clear how to write a sim­ple com­puter pro­gram but unclear how to solve a prob­lem? Some­thing about puz­zles? I have no idea.

At any rate, this one has that same stuff on it. It’s fun.

I picked it up from the stack this morn­ing, opened to a ran­dom page, and started read­ing about one-dimensional origami. Now this is a book that’s fram­ing new work in mod­el­ing phys­i­cal sys­tems like folded paper (and pro­teins) by set­ting up the math­e­mat­i­cal con­structs and abstrac­tions in a tra­di­tional way. But there’s a heuris­tic I find myself adding to the other handy “kicks to the head”, espe­cially use­ful for GP work: What would it take to build a soft­ware sys­tem that “did” this?

So let’s think about one-dimensional origami for a second.

Does it fold?

Before they even get very far in the for­mal math­e­mat­ics of paper-folding, Demaine and O’Rourke talk a bit about rep­re­sent­ing one-dimensional folded struc­tures. You know, the tra­di­tional nec­es­sary and suf­fi­cient con­di­tions for deter­min­ing whether a thing is what you call it or not. Those core con­cepts, the stuff hang­ing off the “triv­ial” parts of tra­di­tional sci­ence and engi­neer­ing that you often elide because you’re just defin­ing your terms, that’s where there’s often low-hanging fruit for GP projects.

I rec­om­mend a browse through the excel­lent book, or just peek at Erik Demaine’s lec­ture notes on the sub­ject. We’re talk­ing about what starts out as a line seg­ment, which we crease at cer­tain (arbi­trary) points, and then press flat so that it pro­duces a sort of accor­dioned stack of squig­gles. Think of a cross-section through a piece of folded paper.

Let’s use paper, for a minute, and just assume for now we are fold­ing it only in the ver­ti­cal direc­tion. Just to get a slightly more vis­ceral sense of it.

Plop a (big) sheet of paper down on the table in front of your mind’s eye for me, OK?

We can make “moun­tain” or “val­ley” folds. Think of a “val­ley” fold as tak­ing either the left or right edge of the paper and fold­ing it upwards and across towards the oppo­site; think of “moun­tain” folds as tuck­ing the right or left edge down under­neath the stack. You can make these moun­tain or val­ley folds any­where between the edges of the paper, and as long as the creases are par­al­lel with the left and right sides you’re mim­ic­k­ing one-dimensional fold­ing. Just peek at the end of the sheet to lose the extra dimension.

There’s a tricky bit of math­e­mat­ics hid­den inside this simple-seeming phys­i­cal model, though: how do we cap­ture the phys­i­cal con­straint that keeps paper from pass­ing through itself?

Demaine and O’Rourke’s con­tri­bu­tions are emi­nent and inter­est­ing and well-considered. There are cunningly-crafted con­straints that cap­ture the phys­i­cal­ity of paper’s inabil­ity to cross itself, and iden­tify fea­si­ble flat fold­ings (and implic­itly fold­ings that aren’t “flat” at all), while main­tain­ing the integrity of the paper itself. In other words, you carry on that direc­tion, and you have a for­mal rep­re­sen­ta­tion that lets you do some fas­ci­nat­ing math­e­mat­ics and modeling.

But what would it take to build a soft­ware sys­tem that “did” this?

By “this” I mean the work of estab­lish­ing nec­es­sary and suf­fi­cient con­di­tions for real­is­tic folded lines. The implicit and tacit stuff a human being takes for granted when they have some notion of “cross­ing” or even “fold­ing” in their heads already.

Does this make sense?

So let’s ask a GP sys­tem to look at a stack of line seg­ments of var­i­ous lengths and “merely” say whether there is any way a sin­gle line seg­ment could have been folded that way, with­out cross­ing itself. Heck, there are prob­a­bly long-range sit­u­a­tions in which a partially-folded crum­ple would inter­fere with itself; let’s ignore those.

So here’s a quick sketch to help out:

1D-origami.png

The top two squig­gles are actual folded line segments.

The first is def­i­nitely fea­si­ble, in the sense that you can imag­ine crunch­ing up a pipe cleaner or fold­ing the edges-only paper I men­tioned above and mak­ing the cross sec­tion look like that.

The sec­ond it infea­si­ble, because the mid­dle leaf is too big for the space it’s in, and pro­trudes through the crease.

But I think we need to go far­ther for this to be rea­son­ably inter­est­ing. Think about how you would rep­re­sent these objects or sit­u­a­tions in your GP sys­tem. What is a “folded stack”? Do you start from a line seg­ment and intro­duce moun­tain and val­ley folds at cer­tain posi­tions in some order? Or do you start from the folded stack and rep­re­sent it as a series of orders in cer­tain posi­tions, like those I’ve shown below?

I’ve sketched five lit­tle sit­u­a­tions down there in the bot­tom, indi­cat­ing with the dot­ted green lines where the nom­i­nal “crease” points are. Which of those five might be fea­si­ble? Which of them are fea­si­ble but rep­re­sent a line seg­ment that’s not the same size as the orig­i­nal shown in the top two? Which if them is infea­si­ble even when you allow the raw mate­r­ial to be any size at all?

See how this works? Those are all rea­son­ably inter­est­ing ques­tions. I can totally see a set of a few hun­dred (or thou­sand) exam­ples and coun­terex­am­ples for each cat­e­gory. Some exam­ples (I assume) from every com­bi­na­tion of feasible/infeasible, same/different, congruent/incongruent, single/multiple pieces. It’s an inter­est­ing algo­rith­mic exer­cise to fill in that chart with dia­gram­matic exam­ples. Train­ing and test data are yours for the tak­ing then.

But what this sort of project wants from us, as GP folks, is a bit of onto­log­i­cal work.

I’m the one who does this for a liv­ing, so let me pre­empt your ver­sions now:

  • a Diagram is a list of Stretches
  • each Stretch has a numeric length attribute, and a list Segments attribute
  • each Segments list con­tains inte­gers rep­re­sent­ing the seg­ments present, in top-to-bottom order, num­bered from 1 at the top and increas­ing downwards

So for the five exam­ples I’ve shown, each would have three Stretches. Say their lengths are 4, 11, and 5 respec­tively. And the Stretches would con­tain these Segments lists, respectively:

  1. [1],[1,2,3],[2]
  2. [1],[1,2,3],[3]
  3. [1,2],[1,2],[1,3]
  4. [1,3],[1,2,3],[3]
  5. [1,2],[2,3],[2]

Notice that the only dif­fer­ence between the fea­si­ble and infea­si­ble exam­ples (the first two) is the third Segment. What sort of “think­ing work” does your GP-developed algo­rithm need to do in order to dif­fer­en­ti­ate use­fully between these?

Notice that the first and third are both fea­si­ble, but that the third doesn’t add up to the same amount of mate­r­ial. Again, what does your GP-developed algo­rithm need to “know” to be able to iden­tify which dia­grams might and which might not be the same line? On the other hand, if we think of the Segment lengths as pro­por­tions rather than explicit mea­sure­ments, we’re sud­denly allow­ing the third dia­gram as well; in some sense it’s con­gru­ent to the first, but not identical.

And so on.

What sort of manip­u­la­tions of these input struc­tures might a general-purpose clas­si­fi­ca­tion algo­rithm do? What, in other words, is the Answer Lan­guage like?