Skip to content

Commit ba45be4

Browse files
committed
v.0.9.4 contd
* add .get() method to get all (filtered) results as an array, from current position to end * add magic squares combinatorial example and update n-queens example * update examples/readme
1 parent b45e513 commit ba45be4

File tree

7 files changed

+1352
-62
lines changed

7 files changed

+1352
-62
lines changed

examples/README.md

+164-29
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# Combinatorial Solutions to Popular Problems using Abacus
22

33

4-
The solutions, to popular problems, below exhibit the combinatorial capabilities of solving complex combinatorial problems of `Abacus`. Sometimes a solution is found by exhaustive search, other times better than full exhaustive search can be achieved and other times the solution does not require search at all but simply smart composition and manipulation of appropriate combinatorial objects.
4+
The solutions, to popular problems, below exhibit the combinatorial capabilities, for solving complex combinatorial problems, of `Abacus` library. Sometimes a solution is found by exhaustive search, other times better than full exhaustive search can be achieved and other times the solution does not require search at all but simply smart composition and manipulation of appropriate combinatorial objects.
55

66

77
### Contents
88

99
* [N-Queens Problem](#n-queens)
10+
* [Magic Squares](#magic-squares)
1011
* [Knapsack Problem](#knapsack)
1112
* [TSP Problem](#tsp)
1213

@@ -19,74 +20,208 @@ see associated file: `examples/n_queens.js`
1920

2021
**Exhaustive Search**
2122

22-
Let's assume we have some utility methods which allow us to check if a certain potential solution configuration is valid `isValid` and also (we need that as well) a method (`toRowColumn`) to map numeric patterns of combinatorial objects to `(row,column)` pairs on a hypothetical `NxN` grid.
23+
Let's assume we have some utility methods which allow us to check if a certain potential solution configuration is valid `is_valid` and also (we need that as well) a method (`row_column`) to map numeric patterns of combinatorial objects to `(row,column)` pairs on a hypothetical `NxN` grid. Also assume we have a utility method to make a `NxN` square grid with symbols `X` on `(row,col)` positions where a Queen is placed (`make_grid`)
2324

24-
With these utitlities available we can start directly using an exhaustive search among all configurations of placing `N` queens on distinct positions on an `NxN` grid.
25+
With these utilities available we can start directly using an exhaustive search among all configurations of placing `N` queens on distinct positions on an `NxN` grid.
2526

2627

2728
```javascript
28-
o = Abacus.Combination(N*N, N, {output:toRowColumn}).filterBy(isValid);
29+
solutions = Abacus.Combination(N*N, N, {output:row_column}).filterBy(is_valid).get();
2930

30-
echo(''+N+' Queens solutions (exhaustive search): START');
31-
for(let solution of o) echo(solution);
32-
echo(''+N+' Queens solutions (exhaustive search): END');
31+
echo(''+solutions.length+' Solutions for '+N+' Queens (exhaustive search):');
32+
echo(solutions.map(function(solution){return print_grid(make_grid(solution));}).join("\n---\n"));
3333
```
3434

3535
The above (for `N=4`) gives the following output:
3636

3737
```text
38-
4 Queens solutions (exhaustive search): START
39-
[ [ 0, 1 ], [ 1, 3 ], [ 2, 0 ], [ 3, 2 ] ]
40-
[ [ 0, 2 ], [ 1, 0 ], [ 2, 3 ], [ 3, 1 ] ]
41-
4 Queens solutions (exhaustive search): END
38+
2 Solutions for 4 Queens (exhaustive search):
39+
O X O O
40+
O O O X
41+
X O O O
42+
O O X O
43+
---
44+
O O X O
45+
X O O O
46+
O O O X
47+
O X O O
4248
```
4349

4450
**Reduced Exhaustive Search**
4551

46-
However searching among all combinations is inefficient, we can be a little smarter and assume from the beginning that each queen is placed on different row (or column). Then we simply check among all permutations of assigning each queen on a specific (different) column.
52+
However searching among all combinations as above is inefficient, we can be a little smarter and assume from the beginning that each queen is placed on different row (or column). Then we simply check among all permutations of assigning each queen on a specific (different) column.
4753

4854
```javascript
49-
o = Abacus.Permutation(N, {output:toRowColumnP}).filterBy(isValid);
55+
solutions = Abacus.Permutation(N, {output:row_column_perm}).filterBy(is_valid).get();
5056

51-
echo(''+N+' Queens solutions (reduced exhaustive search): START');
52-
for(let solution of o) echo(solution);
53-
echo(''+N+' Queens solutions (reduced exhaustive search): END');
57+
echo(''+solutions.length+' Solutions for '+N+' Queens (reduced exhaustive search):');
58+
echo(solutions.map(function(solution){return print_grid(make_grid(solution));}).join("\n---\n"));
5459
```
5560
The above (for `N=4`) gives the following output:
5661

5762
```text
58-
4 Queens solutions (reduced exhaustive search): START
59-
[ [ 0, 1 ], [ 1, 3 ], [ 2, 0 ], [ 3, 2 ] ]
60-
[ [ 0, 2 ], [ 1, 0 ], [ 2, 3 ], [ 3, 1 ] ]
61-
4 Queens solutions (reduced exhaustive search): END
63+
2 Solutions for 4 Queens (reduced exhaustive search):
64+
O X O O
65+
O O O X
66+
X O O O
67+
O O X O
68+
---
69+
O O X O
70+
X O O O
71+
O O O X
72+
O X O O
6273
```
6374

75+
By the way let's **prove** there is **no solution for 3-Queens** using previous method. Piece of cake, simply set `N=3`!
76+
77+
```text
78+
0 Solutions for 3 Queens (reduced exhaustive search):
79+
```
80+
81+
6482
**Exploiting Symmetries**
6583

66-
If we only need to find one solution, then there is an interesting connection between **pan-diagonal latin/magic squares** and **n-queens problems**. Specificaly if we have a pan-diagonal latin or magic square of order `N` then we can have (at least) one solution for the `N` Queens problem simply by placing a queen on each cell which contains only the symbol/number `s` (whatever we choose to be).
84+
If we only need to find one solution, any solution, then there is an interesting connection between **pan-diagonal latin/magic squares** and **n-queens problems**. Specificaly if we have a pan-diagonal latin or magic square of order `N` then we can have (at least) one solution for the `N` Queens problem simply by placing a queen on each cell which contains the symbol/number `s` (whatever we choose that to be) from the available `N` different symbols/numbers.
6785

68-
Since `Abacus` can generate `LatinSquares` and also will try to generate pan-diagonal latin squares if possible (for example for `N=5` it is possible), then we can generate a solution to the 5-Queens problem as follows:
86+
Since `Abacus` can generate `LatinSquare`s and also generates **pan-diagonal latin squares** by default if possible (for example for `N=5` it is possible), then we can generate a solution to the 5-Queens problem as follows:
6987

7088
```javascript
71-
o = Abacus.LatinSquare.make(N);
72-
echo(''+N+' Queens solution (pan-diagonal latin square): START');
73-
o.forEach(function(oi){echo(oi.map(function(x){ return N===x ? 'X' : 'O'}).join(' '));});
74-
echo(''+N+' Queen solutions (pan-diagonal latin square): END');
89+
solutions = [Abacus.LatinSquare.make(N)];
90+
91+
echo(''+solutions.length+' Solution for '+N+' Queens (pan-diagonal latin square):');
92+
echo(solutions.map(function(solution){return print_grid(from_latin_square(solution));}).join("\n---\n"));
7593
```
7694

7795
For `N=5` we get the following output:
7896

7997
```text
80-
5 Queens solution (pan-diagonal latin square): START
98+
1 Solution for 5 Queens (pan-diagonal latin square):
8199
O O X O O
82100
O O O O X
83101
O X O O O
84102
O O O X O
85103
X O O O O
86-
5 Queen solutions (pan-diagonal latin square): END
87104
```
88105

89-
We saw how we can explore and solve the N-Queens problem with a few lines of code using `Abacus` library.
106+
We saw how we can explore and solve the N-Queens problem with a two or three lines of code using `Abacus`.
107+
108+
109+
### Magic Squares
110+
111+
[Magic Square, wikipedia](https://en.wikipedia.org/wiki/Magic_square)
112+
113+
see associated file: `examples/magic_squares.js`
114+
115+
Although `Abacus` can compute magic squares for all orders `N` (except `2`), still it only produces one magic square.
116+
Let's try to find all possible magic squares (including rotated and reflected ones) systematically.
117+
118+
119+
**Exhaustive Search**
120+
121+
First we can try an exhaustive search over all perumations of numbers `1..N^2` arranged in a square grid.
122+
123+
```javascript
124+
solutions = Abacus.Permutation(N*N, {output:square}).filterBy(Abacus.MagicSquare.is_magic).get();
125+
126+
echo(''+solutions.length+' Solutions for '+N+'x'+N+' Magic Squares (exhaustive search):');
127+
echo(solutions.map(print_square).join("\n---\n"));
128+
```
129+
130+
The above for 3x3 magic squares gives:
131+
132+
```text
133+
8 Solutions for 3x3 Magic Squares (exhaustive search):
134+
2 7 6
135+
9 5 1
136+
4 3 8
137+
---
138+
2 9 4
139+
7 5 3
140+
6 1 8
141+
---
142+
4 3 8
143+
9 5 1
144+
2 7 6
145+
---
146+
4 9 2
147+
3 5 7
148+
8 1 6
149+
---
150+
6 1 8
151+
7 5 3
152+
2 9 4
153+
---
154+
6 7 2
155+
1 5 9
156+
8 3 4
157+
---
158+
8 1 6
159+
3 5 7
160+
4 9 2
161+
---
162+
8 3 4
163+
1 5 9
164+
6 7 2
165+
```
166+
167+
By the way, let's **prove** that there are no `2x2` magic squares (under standard definition). It's super easy and fast.
168+
Setting `N=2` we get **zero solutions**:
169+
170+
```text
171+
0 Solutions for 2x2 Magic Squares (exhaustive search):
172+
```
173+
174+
**Reduced Search**
175+
176+
Exhaustive search is very inefficient as `N` grows (even for small N such as 4 or 5 we get an enormous search space).
177+
We can try something else. We can generate a magic square (for example using `Abacus.MagicSquare.make(N)`) and try to permute its rows and columns and see if we get different magic squares. This is considerably faster, but might not generate all possible magic squares of order `N`.
178+
179+
Let's try this:
180+
181+
```javascript
182+
square = Abacus.MagicSquare.make(N);
183+
solutions = square ? Abacus.Permutation(N).concatWith(Abacus.Permutation(N)).get() : [];
184+
185+
solutions = solutions.reduce(function(solutions, solution){
186+
var permuted = permute_rows_cols(square, solution.slice(0,N), solution.slice(N));
187+
if ( Abacus.MagicSquare.is_magic(permuted) ) solutions.push(permuted);
188+
return solutions;
189+
}, []);
190+
191+
echo(''+solutions.length+' Solutions for '+N+'x'+N+' Magic Squares (limited search):');
192+
echo(solutions.map(print_square).join("\n---\n"));
193+
```
194+
195+
Setting `N=4` we get:
196+
197+
```text
198+
192 Solutions for 4x4 Magic Squares (limited search):
199+
16 2 3 13
200+
5 11 10 8
201+
9 7 6 12
202+
4 14 15 1
203+
---
204+
16 2 3 13
205+
9 7 6 12
206+
5 11 10 8
207+
4 14 15 1
208+
---
209+
5 11 10 8
210+
16 2 3 13
211+
4 14 15 1
212+
9 7 6 12
213+
---
214+
5 11 10 8
215+
4 14 15 1
216+
16 2 3 13
217+
9 7 6 12
218+
---
219+
..etc..
220+
```
221+
222+
Setting `N=6` we get 1440 solutions with our limited search.
223+
224+
We saw how we can investigate properties of magic squares and also enumerate them efficiently using a few lines of code with `Abacus`.
90225

91226

92227
### Knapsack

examples/magic_squares.js

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
var isNode = 'undefined' !== typeof global && '[object global]' === {}.toString.call(global);
2+
var Abacus = isNode ? require('../src/js/Abacus.js') : window.Abacus, echo = console.log;
3+
4+
var solutions, N, square;
5+
// compute all magic squares of order N by Combinatorial methods using Abacus
6+
7+
// utility functions
8+
function square(item)
9+
{
10+
// arrange a permutation of 0..N^2-1 to NxN grid of symbols 1..N^2
11+
var N = Math.floor(Math.sqrt(item.length)),
12+
i, j, k,
13+
output = new Array(N);
14+
for(i=0,k=0; i<N; i++)
15+
{
16+
output[i] = new Array(N);
17+
for(j=0; j<N; j++,k++) output[i][j] = item[k] + 1;
18+
}
19+
return output;
20+
}
21+
function format_num( n, l )
22+
{
23+
var s = String(n), sl = s.length;
24+
return sl < l ? new Array(l-sl+1).join(' ')+s : s;
25+
}
26+
function print_square(grid)
27+
{
28+
for(var out='',i=0,N=grid.length,LEN = String(N*N).length; i<N; i++)
29+
out += grid[i].map(function(x){ return format_num(x, LEN); }).join(' ') + (i+1<N?"\n":"");
30+
return out;
31+
}
32+
function permute_rows_cols(square, row_perm, col_perm)
33+
{
34+
var N = square.length, i, j, output = new Array(N);
35+
for(i=0; i<N; i++)
36+
{
37+
output[i] = new Array(N);
38+
for(j=0; j<N; j++)
39+
output[i][j] = square[row_perm[i]][col_perm[j]];
40+
}
41+
return output;
42+
}
43+
44+
N = 3; // 3-Magic
45+
// try filtering from all possible permutations of 1..N^2
46+
solutions = Abacus.Permutation(N*N, {output:square}).filterBy(Abacus.MagicSquare.is_magic).get();
47+
48+
echo(''+solutions.length+' Solutions for '+N+'x'+N+' Magic Squares (exhaustive search):');
49+
echo(solutions.map(print_square).join("\n---\n"));
50+
51+
echo('---');
52+
53+
N = 2; // 2-Magic
54+
// try filtering from all possible permutations of 1..N^2
55+
solutions = Abacus.Permutation(N*N, {output:square}).filterBy(Abacus.MagicSquare.is_magic).get();
56+
57+
echo(''+solutions.length+' Solutions for '+N+'x'+N+' Magic Squares (exhaustive search):');
58+
echo(solutions.map(print_square).join("\n---\n"));
59+
60+
echo('---');
61+
62+
N = 4; // 4-Magic
63+
square = Abacus.MagicSquare.make(N);
64+
solutions = square ? Abacus.Permutation(N).concatWith(Abacus.Permutation(N)).get() : [];
65+
66+
solutions = solutions.reduce(function(solutions, solution){
67+
var permuted = permute_rows_cols(square, solution.slice(0,N), solution.slice(N));
68+
if ( Abacus.MagicSquare.is_magic(permuted) ) solutions.push(permuted);
69+
return solutions;
70+
}, []);
71+
72+
echo(''+solutions.length+' Solutions for '+N+'x'+N+' Magic Squares (limited search):');
73+
echo(solutions.map(print_square).join("\n---\n"));
74+
75+
echo('---');
76+
77+
N = 6; // 6-Magic
78+
square = Abacus.MagicSquare.make(N);
79+
solutions = square ? Abacus.Permutation(N).concatWith(Abacus.Permutation(N)).get() : [];
80+
81+
solutions = solutions.reduce(function(solutions, solution){
82+
var permuted = permute_rows_cols(square, solution.slice(0,N), solution.slice(N));
83+
if ( Abacus.MagicSquare.is_magic(permuted) ) solutions.push(permuted);
84+
return solutions;
85+
}, []);
86+
87+
echo(''+solutions.length+' Solutions for '+N+'x'+N+' Magic Squares (limited search):');
88+
//echo(solutions.map(print_square).join("\n---\n"));
89+
90+
echo('---');

0 commit comments

Comments
 (0)