This commit is contained in:
Taylor 2025-01-14 02:24:54 -06:00
commit 491975d207
37 changed files with 397 additions and 0 deletions

111
.gitignore vendored Normal file
View File

@ -0,0 +1,111 @@
*$py.class
**/*.DS_Store
**/*__pycache__
*.cover
*.egg
*.egg-info/
*.hi
*.hie
*.log
*.manifest
*.mo
*.o
*.pot
*.py,cover
*.py[cod]
*.pyc
*.sage.py
*.so
*.spec
*.swp
*__pycache__*
./*/__pycache__
.Python
.cache
.coverage
.coverage.*
.dmypy.json
.eggs/
.env
.gdb_history
.hypothesis/
.installed.cfg
.ipynb_checkpoints
.mypy_cache/
.nox/
.py2cfg
.pyre/
.pytest_cache/
.python-version
.pytype/
.ropeproject
.scrapy
.spyderproject
.spyproject
.tox/
.venv
.vscode
.webassets-cache
/*.egg-info
/dist/
/site
/target/*.out
/target/*.svg
/target/*main*
ENV/
MANIFEST
__pycache__
__pycache__/
__pypackages__/
admin_files/hashes.txt
build/*.o
build/*.out
celerybeat-schedule
celerybeat.pid
coverage.xml
db.sqlite3
db.sqlite3-journal
develop-eggs/
dist/
dmypy.json
docs/_build/
docs/build
downloads/
eggs/
env.bak/
env/
examples/*.pdf
examples/*.png
examples/*.svg
examples/_*.py
grade
htmlcov/
instance/
ipython_config.py
lib/
lib64/
local_settings.py
nosetests.xml
parts/
pip-delete-this-directory.txt
pip-log.txt
pip-wheel-metadata/
profile_default/
scores
sdist/
share/python-wheels/
src/*.hi
src/*.hie
src/*.o
target/*.out
target/*main*
tests/*/*.out
tests/*/out.*
tests/*/pass
tests/stdio_tests/diffs/?.*
tests/stdio_tests/outputs/?.*
tests/unit_tests/.mypy_cache/
var/
venv.bak/
venv/
wheels/

34
Makefile Normal file
View File

@ -0,0 +1,34 @@
code := $(wildcard src/*)
test_directories := $(wildcard tests/*)
test_targets := $(addsuffix /pass,$(test_directories))
existing_passes := $(wildcard tests/*/pass)
out_files := $(wildcard tests/*/*.out)
out_files += $(wildcard tests/*/out.*)
.PHONY: help build run test clean
help: # Show help for each of the commented Makefile recipes.
@grep -E '^[a-zA-Z0-9 -]+:.*#' Makefile | sort | while read -r l; \
do printf "\033[1;32m$$(echo $$l | cut -f 1 -d':')\033[00m:$$(echo $$l | cut -f 2- -d'#')\n"; done
tests/%/pass: $(code)
cd $(patsubst %/pass,%/,$@) && $(MAKE)
build: $(code) # Builds your code alone (does not build not any unit tests).
cd src && $(MAKE)
run: build # Runs your compiled main code (does not pass any args or std-io).
./target/main.out
test: $(test_targets) # Runs test code, generating score logfiles. To run past failing tests, use: `make test --keep-going`
@#$(MAKE) grade
clean: # Cleans up all the generated logfiles and outfiles.
@rm -f $(test_targets)
@rm -f $(out_files)
@rm -rf .mypy_cache __pycache__ *.out *.o *.hi .gdb_history
@rm -rf build/*
@rm -rf target/*
@rm -rf .admin_files/.mypy_cache .admin_files/__pycache__ .admin_files/*.hi .admin_files/*.o
@rm -rf */.mypy_cache */__pycache__ */*.out */*.o */*.hi
@rm -rf */*/.mypy_cache */*/__pycache__ */*/*.out */*/*.o */*/*.hi */*/.gdb_history

8
README.md Normal file
View File

@ -0,0 +1,8 @@
# HushGP
A PushGP implementation in Haskell
## Tasks
* [ ] Read this: https://arxiv.org/abs/2206.04561
* [ ] Do test-driven development on this one.
* [ ] Write tests for every function.
* [ ] tests/ are just copied from make-grade, need to write for this project.

3
src/.ghci Normal file
View File

@ -0,0 +1,3 @@
:set stop :list
:set prompt "\ESC[1;34m%s \ESC[0;35mλ>\ESC[m "
:load Push GP

0
src/.gitkeep Normal file
View File

3
src/GP.hs Normal file
View File

@ -0,0 +1,3 @@
module GP where
-- import Debug.Trace (trace, traceStack)

3
src/Makefile Normal file
View File

@ -0,0 +1,3 @@
../target/main.out: *.hs
ghc -g -fprof-auto -prof -Wall *.hs -o ../target/main.out
@rm -f *.o *.hi

81
src/Push.hs Normal file
View File

@ -0,0 +1,81 @@
module Push where
-- import Debug.Trace (trace, traceStack)
-- GeneModular or Gene?
-- Should we use a StateFunc or *Func for each push type?
-- Start with whole StateFunc since it is monolithic (easier to start),
-- then generalize and abstract with an apply method that itself takes a simpler function and the state?
{-
data GeneModular
= IntGene Int
| FloatGene Float
| BoolGene Bool
| StringGene String
| IntFunc [([Int] -> [Int] -> [Int])]
| StrFunc [([String] -> [String] -> [String])]
| BoolFunc [([Bool] -> [Bool] -> [Bool])]
| FloatFunc [([Float] -> [Float] -> [Float])]
-}
data Gene
= IntGene Int
| FloatGene Float
| BoolGene Bool
| StringGene String
| StateFunc (State -> State -> State)
| Close
-- | Group [Gene]
-- If we do plushy,
-- then we may need to make a structually recursive data structure for the "program" data structure
-- exampleGenome = [Program] rather than [Gene], or just include the Group above?
data State = State
{ exec :: [Gene],
int :: [Gene],
float :: [Gene],
bool :: [Gene],
string :: [Gene],
input :: [Gene]
}
emptyState :: State
emptyState =
State
{ exec = [],
int = [],
float = [],
bool = [],
string = [],
input = []
}
stackUpdate :: [Gene] -> State -> State
stackUpdate newstack@(StateFunc _ : _) (State _ i f b s p) = State newstack i f b s p
stackUpdate newstack@(IntGene _ : _) (State e _ f b s p) = State e newstack f b s p
stackUpdate newstack@(FloatGene _ : _) (State e i _ b s p) = State e i newstack b s p
stackUpdate newstack@(BoolGene _ : _) (State e i f _ s p) = State e i f newstack s p
stackUpdate newstack@(StringGene _ : _) (State e i f b _ p) = State e i f b newstack p
stackUpdate _ state = state
-- stackUpdate stackFunc (Input? _ : xs) (State e i f b s _) = State e i f b s newstack
unpackIntGene :: Gene -> Int
unpackIntGene (IntGene item) = item
-- Start with monolithic add function this:
intAdd :: State -> State
intAdd state =
let result = sum (map unpackIntGene (take 2 (int state)))
dropped = drop 2 (int state)
in stackUpdate (IntGene result : dropped) state
-- Later, generalize an applyFuncToState which applies simplifications of each simpler, modular atomic function:
-- intAdd :: (Int, Int) -> Int
-- applyFuncState :: State -> AtomicFuncTypes -> State
interpretGenome :: State -> [(State -> State)] -> State
interpretGenome state = foldl (\acc f -> f acc) state

20
src/main.hs Normal file
View File

@ -0,0 +1,20 @@
import Control.Exception (assert)
import GP
import Push
main :: IO ()
main = do
let exampleGenome = [intAdd, intAdd]
let exampleState =
State
{ exec = [IntGene 5, FloatGene 3.4, BoolGene True, StringGene "hi"],
int = [IntGene 1, IntGene 2, IntGene 3],
float = [FloatGene 1.2, FloatGene 1.7],
bool = [BoolGene True, BoolGene False],
string = [StringGene "Hello", StringGene "Push"],
input = [IntGene 1, StringGene "Hi", BoolGene True, FloatGene 1.3]
}
-- This is an example of applynig one function (head exampleGenome) to the exampleState:
assert ([3, 3] == map unpackIntGene (int (head exampleGenome exampleState))) pure ()
-- This one-liner applies an entire genome to the starting state, and produces the final state:
assert ([6] == (map unpackIntGene (int (interpretGenome exampleState exampleGenome)))) pure ()

0
target/.gitkeep Normal file
View File

View File

@ -0,0 +1,7 @@
-- https://stackoverflow.com/questions/8867350/how-to-set-a-programs-command-line-arguments-for-ghci
-- :set args is a GHCI thing:
-- https://downloads.haskell.org/ghc/latest/docs/users_guide/ghci.html#ghci-commands
:set stop :list
:load ../../src/main.hs ../../src/BinaryConversions.hs
:set args "argfile.in" "argfile.out"
:step main

View File

@ -0,0 +1,10 @@
pass: ../../src/*
cd ../../src/ && $(MAKE)
./../../target/main.out argfile.in argfile.out
delta argfile.goal argfile.out && echo 100 >pass \
|| ([[ "$$IS_PIPELINE" ]] && exit 1 \
|| (echo "Press enter to debug:" && read && $(MAKE) debug && exit 1))
.PHONY: debug
debug:
ghci

View File

@ -0,0 +1 @@
1010

View File

@ -0,0 +1 @@
10

View File

@ -0,0 +1,7 @@
-- https://stackoverflow.com/questions/8867350/how-to-set-a-programs-command-line-arguments-for-ghci
-- :set args is a GHCI thing:
-- https://downloads.haskell.org/ghc/latest/docs/users_guide/ghci.html#ghci-commands
:set stop :list
:load ../../src/main.hs ../../src/BinaryConversions.hs
:set args "argfile.in" "argfile.out"
:step main

View File

@ -0,0 +1,10 @@
pass: ../../src/*
cd ../../src/ && $(MAKE)
./../../target/main.out argfile.in argfile.out
python3 ../../.admin_files/fuzzydiffer.py argfile.goal argfile.out >pass \
|| ([[ "$$IS_PIPELINE" ]] && exit 1 \
|| (echo -e "$$(delta argfile.goal argfile.out)\nPress enter to debug:" && read && $(MAKE) debug && exit 1))
.PHONY: debug
debug:
ghci

View File

@ -0,0 +1 @@
1010

View File

@ -0,0 +1 @@
10

3
tests/doctests/Makefile Normal file
View File

@ -0,0 +1,3 @@
pass: ../../src/*.hs
echo $$PATH
doctest --verbose $^ && echo 100 >pass

2
tests/format/Makefile Normal file
View File

@ -0,0 +1,2 @@
pass: ../../src/*.hs
ormolu --mode check $^ && echo 100 >pass

View File

@ -0,0 +1,2 @@
pass: ../../src/*.hs
hlint $^ && echo 100 >pass

View File

@ -0,0 +1,13 @@
pass: ../../src/*.hs
ghc -fwrite-ide-info $^ -o main.out
stan --hiedir ../../src/ | grep "Total found observations ┃ 0" && echo 100 >pass \
|| ([[ "$$IS_PIPELINE" ]] && exit 1 \
|| (echo -e "\nPress enter to debug:" && read && $(MAKE) debug && exit 1))
@rm -f ../../src/*.hie ../../src/*.hi ../../src/*.o main.out
.PHONY: debug
debug:
ghc -fwrite-ide-info ../../src/*.hs -o main.out
stan --hiedir ../../src/
@rm -f ../../src/*.hie ../../src/*.hi ../../src/*.o main.out
@echo "To get points, fix the above 'observations'."

View File

@ -0,0 +1,3 @@
pass: ../../src/*.hs
ghc -Wall -Werror $^ -o main.out && echo 100 >pass || (rm main.out && exit 1)
@rm main.out

View File

@ -0,0 +1,3 @@
:set stop :list
:load ../../src/main.hs ../../src/BinaryConversions.hs
:step main

View File

@ -0,0 +1,10 @@
pass: ../../src/*
cd ../../src/ && $(MAKE)
./../../target/main.out <std.in >std.out
delta std.goal std.out && echo 100 >pass \
|| ([[ "$$IS_PIPELINE" ]] && exit 1 \
|| (echo "Press enter to debug (type std.in in yourself):" && read && $(MAKE) debug && exit 1))
.PHONY: debug
debug:
ghci

View File

@ -0,0 +1 @@
1010

View File

@ -0,0 +1 @@
10

View File

@ -0,0 +1,3 @@
:set stop :list
:load ../../src/main.hs ../../src/BinaryConversions.hs
:step main

View File

@ -0,0 +1,10 @@
pass: ../../src/*
cd ../../src/ && $(MAKE)
./../../target/main.out <std.in >std.out
python3 ../../.admin_files/fuzzydiffer.py std.goal std.out >pass \
|| ([[ "$$IS_PIPELINE" ]] && exit 1 \
|| (echo -e "$$(delta std.goal std.out)\nPress enter to debug (type std.in yourself):" && read && $(MAKE) debug && exit 1))
.PHONY: debug
debug:
ghci

View File

@ -0,0 +1 @@
1010

View File

@ -0,0 +1 @@
10

View File

@ -0,0 +1,3 @@
:set stop :list
:load unit.hs ../../src/BinaryConversions.hs
:step main

View File

@ -0,0 +1,10 @@
pass: ../../src/*
ghc -g -fprof-auto -prof -Wall unit.hs ../../src/BinaryConversions.hs -o unit.out
@rm -f *.o *.hi
./unit.out && echo 100 >pass \
|| ([[ "$$IS_PIPELINE" ]] && exit 1 \
|| (echo "Press enter to debug:" && read && $(MAKE) debug && exit 1))
.PHONY: debug
debug:
ghci

View File

@ -0,0 +1,7 @@
import BinaryConversions
import Control.Exception (assert)
main :: IO ()
main = do
let nums = [1, 2 .. 10]
assert (nums == map (binToNat . natToBin) nums) pure ()

View File

@ -0,0 +1,3 @@
:set stop :list
:load unit.hs ../../src/BinaryConversions.hs
:step main

View File

@ -0,0 +1,10 @@
pass: ../../src/*
ghc -g -fprof-auto -prof -Wall unit.hs ../../src/BinaryConversions.hs -o unit.out
@rm -f *.o *.hi
./unit.out | grep "OK" && echo 100 >pass \
|| ([[ "$$IS_PIPELINE" ]] && exit 1 \
|| (echo "Press enter to debug:" && read && $(MAKE) debug && exit 1))
.PHONY: debug
debug:
ghci

View File

@ -0,0 +1,10 @@
import BinaryConversions
import Numeric.Natural (Natural)
import Test.QuickCheck
import Test.QuickCheck.Instances.Natural ()
test :: [Natural] -> Bool
test nums = nums == map (binToNat . natToBin) nums
main :: IO ()
main = quickCheck test