Recently I came across this intriguing little puzzle…

*Take the integers 1..n and, if possible, arrange them in a list in such a way that consecutive numbers in the list add up to a square number. Use each number 1..n once only.*

*Take the integers 1..n and, if possible, arrange them in a list in such a way that consecutive numbers in the list add up to a square number. Use each number 1..n once only.*

In exploring this puzzle I started writing down the numbers and forming a graph where two numbers are connected if they add up to a square. Drawing such graphs is fun but slightly tedious for, for example, [1..300]… Here’s such a graph for numbers 1..15. Starting at 8 then 1 etc. and following the path gives the solution for 1..15.

I became sidetracked into writing a bit of Haskell to generate such graphs and and then create an image from it 🙂

In this post we’ll

- look at one way of capturing the essence of what a graph is – without any formal development or assertions.
- Then add a few utility functions to create and manipulate such a graph and finally.
- Use some Haskell bindings to graphviz to create images of the graphs.

### Graph Types

A graph is just a collection of vertices of a given type and a set of edges representing connections between vertices. There are various ways to represent this idea, here is one simplistic option.

1 2 3 4 |
-- newtype V a = V [a] deriving Show newtype E a = E [(a, a)] deriving Show newtype Graph a = G (V a ,E a) deriving Show |

For a *Graph* holding things of type *a* we have a list of *a* representing the vertices –* V [a].*

An edge between two *a* s is shown as a tuple and all edges is a list of such tuples – *E [(a, a)].*

Finally a *Graph* of *a* is *G (V a, E a)*.

### Some Functions

If we start with a list of vertices – for this problem we have 1..n but we can keep it quite general – some vertices will be connected to other vertices, some vertices may have many connections and some may have none. In our puzzle the criteria is that the two vertices (integers) add up to a square. Two numbers adding to give a square is a very specific function on integers. We can generalise it to a function that takes two vertices to give a boolean if the vertices should be connected.

i.e.
(a -> a -> Bool)

So, for a given list of vertices we can generate a graph by applying the function to each possible pair like this:

1 2 3 4 5 6 7 8 9 |
-- buildGraph :: (Eq a) => [a] -> (a -> a -> Bool) -> Graph a buildGraph vs ed = G (V vs, E es) where es = nubBy sameEdge . join . makeEdges $ vs makeEdges = map f where f n = foldr (\v a -> if ed n v then (n, v) : a else a) [] vs sameEdge ::(Eq a) => (a, a) -> (a, a) -> Bool sameEdge (a, b) (c, d) = a == d && b == c || a == c && b == d |

Here we are mapping a function f over the vertices and f is a fold over the vertices of the ‘*am I an edge function*‘ –
(a -> a -> Bool)

The *join* function is needed as *makeEdges* creates a list of lists and *nubBy sameEdge* is used to remove duplicate edges.

We can use this general function for our puzzle by creating a suitable ‘*am I an edge function*‘ i.e.

1 2 3 4 5 6 |
-- sqEdge :: (Integral a, Num a) => a -> a -> Bool sqEdge n v = n /= v && isSquare (n + v) isSquare :: Integral a => a -> Bool isSquare n = sq * sq == n where sq = floor $ sqrt (fromIntegral n :: Double) |

To generate a graph where connected vertices add up to a square we just call the *buildGraph *with a list of vertices and the *sqEdge* function.

1 2 3 4 5 |
-- λ-> buildGraph [1..15] sqEdge G (V [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], E [(1,3),(1,8),(1,15),(2,7),(2,14),(3,6),(3,13), (4,5),(4,12),(5,11),(6,10),(7,9),(10,15),(11,14),(12,13)]) |

1 2 3 4 5 6 7 8 9 10 11 12 |
-- λ-> buildGraph [1..50] sqEdge G (V [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, 31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50], E [(1,3),(1,8),(1,15),(1,24),(1,35),(1,48),(2,7),(2,14),(2,23),(2,34),(2,47),(3,6),(3,13), (3,22),(3,33),(3,46),(4,5),(4,12),(4,21),(4,32),(4,45),(5,11),(5,20),(5,31),(5,44),(6,10), (6,19),(6,30),(6,43),(7,9),(7,18),(7,29),(7,42),(8,17),(8,28),(8,41),(9,16),(9,27),(9,40), (10,15),(10,26),(10,39),(11,14),(11,25),(11,38),(12,13),(12,24),(12,37),(13,23),(13,36), (14,22),(14,35),(14,50),(15,21),(15,34),(15,49),(16,20),(16,33),(16,48),(17,19),(17,32), (17,47),(18,31),(18,46),(19,30),(19,45),(20,29),(20,44),(21,28),(21,43),(22,27),(22,42), (23,26),(23,41),(24,25),(24,40),(25,39),(26,38),(27,37),(28,36),(29,35),(30,34),(31,33), (31,50),(32,49),(33,48),(34,47),(35,46),(36,45),(37,44),(38,43),(39,42),(40,41)]) |

### Drawing with Graphviz

Having some previous familiarity with Graphviz I found a Haskell library with bindings for Graphviz. Of course you will need to install Graphviz but the Haskell side is covered by the stack and cabal files in the Github repo for this post. In outline, the pipeline to get an image (.png) of a graph is to

- Create the graph… we’ve covered that.
- Modify the structure of the graph so that Graphviz can process it. This involves adding ‘labels’ to the edges and vertices.
- Use the Haskell Graphviz library to create an intermediate Graphviz dot file.
- Use the Graphviz command line to create a png from the dot file.
- Look at the pictures 🙂

**Modify the structure. ** Perhaps in retrospect I could/should have defined* Vs* and *Es* as a pair and a triple respectively as this is what Grapviz needs. The extra item is a label for the vertex or edge – so we need to add an extra value to the vertices and edges. Here’s a labelling function to do just that.

1 2 3 4 5 |
-- graphLabeller :: (a -> b) -> (a -> a -> c) -> Graph a -> ([(a,b)], [(a,a,c)]) graphLabeller vf ef (G (V vs, E es)) = (vs', es') where vs' = map (\ v -> (v, vf v)) vs es' = map (\ (x, y) -> (x, y, ef x y)) es |

It takes a vertex function, *vf* which defines how to label a vertex. Similarly an edge function, *ef*, that creates a label from the two vertices of this edge. The function works by mapping these two functions over the edges and vertices.

**Graphviz dot file. **Creation of a dot file and the invocation of the Graphviz command line is done in *makeImage*

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
-- graphParams ::(Show a) => G.GraphvizParams a a a () a graphParams = G.defaultParams { G.fmtNode = const [colorAttribute $ G.RGB 0 0 0], G.fmtEdge = \(t, f, l) -> [G.textLabel (TL.pack $ show l), G.arrowTo G.noArrow, colorAttribute (G.RGB 200 0 0)]} where colorAttribute color = G.Color $ G.toColorList [ color ] makeImage :: FilePath -> ([(Int, Int)], [(Int, Int, Int)]) -> IO () makeImage name (vs, es) = do let dotGraph = G.graphElemsToDot graphParams vs es :: G.DotGraph Int let dotText = G.printDotGraph dotGraph :: TL.Text TL.writeFile (name <> ".dot") dotText callCommand ("dot " <> name <> ".dot -Tpng > " <> name <> ".png") >>= print |

and the *graphParams* function gives basic details on how to format the display of a vertex – *G.fmtNode* – and an edge – *G.fmtEdge. *Pulling all this together into one utility function gives

1 2 3 4 5 6 |
-- graphToImage :: Int -> IO () graphToImage n = do let g = buildGraph [1..n] sqEdge let (vs, es) = graphLabeller id (+) g makeImage ("../images/1_" <> show n) (vs, es) |

And some sample outputs:

*graphToImage 15*

*graphToImage 30*

*graphToImage 50*

and the above can be sequenced like this graphToImage 15 >> graphToImage 30 >> graphToImage 50

Really, just an interesting diversion into playing with graphs and then rendering them!

Of course we can quite easily use a different ‘*am I an edge function*‘ to create other ‘Integer graphs’. For example
buildGraph [1..20 ] (\ x y -> x `mod` y == 0)

produces this graph

Having touched on graphs and rendering them the next post will either start looking at how to solve the original problem or will perhaps explore and refine the graph type and further investigate rendering.

Anyway, all the code is here in Github.

Thanks for reading!