Review knights benchmark and update dependencies.

This commit is contained in:
KtorZ 2024-07-16 14:46:36 +02:00
parent 1d16cbf386
commit f2ff9a2ee3
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
9 changed files with 555 additions and 124 deletions

View File

@ -3,12 +3,12 @@
[[requirements]] [[requirements]]
name = "aiken-lang/stdlib" name = "aiken-lang/stdlib"
version = "1.7.0" version = "1.9.0"
source = "github" source = "github"
[[packages]] [[packages]]
name = "aiken-lang/stdlib" name = "aiken-lang/stdlib"
version = "1.7.0" version = "1.9.0"
requirements = [] requirements = []
source = "github" source = "github"

View File

@ -10,5 +10,5 @@ platform = "github"
[[dependencies]] [[dependencies]]
name = "aiken-lang/stdlib" name = "aiken-lang/stdlib"
version = "1.7.0" version = "1.9.0"
source = "github" source = "github"

View File

@ -1,42 +1,47 @@
use aiken/list use aiken/list
use benchmarks/knights/heuristic.{descendants, finished_tour, start_tour} use benchmarks/knights/heuristic.{descendants, start_tour, tour_finished}
use benchmarks/knights/types.{ChessSet, Solution} use benchmarks/knights/types.{ChessSet, Solution}
use benchmarks/queue.{ use benchmarks/queue.{Queue}
Queue, append_all_front, append_front, create_queue, head, is_empty,
remove_front, to_list, // ------------------------------------------------------------------ Benchmarks
test bench_knights_100_4x4() {
run_knights(100, 4) == []
} }
test run_knights0() { test bench_knights_100_6x6() {
run_knights(100, 0) == [] run_knights(100, 6) == solution_100_6x6()
} }
test run_knights1() { test bench_knights_100_8x8() {
run_knights(100, 2) == [] run_knights(100, 8) == solution_100_8x8()
} }
// ----------------------------------------------------------------------- Setup
fn run_knights(depth: Int, board_size: Int) -> Solution { fn run_knights(depth: Int, board_size: Int) -> Solution {
depth_search(depth, root(board_size), grow, is_fin) |> to_list depth_search(depth, root(board_size), grow, done) |> queue.to_list
} }
fn depth_search( fn depth_search(
depth: Int, depth: Int,
queue: Queue<a>, xs: Queue<a>,
grow_fn: fn(a) -> List<a>, grow: fn(a) -> List<a>,
fin_fn: fn(a) -> Bool, done: fn(a) -> Bool,
) -> Queue<a> { ) -> Queue<a> {
if depth == 0 || is_empty(queue) { if depth == 0 || queue.is_empty(xs) {
create_queue() queue.new()
} else if fin_fn(head(queue)) { } else if done(queue.head(xs)) {
depth_search(depth - 1, remove_front(queue), grow_fn, fin_fn) depth_search(depth - 1, queue.remove_front(xs), grow, done)
|> append_front(head(queue)) |> queue.append_front(queue.head(xs))
} else { } else {
append_all_front(remove_front(queue), grow_fn(head(queue))) queue.append_all_front(queue.remove_front(xs), grow(queue.head(xs)))
|> depth_search(depth - 1, _, grow_fn, fin_fn) |> depth_search(depth - 1, _, grow, done)
} }
} }
fn root(sze: Int) -> Queue<(Int, ChessSet)> { fn root(size: Int) -> Queue<(Int, ChessSet)> {
append_all_front(create_queue(), mk_starts(sze)) queue.append_all_front(queue.new(), mk_starts(size))
} }
fn mk_starts(sze: Int) -> List<(Int, ChessSet)> { fn mk_starts(sze: Int) -> List<(Int, ChessSet)> {
@ -59,13 +64,506 @@ fn interval(a: Int, b: Int) -> List<Int> {
fn grow(item: (Int, ChessSet)) -> List<(Int, ChessSet)> { fn grow(item: (Int, ChessSet)) -> List<(Int, ChessSet)> {
let (x, y) = item let (x, y) = item
descendants(y) |> list.map(fn(list_item) { (x + 1, list_item) })
let const_item = x + 1
descendants(y) |> list.map(fn(list_item) { (const_item, list_item) })
} }
fn is_fin(item: (Int, ChessSet)) -> Bool { fn done(item: (Int, ChessSet)) -> Bool {
let (_, y) = item tour_finished(item.2nd)
}
finished_tour(y)
// ------------------------------------------------------------------ Fixtures
fn solution_100_6x6() {
[
(
0,
ChessSet {
size: 6,
move_number: 36,
start: Some((1, 1)),
visited: [
(3, 2),
(5, 3),
(6, 1),
(4, 2),
(3, 4),
(2, 6),
(4, 5),
(6, 6),
(5, 4),
(6, 2),
(4, 1),
(2, 2),
(1, 4),
(3, 3),
(2, 1),
(1, 3),
(2, 5),
(4, 6),
(6, 5),
(4, 4),
(5, 2),
(6, 4),
(5, 6),
(3, 5),
(1, 6),
(2, 4),
(1, 2),
(3, 1),
(4, 3),
(5, 1),
(6, 3),
(5, 5),
(3, 6),
(1, 5),
(2, 3),
(1, 1),
],
},
),
(
0,
ChessSet {
size: 6,
move_number: 36,
start: Some((1, 1)),
visited: [
(3, 2),
(5, 3),
(6, 1),
(4, 2),
(3, 4),
(2, 2),
(4, 1),
(6, 2),
(5, 4),
(6, 6),
(4, 5),
(2, 6),
(1, 4),
(3, 3),
(2, 1),
(1, 3),
(2, 5),
(4, 6),
(6, 5),
(4, 4),
(5, 2),
(6, 4),
(5, 6),
(3, 5),
(1, 6),
(2, 4),
(1, 2),
(3, 1),
(4, 3),
(5, 1),
(6, 3),
(5, 5),
(3, 6),
(1, 5),
(2, 3),
(1, 1),
],
},
),
(
0,
ChessSet {
size: 6,
move_number: 36,
start: Some((1, 1)),
visited: [
(3, 2),
(5, 3),
(6, 1),
(4, 2),
(3, 4),
(2, 2),
(1, 4),
(2, 6),
(4, 5),
(6, 6),
(5, 4),
(6, 2),
(4, 1),
(3, 3),
(2, 1),
(1, 3),
(2, 5),
(4, 6),
(6, 5),
(4, 4),
(5, 2),
(6, 4),
(5, 6),
(3, 5),
(1, 6),
(2, 4),
(1, 2),
(3, 1),
(4, 3),
(5, 1),
(6, 3),
(5, 5),
(3, 6),
(1, 5),
(2, 3),
(1, 1),
],
},
),
(
0,
ChessSet {
size: 6,
move_number: 36,
start: Some((1, 1)),
visited: [
(3, 2),
(5, 3),
(6, 1),
(4, 2),
(3, 4),
(2, 6),
(1, 4),
(2, 2),
(4, 1),
(6, 2),
(5, 4),
(6, 6),
(4, 5),
(3, 3),
(2, 1),
(1, 3),
(2, 5),
(4, 6),
(6, 5),
(4, 4),
(5, 2),
(6, 4),
(5, 6),
(3, 5),
(1, 6),
(2, 4),
(1, 2),
(3, 1),
(4, 3),
(5, 1),
(6, 3),
(5, 5),
(3, 6),
(1, 5),
(2, 3),
(1, 1),
],
},
),
]
}
fn solution_100_8x8() {
[
(
0,
ChessSet {
size: 8,
move_number: 64,
start: Some((1, 1)),
visited: [
(3, 2),
(5, 3),
(4, 5),
(5, 7),
(7, 6),
(8, 8),
(6, 7),
(5, 5),
(3, 4),
(1, 5),
(2, 7),
(4, 8),
(3, 6),
(1, 7),
(3, 8),
(4, 6),
(6, 5),
(4, 4),
(5, 6),
(6, 4),
(7, 2),
(8, 4),
(6, 3),
(5, 1),
(4, 3),
(3, 5),
(5, 4),
(3, 3),
(2, 5),
(1, 3),
(2, 1),
(4, 2),
(6, 1),
(8, 2),
(7, 4),
(8, 6),
(7, 8),
(6, 6),
(8, 5),
(7, 7),
(5, 8),
(3, 7),
(1, 8),
(2, 6),
(1, 4),
(2, 2),
(4, 1),
(6, 2),
(8, 1),
(7, 3),
(5, 2),
(7, 1),
(8, 3),
(7, 5),
(8, 7),
(6, 8),
(4, 7),
(2, 8),
(1, 6),
(2, 4),
(1, 2),
(3, 1),
(2, 3),
(1, 1),
],
},
),
(
0,
ChessSet {
size: 8,
move_number: 64,
start: Some((1, 1)),
visited: [
(3, 2),
(5, 3),
(4, 5),
(5, 7),
(7, 6),
(8, 8),
(6, 7),
(4, 8),
(2, 7),
(1, 5),
(3, 4),
(5, 5),
(3, 6),
(1, 7),
(3, 8),
(4, 6),
(6, 5),
(4, 4),
(5, 6),
(6, 4),
(7, 2),
(8, 4),
(6, 3),
(5, 1),
(4, 3),
(3, 5),
(5, 4),
(3, 3),
(2, 5),
(1, 3),
(2, 1),
(4, 2),
(6, 1),
(8, 2),
(7, 4),
(8, 6),
(7, 8),
(6, 6),
(8, 5),
(7, 7),
(5, 8),
(3, 7),
(1, 8),
(2, 6),
(1, 4),
(2, 2),
(4, 1),
(6, 2),
(8, 1),
(7, 3),
(5, 2),
(7, 1),
(8, 3),
(7, 5),
(8, 7),
(6, 8),
(4, 7),
(2, 8),
(1, 6),
(2, 4),
(1, 2),
(3, 1),
(2, 3),
(1, 1),
],
},
),
]
}
fn solution_80_8x8() {
[
(
0,
ChessSet {
size: 8,
move_number: 64,
start: Some((1, 1)),
visited: [
(3, 2),
(5, 3),
(4, 5),
(5, 7),
(7, 6),
(8, 8),
(6, 7),
(5, 5),
(3, 4),
(1, 5),
(2, 7),
(4, 8),
(3, 6),
(1, 7),
(3, 8),
(4, 6),
(6, 5),
(4, 4),
(5, 6),
(6, 4),
(7, 2),
(8, 4),
(6, 3),
(5, 1),
(4, 3),
(3, 5),
(5, 4),
(3, 3),
(2, 5),
(1, 3),
(2, 1),
(4, 2),
(6, 1),
(8, 2),
(7, 4),
(8, 6),
(7, 8),
(6, 6),
(8, 5),
(7, 7),
(5, 8),
(3, 7),
(1, 8),
(2, 6),
(1, 4),
(2, 2),
(4, 1),
(6, 2),
(8, 1),
(7, 3),
(5, 2),
(7, 1),
(8, 3),
(7, 5),
(8, 7),
(6, 8),
(4, 7),
(2, 8),
(1, 6),
(2, 4),
(1, 2),
(3, 1),
(2, 3),
(1, 1),
],
},
),
(
0,
ChessSet {
size: 8,
move_number: 64,
start: Some((1, 1)),
visited: [
(3, 2),
(5, 3),
(4, 5),
(5, 7),
(7, 6),
(8, 8),
(6, 7),
(4, 8),
(2, 7),
(1, 5),
(3, 4),
(5, 5),
(3, 6),
(1, 7),
(3, 8),
(4, 6),
(6, 5),
(4, 4),
(5, 6),
(6, 4),
(7, 2),
(8, 4),
(6, 3),
(5, 1),
(4, 3),
(3, 5),
(5, 4),
(3, 3),
(2, 5),
(1, 3),
(2, 1),
(4, 2),
(6, 1),
(8, 2),
(7, 4),
(8, 6),
(7, 8),
(6, 6),
(8, 5),
(7, 7),
(5, 8),
(3, 7),
(1, 8),
(2, 6),
(1, 4),
(2, 2),
(4, 1),
(6, 2),
(8, 1),
(7, 3),
(5, 2),
(7, 1),
(8, 3),
(7, 5),
(8, 7),
(6, 8),
(4, 7),
(2, 8),
(1, 6),
(2, 4),
(1, 2),
(3, 1),
(2, 3),
(1, 1),
],
},
),
]
} }

View File

@ -1,4 +1,3 @@
use aiken/builtin
use aiken/list use aiken/list
use benchmarks/knights/types.{ChessSet, Tile} use benchmarks/knights/types.{ChessSet, Tile}
@ -12,7 +11,6 @@ pub fn create_board(size: Int, init_square: Tile) -> ChessSet {
} }
pub fn add_piece(board: ChessSet, tile: Tile) -> ChessSet { pub fn add_piece(board: ChessSet, tile: Tile) -> ChessSet {
// record update
ChessSet { ChessSet {
..board, ..board,
move_number: board.move_number + 1, move_number: board.move_number + 1,
@ -25,11 +23,6 @@ pub fn first_piece(board: ChessSet) -> Tile {
tile tile
} }
// {-# INLINABLE lastPiece #-}
// lastPiece :: ChessSet -> Tile
// lastPiece (Board _ _ _ (t:_)) = t
// lastPiece _ = Tx.error ()
pub fn last_piece(board: ChessSet) -> Tile { pub fn last_piece(board: ChessSet) -> Tile {
when board.visited is { when board.visited is {
[] -> fail [] -> fail
@ -70,58 +63,5 @@ fn second_last(visited: List<a>) -> Option<a> {
} }
pub fn is_square_free(board: ChessSet, tile: Tile) -> Bool { pub fn is_square_free(board: ChessSet, tile: Tile) -> Bool {
not_in(board.visited, tile) !list.has(board.visited, tile)
} }
pub fn not_in(tiles: List<a>, tile: a) -> Bool {
!list.has(tiles, tile)
}
// {-# INLINABLE positionPiece #-}
// positionPiece :: Integer -> ChessSet -> Tile
// positionPiece x (Board _ n _ ts) = ts Tx.!! (n - x)
// {-# INLINABLE pieceAtTile #-}
// pieceAtTile :: Tile -> ChessSet -> Integer
// pieceAtTile x0 (Board _ _ _ ts)
// = findPiece x0 ts
// where
// findPiece _ [] = Tx.error ()
// findPiece x (y:xs)
// | x == y = 1 + Tx.length xs
// | otherwise = findPiece x xs
// -- % Everything below here is only needed for printing boards.
// -- % This is useful for debugging.
// instance Haskell.Show ChessSet where
// showsPrec _ (Board sze n _ ts)
// = Haskell.showString (printBoard sze sortedTrail 1)
// where sortedTrail = quickSort (assignMoveNo ts sze n)
// assignMoveNo :: [Tile] -> Integer -> Integer -> [Tile]
// assignMoveNo [] _ _
// = []
// assignMoveNo ((x,y):t) size z
// = (((y-1)*size)+x,z):assignMoveNo t size (z-1)
// printBoard :: Integer -> [Tile] -> Integer -> Haskell.String
// printBoard s [] n
// | (n > (s*s)) = ""
// | ((n `Haskell.mod` s) /=0)= "*"++(spaces (s*s) 1) ++(printBoard s [] (n+1))
// | ((n `Haskell.mod` s) ==0)= "*\n" ++(printBoard s [] (n+1))
// printBoard s trail@((i,j):xs) n
// | (i==n) &&
// ((n `Haskell.mod` s) ==0) = (Haskell.show j)++"\n"++(printBoard s xs (n+1))
// | (i==n) &&
// ((n `Haskell.mod` s) /=0)= (Haskell.show j)++(spaces (s*s) j)++(printBoard s xs (n+1))
// | ((n `Haskell.mod` s) /=0)= "*" ++(spaces (s*s) 1)++(printBoard s trail (n+1))
// | ((n `Haskell.mod` s) ==0)= "*\n" ++(printBoard s trail (n+1))
// printBoard _ _ _ = "?"
// spaces :: Integer -> Integer -> Haskell.String
// spaces s y =
// take' ((logTen s) - (logTen y) + 1) [' ',' '..]
// where
// logTen :: Integer -> Integer
// logTen 0 = 0
// logTen x = 1 + logTen (x `Haskell.div` 10)

View File

@ -1,9 +1,10 @@
use aiken/builtin use aiken/builtin
use aiken/int
use aiken/list use aiken/list
use benchmarks/knights/chess_set.{ use benchmarks/knights/chess_set.{
add_piece, create_board, delete_first, first_piece, is_square_free, last_piece, add_piece, create_board, delete_first, first_piece, is_square_free, last_piece,
} }
use benchmarks/knights/sort.{quick_sort} use benchmarks/knights/sort.{quicksort}
use benchmarks/knights/types.{ChessSet, Tile} use benchmarks/knights/types.{ChessSet, Tile}
type Direction { type Direction {
@ -23,7 +24,6 @@ fn direction_list() {
fn move(direction: Direction, tile: Tile) -> Tile { fn move(direction: Direction, tile: Tile) -> Tile {
let (x, y) = tile let (x, y) = tile
when direction is { when direction is {
UL -> (x - 1, y - 2) UL -> (x - 1, y - 2)
UR -> (x + 1, y - 2) UR -> (x + 1, y - 2)
@ -38,13 +38,11 @@ fn move(direction: Direction, tile: Tile) -> Tile {
pub fn start_tour(st: Tile, size: Int) -> ChessSet { pub fn start_tour(st: Tile, size: Int) -> ChessSet {
expect 0 = builtin.remainder_integer(size, 2) expect 0 = builtin.remainder_integer(size, 2)
create_board(size, st) create_board(size, st)
} }
pub fn finished_tour(board: ChessSet) -> Bool { pub fn tour_finished(board: ChessSet) -> Bool {
let ChessSet { move_number, size, .. } = board let ChessSet { move_number, size, .. } = board
move_number == size * size && can_jump_first(board) move_number == size * size && can_jump_first(board)
} }
@ -78,9 +76,8 @@ pub fn dead_end(board: ChessSet) -> Bool {
} }
pub fn single_descend(board: ChessSet) -> List<ChessSet> { pub fn single_descend(board: ChessSet) -> List<ChessSet> {
let descendants_and_moves = desc_and_no(board)
list.filter_map( list.filter_map(
descendants_and_moves, desc_and_no(board),
fn(item) { fn(item) {
let (moves, board) = item let (moves, board) = item
if moves == 1 { if moves == 1 {
@ -96,16 +93,15 @@ pub fn desc_and_no(board: ChessSet) -> List<(Int, ChessSet)> {
board board
|> all_descend |> all_descend
|> list.map( |> list.map(
fn(item) { fn(item) {
(item |> delete_first |> possible_moves |> list.length, item) (item |> delete_first |> possible_moves |> list.length, item)
}, },
) )
} }
pub fn can_move_to(board: ChessSet, tile: Tile) -> Bool { pub fn can_move_to(board: ChessSet, tile: Tile) -> Bool {
let (x, y) = tile let (x, y) = tile
let size = board.size let size = board.size
and { and {
x >= 1, x >= 1,
x <= size, x <= size,
@ -122,7 +118,7 @@ fn can_move(board: ChessSet, direction: Direction) -> Bool {
pub fn all_descend(board: ChessSet) -> List<ChessSet> { pub fn all_descend(board: ChessSet) -> List<ChessSet> {
board board
|> possible_moves |> possible_moves
|> list.map(fn(direction) { move_knight(board, direction) }) |> list.map(move_knight(board, _))
} }
fn move_knight(board: ChessSet, direction: Direction) -> ChessSet { fn move_knight(board: ChessSet, direction: Direction) -> ChessSet {

View File

@ -4,8 +4,8 @@ pub type Tile =
pub type ChessSet { pub type ChessSet {
size: Int, size: Int,
move_number: Int, move_number: Int,
visited: List<Tile>,
start: Option<Tile>, start: Option<Tile>,
visited: List<Tile>,
} }
pub type Solution = pub type Solution =

View File

@ -4,38 +4,35 @@ pub opaque type Queue<a> {
inner: List<a>, inner: List<a>,
} }
pub fn create_queue() -> Queue<a> { pub fn new() -> Queue<a> {
[] |> Queue [] |> Queue
} }
pub fn to_list(queue: Queue<a>) -> List<a> { pub fn to_list(self: Queue<a>) -> List<a> {
queue.inner self.inner
} }
pub fn is_empty(queue: Queue<a>) -> Bool { pub fn is_empty(self: Queue<a>) -> Bool {
when queue.inner is { when self.inner is {
[] -> True [] -> True
_ -> False _ -> False
} }
} }
pub fn append_front(queue: Queue<a>, item: a) -> Queue<a> { pub fn append_front(self: Queue<a>, item: a) -> Queue<a> {
list.push(queue.inner, item) |> Queue list.push(self.inner, item) |> Queue
} }
/// Add all items from the list to the front of the queue pub fn append_all_front(self: Queue<a>, items: List<a>) -> Queue<a> {
pub fn append_all_front(queue: Queue<a>, items: List<a>) -> Queue<a> { list.concat(items, self.inner) |> Queue
list.concat(items, queue.inner) |> Queue
} }
pub fn remove_front(queue: Queue<a>) -> Queue<a> { pub fn remove_front(self: Queue<a>) -> Queue<a> {
expect [_, ..rest] = queue.inner expect [_, ..rest] = self.inner
rest |> Queue rest |> Queue
} }
pub fn head(queue: Queue<a>) -> a { pub fn head(self: Queue<a>) -> a {
expect [q, ..] = queue.inner expect [q, ..] = self.inner
q q
} }

View File

@ -5,5 +5,5 @@ description = "Aiken contracts for project 'aiken-lang/hello_world'"
[[dependencies]] [[dependencies]]
name = "aiken-lang/stdlib" name = "aiken-lang/stdlib"
version = "1.7.0" version = "main"
source = "github" source = "github"

View File

@ -6,7 +6,7 @@
"plutusVersion": "v2", "plutusVersion": "v2",
"compiler": { "compiler": {
"name": "Aiken", "name": "Aiken",
"version": "v1.0.21-alpha+4b04517" "version": "v1.0.19-alpha+d56d518"
} }
}, },
"validators": [ "validators": [