Skip to content

Commit

Permalink
More Benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
christofsteel committed Dec 30, 2024
1 parent 54d5b35 commit 1602d78
Show file tree
Hide file tree
Showing 5 changed files with 556 additions and 0 deletions.
130 changes: 130 additions & 0 deletions tests/benchmarks/benchmark_maze_loopfree_generate_and_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
from functools import partial, cache

from collections.abc import Callable, Mapping
import timeit
from itertools import product
from typing import Any, cast
from clsp.dsl import DSL
from clsp.enumeration import Tree, enumerate_terms, interpret_term
from clsp.fcl import FiniteCombinatoryLogic

from clsp.types import Constructor, Literal, Param, LVar, Type


@cache
def visited(path: Tree[Any]) -> list[tuple[int, int]]:
if path.root == "START":
return []
return [cast(tuple[int, int], path.parameters["a"].root)] + visited(path.parameters["pos"])


def loopfree(term: Tree[Any]) -> bool:
visited_positions = visited(term)
return len(visited_positions) == len(set(visited_positions))


def is_free(size: int, pos: tuple[int, int]) -> bool:
"""
Create a maze in the form:
XXX...XXX
X X
X X...X X
. ..... .
X X...X X
X X
X X...XXX
X X
XXX...XXX
"""

col, row = pos
if row in [0, size - 1, size - 3]:
return True
else:
if row == size - 2 and col == size - 1:
return False
if col in [0, size - 1]:
return True
return False


def main(SIZE: int = 10, output: bool = True) -> float:
visited.cache_clear()
U: Callable[[int, int, str], str] = lambda b, _, p: f"{p} => UP({b})"
D: Callable[[int, int, str], str] = lambda b, _, p: f"{p} => DOWN({b})"
L: Callable[[int, int, str], str] = lambda b, _, p: f"{p} => LEFT({b})"
R: Callable[[int, int, str], str] = lambda b, _, p: f"{p} => RIGHT({b})"

pos: Callable[[str], Type] = lambda ab: Constructor("pos", (LVar(ab)))

repo: Mapping[
Callable[[int, int, str], str] | str,
Param | Type,
] = {
U: DSL()
.Use("b", "int2")
.Use("a", "int2")
.As(lambda b: (b[0], b[1] + 1))
.Use("pos", pos("a"))
# .With(lambda b, pos: b not in visited(pos))
.In(pos("b")),
D: DSL()
.Use("b", "int2")
.Use("a", "int2")
.As(lambda b: (b[0], b[1] - 1))
.Use("pos", pos("a"))
# .With(lambda b, pos: b not in visited(pos))
.In(pos("b")),
L: DSL()
.Use("b", "int2")
.Use("a", "int2")
.As(lambda b: (b[0] + 1, b[1]))
.Use("pos", pos("a"))
# .With(lambda b, pos: b not in visited(pos))
.In(pos("b")),
R: DSL()
.Use("b", "int2")
.Use("a", "int2")
.As(lambda b: (b[0] - 1, b[1]))
.Use("pos", pos("a"))
# .With(lambda b, pos: b not in visited(pos))
.In(pos("b")),
"START": "pos" @ (Literal((0, 0), "int2")),
}

# literals = {"int": list(range(SIZE))}
literals = {"int2": list(filter(partial(is_free, SIZE), product(range(SIZE), range(SIZE))))}

if output:
for row in range(SIZE):
for col in range(SIZE):
if is_free(SIZE, (col, row)):
print("-", end="")
else:
print("#", end="")
print("")

fin = "pos" @ (Literal((SIZE - 1, SIZE - 1), "int2"))

fcl: FiniteCombinatoryLogic[Callable[[int, int, str], str] | str] = FiniteCombinatoryLogic(
repo, literals=literals
)

start = timeit.default_timer()
grammar = fcl.inhabit(fin)

num_terms = 0
for term in enumerate_terms(fin, grammar):
if loopfree(term):
t = interpret_term(term)
if output:
print(t)
num_terms += 1
if num_terms == 2:
break

return timeit.default_timer() - start


if __name__ == "__main__":
main()
114 changes: 114 additions & 0 deletions tests/benchmarks/benchmark_maze_posparams_onlytermparam.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from collections.abc import Callable, Mapping
from functools import cache
import timeit
from typing import Optional
from clsp.dsl import DSL
from clsp.enumeration import Tree, enumerate_terms, interpret_term
from clsp.fcl import FiniteCombinatoryLogic

from clsp.types import Constructor, Literal, Param, Type


def plus_one(a: str) -> Callable[[Mapping[str, Literal]], int]:
def _inner(vars: Mapping[str, Literal]) -> int:
return int(1 + vars[a].value)

return _inner


@cache
def current_position(pos: Tree[str]) -> tuple[int, int]:
curr_pos = (0, 0)
while pos.root != "START":
if pos.root == "D":
curr_pos = (curr_pos[0], curr_pos[1] + 1)
elif pos.root == "U":
curr_pos = (curr_pos[0], curr_pos[1] - 1)
elif pos.root == "L":
curr_pos = (curr_pos[0] - 1, curr_pos[1])
elif pos.root == "R":
curr_pos = (curr_pos[0] + 1, curr_pos[1])
pos = pos.parameters["pos"]
return curr_pos


@cache
def is_free(pos: tuple[int, int], SIZE: int, next_step: Optional[tuple[int, int]] = None) -> bool:
col, row = pos
if next_step is not None:
col = col + next_step[0]
row = row + next_step[1]
if col < 0 or row < 0 or col >= SIZE or row >= SIZE:
return False
SEED = 0
if row == col:
return True
else:
return pow(11, (row + col + SEED) * (row + col + SEED) + col + 7, 1000003) % 5 > 0


def main(SIZE: int = 5, output: bool = True) -> float:
repo: Mapping[
str,
Param | Type,
] = {
"U": DSL()
.Use("pos", Constructor("pos"))
.With(lambda pos: is_free(current_position(pos), SIZE, next_step=(0, -1)))
.In(Constructor("pos")),
"D": DSL()
.Use("pos", Constructor("pos"))
.With(lambda pos: is_free(current_position(pos), SIZE, next_step=(0, 1)))
.In(Constructor("pos")),
"L": DSL()
.Use("pos", Constructor("pos"))
.With(lambda pos: is_free(current_position(pos), SIZE, next_step=(-1, 0)))
.In(Constructor("pos")),
"R": DSL()
.Use("pos", Constructor("pos"))
.With(lambda pos: is_free(current_position(pos), SIZE, next_step=(1, 0)))
.In(Constructor("pos")),
"START": "pos" @ (Literal((0, 0), "int2")),
"END": DSL()
.Use("pos", Constructor("pos"))
.With(lambda pos: current_position(pos) == (SIZE - 1, SIZE - 1))
.In(Constructor("end")),
}

# literals = {"int": list(range(SIZE))}
# literals = {"int2": list(filter(is_free, product(range(SIZE), range(SIZE))))}

if output:
for row in range(SIZE):
for col in range(SIZE):
if is_free((col, row), SIZE):
print("-", end="")
else:
print("#", end="")
print("")

fin = Constructor("end")

fcl: FiniteCombinatoryLogic[str] = FiniteCombinatoryLogic(repo)

start = timeit.default_timer()
grammar = fcl.inhabit(fin)

interpretation = {
"U": lambda pos: f"{pos} => UP",
"D": lambda pos: f"{pos} => DOWN",
"L": lambda pos: f"{pos} => LEFT",
"R": lambda pos: f"{pos} => RIGHT",
"END": lambda pos: f"{pos} => END",
}

for term in enumerate_terms(fin, grammar, 10):
t = interpret_term(term, interpretation)
if output:
print(t)

return timeit.default_timer() - start


if __name__ == "__main__":
main()
128 changes: 128 additions & 0 deletions tests/benchmarks/benchmark_maze_posparams_onlytermparam_stratified.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
from collections.abc import Callable, Mapping
from functools import cache
import timeit
from typing import Optional
from clsp.dsl import DSL
from clsp.enumeration import Tree, enumerate_terms, interpret_term
from clsp.fcl import FiniteCombinatoryLogic

from clsp.types import Constructor, Literal, Param, LVar, Type


def plus_one(a: str) -> Callable[[Mapping[str, Literal]], int]:
def _inner(vars: Mapping[str, Literal]) -> int:
return int(1 + vars[a].value)

return _inner


@cache
def current_position(pos: Tree[str]) -> tuple[int, int]:
curr_pos = (0, 0)
while pos.root != "START":
if pos.root == "D":
curr_pos = (curr_pos[0], curr_pos[1] + 1)
elif pos.root == "U":
curr_pos = (curr_pos[0], curr_pos[1] - 1)
elif pos.root == "L":
curr_pos = (curr_pos[0] - 1, curr_pos[1])
elif pos.root == "R":
curr_pos = (curr_pos[0] + 1, curr_pos[1])
pos = pos.parameters["pos"]
return curr_pos


@cache
def is_free(pos: tuple[int, int], SIZE: int, next_step: Optional[tuple[int, int]] = None) -> bool:
col, row = pos
if next_step is not None:
col = col + next_step[0]
row = row + next_step[1]
if col < 0 or row < 0 or col >= SIZE or row >= SIZE:
return False
SEED = 0
if row == col:
return True
else:
return pow(11, (row + col + SEED) * (row + col + SEED) + col + 7, 1000003) % 5 > 0


def main(SIZE: int = 9, output: bool = True) -> float:
repo: Mapping[
str,
Param | Type,
] = {
"U": DSL()
.Use("new_size", "int")
.Use("size", "int")
.As(lambda new_size: new_size - 1)
.Use("pos", Constructor("pos", LVar("size")))
.With(lambda pos: is_free(current_position(pos), SIZE, next_step=(0, -1)))
.In(Constructor("pos", LVar("new_size"))),
"D": DSL()
.Use("new_size", "int")
.Use("size", "int")
.As(lambda new_size: new_size - 1)
.Use("pos", Constructor("pos", LVar("size")))
.With(lambda pos: is_free(current_position(pos), SIZE, next_step=(0, 1)))
.In(Constructor("pos", LVar("new_size"))),
"L": DSL()
.Use("new_size", "int")
.Use("size", "int")
.As(lambda new_size: new_size - 1)
.Use("pos", Constructor("pos", LVar("size")))
.With(lambda pos: is_free(current_position(pos), SIZE, next_step=(-1, 0)))
.In(Constructor("pos", LVar("new_size"))),
"R": DSL()
.Use("new_size", "int")
.Use("size", "int")
.As(lambda new_size: new_size - 1)
.Use("pos", Constructor("pos", LVar("size")))
.With(lambda pos: is_free(current_position(pos), SIZE, next_step=(1, 0)))
.In(Constructor("pos", LVar("new_size"))),
"START": "pos" @ (Literal(0, "int")),
"END": DSL()
.Use("size", "int")
.Use("pos", Constructor("pos", LVar("size")))
.With(lambda pos: current_position(pos) == (SIZE - 1, SIZE - 1))
.In(Constructor("end")),
}

literals = {"int": set(range(SIZE * SIZE))}
# literals = {"int2": list(filter(is_free, product(range(SIZE), range(SIZE))))}

if output:
for row in range(SIZE):
for col in range(SIZE):
if is_free((col, row), SIZE):
print("-", end="")
else:
print("#", end="")
print("")

fin = Constructor("pos", Literal(4, "int"))
fin = Constructor("end")

fcl: FiniteCombinatoryLogic[str] = FiniteCombinatoryLogic(repo, literals=literals)

start = timeit.default_timer()
grammar = fcl.inhabit(fin)

interpretation = {
"U": lambda new_size, size, pos: f"{pos} => UP",
"D": lambda new_size, size, pos: f"{pos} => DOWN",
"L": lambda new_size, size, pos: f"{pos} => LEFT",
"R": lambda new_size, size, pos: f"{pos} => RIGHT",
"END": lambda size, pos: f"{pos} => END",
}

for term in enumerate_terms(fin, grammar, 10):
t = interpret_term(term, interpretation)
if output:
print(t)

return timeit.default_timer() - start


if __name__ == "__main__":
main()
Loading

0 comments on commit 1602d78

Please sign in to comment.