21 Commits

Author SHA1 Message Date
65c748aab3 Update results file with latest timings. 2025-09-04 20:08:34 +02:00
5a01260281 Code tidy as reported by clang-tidy 2025-09-04 11:35:37 +02:00
ff43ba5287 Make add and clear use indices.
This is the last commit of the workstream and we
have a ~10% speed improvement.
2025-09-04 11:27:49 +02:00
f1445b7544 Make next_pos iterate over indices. 2025-09-04 11:12:51 +02:00
ed71280dc2 Convert largest_square to use pos indices.
This makes the code a bit more confusing but no functional change.
2025-09-04 11:09:22 +02:00
a066fdb552 Convert Pos to an index.
Pos is now just an index into the grid.

This will be a slow down for the moment as we haven't worked through the
 changes to the algorithms yet.
2025-09-04 11:02:54 +02:00
e557933590 [1/n]: Refactor x() & y() calls on position
The goal of this sequence of patches is to end up representing a
position as a single integer index into the grid instead of an (x, y)
pair.  I believe this will have better performance.

First step move all calls of x(), y() into calls on methods of Results &
Grid as in the future these will need to use the length of the grid.
2025-09-04 10:53:20 +02:00
65569982ee Abstract away types and use 64-bit everywhere
We abstract away the types being used from 'int' and 'char'.  The one
exception being for output.

This allows us to experiment to see if using different types can improve
performance.

It turns out it does - and that using 64-bit integers everywhere is a
good idea.
2025-09-03 09:30:33 +02:00
4b9feefbf4 Split out results structure
We now return the results in a separate structure to the grid we have
been working on.

This ultimately makes it easier to play with the implementation of the
solution finder.
2025-09-03 08:59:06 +02:00
1684c289c6 Add a file showing results.
results.md details the results of the Partridge problem for sizes 8, 9
and 10.
2025-09-03 07:44:29 +02:00
f5021aca30 Change implementation to iterative.
Previously our implementation was recursive (although less so than the
OCaml version).

Moving to an iterative implementation improves performance as we have
fewer function calls, and so fewer function prologues and epilogues.
2025-09-02 19:11:01 +02:00
52a73a3d05 Add README.md and LICENSE. 2025-09-01 19:51:02 +02:00
706baf9048 Don't immediately store pretty squares
The initial implementation of the code stored squares in the grid in a
"pretty" form.  This is a complicated bit of code and slowed down the
code slightly.

Now we just store the size of the current square in the grid.  This
reduces the code complexity, and offers a slight performance
improvement.

We still output a prettified version of the grid, as we can generate
that from a grid populated with just square sizes.
2025-09-01 17:43:51 +02:00
9cbc6c4cbc Comment code. 2025-09-01 12:32:43 +02:00
e865b2a567 Change Grid to use vector not string.
This is another optimisation, as it improves memory layout and we are
not using a reference counted string.

On a M1 Macbook Air this brings runtime for solving the 9 cell down to
under 3m30s.  Which is about a 15% performance improvement.
2025-09-01 11:42:07 +02:00
355c4211aa Fix bug in largest_square: y direction
We were not taking into account that the largest_square may be
constrained by the y position as well as the x.  i.e. is there enough
vertical space for the square.

This commit adds that check.

We were working before because C++ is not memory safe, and we weren't
running debug builds.
2025-09-01 11:30:16 +02:00
d7b1290379 Optimize selection of next position.
Grid::next_pos was starting its scan from the position after the current
 one.

This is inefficient as we know how large the square we've just placed is
 as we scan those positions.

This optimisation just skips that square when starting the scan.
2025-09-01 11:00:56 +02:00
3095d38b8a Optimize: if sq N fits then sq (N - 1) does too.
As an optimisation we know that if a square with side length N fits in a
certain position, then one of side length N - 1 does too.  And
conversely, if a square of side length N does not fit then one of side
length N + 1 does not.

So our implementation which asked if every square fitted in a certain
position called Grid::fits() too many times, once for each side length.

We replace this by a function Grid::largest_square which gives the
appropriate side length to start with.

Naïvely the optimisation here is that instead of checking whether N
squares fit, and so having to do (N * (N + 1)) / 2 comparisons in fits
per position, we instead do one scan in largest_square and do at most N
comparisons.

A performance improvement is also seen in real life.
2025-09-01 10:34:24 +02:00
6ac6f2af9b Update VCS config. 2025-08-31 17:40:43 +01:00
d85a5ae57e Change the iteration method used.
We stop using function calls to move down an index but instead use a for
 loop.

This actually provides a slight performance improvement as we are not
repeated making and destroying function frames.
2025-08-31 17:40:30 +01:00
2423f39c57 Initial C++ version of Partridge solver
This is almost a complete copy of the OCaml version

About twice as fast.
2025-08-31 17:05:06 +01:00