From 628037d32c8d7af1469bd7920ea07aa6ac4f134e Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Fri, 22 Dec 2023 17:14:38 -0800 Subject: [PATCH 01/21] gitignore and file cleanup --- .gitignore | 5 +++++ .travis.yml | 17 --------------- appveyor.yml | 34 ------------------------------ deps/.gitignore | 1 - deps/build.jl | 56 ------------------------------------------------- src/.gitignore | 5 ----- 6 files changed, 5 insertions(+), 113 deletions(-) delete mode 100644 .travis.yml delete mode 100644 appveyor.yml delete mode 100644 deps/.gitignore delete mode 100644 deps/build.jl delete mode 100644 src/.gitignore diff --git a/.gitignore b/.gitignore index 8c960ec..c516fa0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ *.jl.cov *.jl.*.cov *.jl.mem +*.alpha +*.pg +**/.DS_Store +.vscode +Manifest.toml \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fc59945..0000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Documentation: http://docs.travis-ci.com/user/languages/julia/ -language: julia -os: - - linux - - osx - - windows -julia: - - 1 -notifications: - email: false -script: - - git clone https://github.com/JuliaRegistries/General $(julia -e 'import Pkg; println(joinpath(Pkg.depots1(), "registries", "General"))') - - git clone https://github.com/JuliaPOMDP/Registry $(julia -e 'import Pkg; println(joinpath(Pkg.depots1(), "registries", "JuliaPOMDP"))') - - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi - - julia --project --color=yes --check-bounds=yes -e 'import Pkg; Pkg.build(); Pkg.test("POMDPSolve"; coverage=true)' -after_success: - - julia --color=yes -e 'import Pkg; Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())' diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index e411740..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,34 +0,0 @@ -environment: - matrix: - - JULIAVERSION: "julialang/bin/winnt/x86/0.4/julia-0.4-latest-win32.exe" - - JULIAVERSION: "julialang/bin/winnt/x64/0.4/julia-0.4-latest-win64.exe" - - JULIAVERSION: "julianightlies/bin/winnt/x86/julia-latest-win32.exe" - - JULIAVERSION: "julianightlies/bin/winnt/x64/julia-latest-win64.exe" - -branches: - only: - - master - - /release-.*/ - -notifications: - - provider: Email - on_build_success: false - on_build_failure: false - on_build_status_changed: false - -install: -# Download most recent Julia Windows binary - - ps: (new-object net.webclient).DownloadFile( - $("http://s3.amazonaws.com/"+$env:JULIAVERSION), - "C:\projects\julia-binary.exe") -# Run installer silently, output to C:\projects\julia - - C:\projects\julia-binary.exe /S /D=C:\projects\julia - -build_script: -# Need to convert from shallow to complete for Pkg.clone to work - - IF EXIST .git\shallow (git fetch --unshallow) - - C:\projects\julia\bin\julia -e "versioninfo(); - Pkg.clone(pwd(), \"POMDPSolve\"); Pkg.build(\"POMDPSolve\")" - -test_script: - - C:\projects\julia\bin\julia --check-bounds=yes -e "Pkg.test(\"POMDPSolve\")" diff --git a/deps/.gitignore b/deps/.gitignore deleted file mode 100644 index cd4a9c0..0000000 --- a/deps/.gitignore +++ /dev/null @@ -1 +0,0 @@ -pomdp-solve-master diff --git a/deps/build.jl b/deps/build.jl deleted file mode 100644 index 0c7ebc5..0000000 --- a/deps/build.jl +++ /dev/null @@ -1,56 +0,0 @@ -using POMDPs - -#POMDPs.add("POMDPFiles") -#POMDPs.add("POMDPModels") -#POMDPs.add("POMDPToolbox") - - -if Sys.islinux() - download("http://www.pomdp.org/code/pomdp-solve-5.4.tar.gz", "pomdp-solve-5.4.tar.gz") - println("UNZIPPING"); run(`tar xvzf pomdp-solve-5.4.tar.gz`) - rm("pomdp-solve-5.4.tar.gz") - - cd("pomdp-solve-5.4") - - println("CONFIGURE"); run(`./configure`) - println("MAKE"); run(`make`) - - cd(@__DIR__) - mv("pomdp-solve-5.4", "pomdp-solve-master", force=true) -end - - -if Sys.isapple() - download("http://www.pomdp.org/code/pomdp-solve-5.4.tar.gz", "pomdp-solve-5.4.tar.gz") - - println("UNZIPPING"); run(`tar -zxf pomdp-solve-5.4.tar.gz`) - - rm("pomdp-solve-5.4.tar.gz") - cd("pomdp-solve-5.4") - - println("CONFIGURE"); run(`./configure`) - println("MAKE"); run(`make`) - - cd(@__DIR__) - mv("pomdp-solve-5.4", "pomdp-solve-master", force=true) -end - -if Sys.iswindows() - cd(@__DIR__) - if isdir("pomdp-solve-5.4") - rm("pomdp-solve-5.4", recursive=true) - end - mkdir("pomdp-solve-5.4") - cd("pomdp-solve-5.4") - mkdir("src") - cd("src") - download("http://web.stanford.edu/group/sisl/resources/pomdp-solve-4.5-cygwin-x64.zip", "pomdp-solve-4.5-cygwin-x64.zip") - exe7z = joinpath(Sys.BINDIR, "7z.exe") - if isdefined(Base, :LIBEXECDIR) - exe7z = joinpath(Sys.BINDIR, Base.LIBEXECDIR, "7z.exe") - end - run(`$exe7z x pomdp-solve-4.5-cygwin-x64.zip`) - rm("pomdp-solve-4.5-cygwin-x64.zip") - cd(@__DIR__) - mv("pomdp-solve-5.4", "pomdp-solve-master", force=true) -end diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index f1e98f1..0000000 --- a/src/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -deps/pomdp-solve-master -deps/pomdp-solve-5.4 -*.alpha -*.pg -.DS_Store \ No newline at end of file From c4b62013a6b222e76733e16d2077e0bd8d7a172f Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Fri, 22 Dec 2023 17:15:10 -0800 Subject: [PATCH 02/21] pomdptools and jll integration --- Project.toml | 21 ++--- src/POMDPSolve.jl | 12 ++- src/solver.jl | 4 +- test/4x4.95.pomdp | 86 +++++++++++++++++ test/runtests.jl | 230 ++++++++++++++++++++++++++++++++-------------- test/tiger.pomdp | 40 ++++++++ 6 files changed, 308 insertions(+), 85 deletions(-) create mode 100644 test/4x4.95.pomdp create mode 100644 test/tiger.pomdp diff --git a/Project.toml b/Project.toml index 9badbc8..8b75011 100644 --- a/Project.toml +++ b/Project.toml @@ -4,28 +4,23 @@ repo = "https://github.com/JuliaPOMDP/POMDPSolve.jl" version = "0.2.3" [deps] -BeliefUpdaters = "8bb6e9a1-7d73-552c-a44a-e5dc5634aac4" POMDPFiles = "9cf5b727-2e06-5671-8c87-8c6b0f729d5d" -POMDPModelTools = "08074719-1b2a-587c-a292-00f91cc44415" -POMDPPolicies = "182e52fb-cfd0-5e46-8c26-fd0667c990f4" +POMDPTools = "7588e00f-9cae-40de-98dc-e0c70c48cdd7" POMDPs = "a93abf59-7444-517b-a68a-c42f96afdd7d" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" [compat] -BeliefUpdaters = "0.1, 0.2" -POMDPFiles = "0.2.3" -POMDPModelTools = "0.2, 0.3" -POMDPPolicies = "0.2, 0.3, 0.4" +POMDPFiles = "0.2" +POMDPTools = "0.1" POMDPs = "0.9" -Reexport = "0.2" -julia = "1" +julia = "1.6" [extras] +NativeSARSOP = "a07c76ea-660d-4c9a-8028-2e6dbd212cb8" POMDPModels = "355abbd5-f08e-5560-ac9e-8b5f2592a0ca" -POMDPSimulators = "e0d0a172-29c6-5d4e-96d0-f262df5d01fd" -POMDPTesting = "92e6a534-49c2-5324-9027-86e3c861ab81" +Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["POMDPModels", "POMDPTesting", "POMDPSimulators", "Test"] +test = ["POMDPModels", "NativeSARSOP", "Suppressor", "Test"] diff --git a/src/POMDPSolve.jl b/src/POMDPSolve.jl index 87d51d0..dc50def 100644 --- a/src/POMDPSolve.jl +++ b/src/POMDPSolve.jl @@ -1,11 +1,17 @@ module POMDPSolve +using Pkg +try + using POMDPSolve_jll +catch + Pkg.add(url="https://github.com/dylan-asmar/POMDPSolve_jll.jl.git") + using POMDPSolve_jll +end + using POMDPs +using POMDPTools using POMDPFiles using Printf -using BeliefUpdaters -using POMDPPolicies -using POMDPModelTools export POMDPSolveSolver diff --git a/src/solver.jl b/src/solver.jl index ab6f9c1..1ec088c 100644 --- a/src/solver.jl +++ b/src/solver.jl @@ -176,10 +176,10 @@ function POMDPs.solve(solver::POMDPSolveSolver, pomdp::POMDP) end if isempty(solver.options) - run(`$EXEC_POMDP_SOLVE -pomdp $(pomdp_filename) -o $(fileprefix)`) + run(`$(pomdpsolve()) -pomdp $(pomdp_filename) -o $(fileprefix)`) else options_list = _get_options_list(solver.options) - run(`$EXEC_POMDP_SOLVE -pomdp $(pomdp_filename) -o $(fileprefix) $options_list`) + run(`$(pomdpsolve()) -pomdp $(pomdp_filename) -o $(fileprefix) $options_list`) end alpha_vectors, alpha_actions = read_alpha(fileprefix * ".alpha") diff --git a/test/4x4.95.pomdp b/test/4x4.95.pomdp new file mode 100644 index 0000000..32dd913 --- /dev/null +++ b/test/4x4.95.pomdp @@ -0,0 +1,86 @@ +discount: 0.95 +values: reward +states: 16 +actions: N0 S0 E0 W0 +observations: nothing goal + +start: +0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.0 + +T: N0 +1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 +0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.0 + +T: S0 +0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 +0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.0 + +T: E0 +0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 +0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.0 + +T: W0 +1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 +0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.066667 0.0 + +O: * : * : nothing 1.0 +O: * : 15 : nothing 0.0 +O: * : 15 : goal 1.0 + +R: * : * : 15 : * 1.0 \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 6579c0c..fce3d41 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,80 +1,176 @@ using POMDPSolve + +using Pkg +try + using POMDPSolve_jll +catch + Pkg.add(url="https://github.com/dylan-asmar/POMDPSolve_jll.jl.git") + using POMDPSolve_jll +end + using POMDPs using POMDPModels using POMDPFiles -using POMDPTesting -using POMDPPolicies -using POMDPSimulators: RolloutSimulator -using POMDPModelTools: Deterministic +using POMDPTools +using NativeSARSOP +using Suppressor using Test -pomdp = TigerPOMDP() -solver = POMDPSolveSolver() -policy = solve(solver, pomdp) +@testset "Solver jll Test" begin + + mktempdir() do dir + @testset "Tiger" begin + + pomdp = TigerPOMDP() + + fname = joinpath(dir, "tiger_test") + run(`$(pomdpsolve()) -pomdp tiger.pomdp -o $fname`) + @test isfile(joinpath(dir, "tiger_test.alpha")) + @test isfile(joinpath(dir, "tiger_test.pg")) + + alpha_vectors, alpha_actions = POMDPSolve.read_alpha(fname * ".alpha") + ord_acts = ordered_actions(pomdp) + p1 = AlphaVectorPolicy(pomdp, alpha_vectors, ord_acts[alpha_actions.+1]) + @test length(p1.alphas) == 9 + + solver = POMDPSolveSolver() + p2 = solve(solver, pomdp) + @test length(p2.alphas) == 9 + for (α1, α2) in zip(p1.alphas, p2.alphas) + @test isapprox(α1, α2; atol=1e-6) + end + + solver_sarsop = SARSOPSolver() + p_ss = solve(solver_sarsop, pomdp) + + v_ip = value(p2, initialstate(pomdp)) + v_ss = value(p_ss, initialstate(pomdp)) + @test isapprox(v_ip, v_ss; atol=1e-3) + + end + @testset "4x4.95" begin + fname = joinpath(dir, "4x4.95_test") + run(`$(pomdpsolve()) -pomdp 4x4.95.pomdp -o $fname`) + @test isfile(joinpath(dir, "4x4.95_test.alpha")) + @test isfile(joinpath(dir, "4x4.95_test.pg")) + + alpha_vectors, alpha_actions = POMDPSolve.read_alpha(fname * ".alpha") + ord_acts = [:up, :down, :left, :right] # N0 S0 E0 W0 in file + alpha_actions = ord_acts[alpha_actions.+1] + # All actions should be :down or :left (15th state is bottom left) + @test all((alpha_actions .== :down) .| (alpha_actions .== :left)) + end + + @testset "Baby POMDP" begin + pomdp = BabyPOMDP() + solver_sarsop = SARSOPSolver() + policy_sarsop = solve(solver_sarsop, pomdp) + v_sarsop = value(policy_sarsop, initialstate(pomdp)) + + solver_ip = POMDPSolveSolver() + policy_ip = solve(solver_ip, pomdp) + v_ip = value(policy_ip, initialstate(pomdp)) + + @test isapprox(v_sarsop, v_ip; atol=1e-3) + end + + @testset "Stopping Options" begin + p = TigerPOMDP() + solver = POMDPSolveSolver(; time_limit=1) + start_time = time() + policy = solve(solver, p) + end_time = time() + @test end_time - start_time < 1.5 + @test policy isa AlphaVectorPolicy + + solver = POMDPSolveSolver(; horizon=19) + output = @capture_out begin + policy = solve(solver, p) + end + @test occursin("Epoch: 1", output) + @test occursin("Epoch: 19", output) + @test !occursin("Epoch: 20", output) + end + + end + +end -show(stdout, MIME("text/plain"), collect(alphapairs(policy))) -# test _get_options_list -options = Dict{AbstractString, Any}() -options["A"] = "optionA" -options["B"] = 2 -println(POMDPSolve._get_options_list(options)) -@test POMDPSolve._get_options_list(options) == ["-A", "optionA", "-B", "2"] || - POMDPSolve._get_options_list(options) == ["-B", "2", "-A", "optionA"] +# show(stdout, MIME("text/plain"), collect(alphapairs(policy))) -# NOTe: following are arbitrarily set, values are probably not useful -solver2 = POMDPSolveSolver( - stdout = "out.txt", # Redirect programs stdout to a file of this name - rand_seed = (1,2,3), # Set the random seed for program execution - stat_summary=true, # Whether to keep and print internal execution stats - memory_limit = 10000, # Set upper bound memory usage - time_limit = 10000, # Set upper bound on execution time - terminal_values = "???", - horizon = 10, # Sets the number of iterations of value iteration - discount = 0.9, # Set the discount fact to use in value iteration - stop_criteria = :weak, # Sets the value iteration stopping criteria - stop_delta = 0.01, # Sets the precision for the stopping criteria check - save_all = true, # Sets whether or not to save every iteration's solution - vi_variation = :adjustable_epsilon, # Sets the general category of value iteration to use - start_epsilon = 0.01, # Sets the starting precision for adjustable epsilon VI - end_epsilon = 0.02, # Sets the ending precision for adjustable epsilon VI - epsilon_adjust = 0.01, # Sets the precision increment for adjustable epsilon VI - max_soln_size = 1000.0, # Sets the max size for the fixed solution size VI - history_length = 2, # Sets history window to use for adjustable epsilon VI - history_delta = 1, # Sets solution size delta to use for adjustable epsilon VI - dom_check = false, # Controls whether simple domination check is done or not - prune_epsilon = 1e-6, # Sets the precision level for the prune operations - epsilon = 1e-6, # General solution precision level setting - lp_epsilon = 1e-6, # Precision use in linear programs - proj_purge = :normal_prune, # Type of pruning to use for pre-iteration solving - q_purge = :normal_prune, # Type of pruning to use for a post-iteration solving - witness_points = true, # Whether to include 'witness points' in solving - alg_rand = 10, # How many points to use to seed value function creation - prune_rand = 10, # How many points to use to seed pruning process - method = :normal_prune, # Selects the main solution algorithm to use - enum_purge = :epsilon_prune, # The pruning method to use when using the 'enum' algorithm - inc_prune = :generalized, # The variation of the incremental pruning algorithm - fg_type = :pairwise, # Finite grid method means to generate belief points - fg_points = 10, # Maximal number of belief points to use in finite grid - fg_save = true, # Whether to save the points used in finite grid - mcgs_traj_length = 2, # Trajectory length for Monte Carlo belief generation - mcgs_num_traj = 10, # Number of trajectories for Monte Carlo belief generation - mcgs_traj_iter_count = 10, # Times to iterate on a trajectory for MCGS method - mcgs_prune_freq = 2, # How frequently to prune during MCGS method - fg_purge = :normal_prune, # Finite grid method means to prune value functions - verbose = :witness, # Turns on extra debugging output for a module - ) +# # test _get_options_list +# options = Dict{AbstractString, Any}() +# options["A"] = "optionA" +# options["B"] = 2 +# println(POMDPSolve._get_options_list(options)) +# @test POMDPSolve._get_options_list(options) == ["-A", "optionA", "-B", "2"] || +# POMDPSolve._get_options_list(options) == ["-B", "2", "-A", "optionA"] -test_solver(solver, pomdp) +# # NOTe: following are arbitrarily set, values are probably not useful +# solver2 = POMDPSolveSolver( +# stdout = "out.txt", # Redirect programs stdout to a file of this name +# rand_seed = (1,2,3), # Set the random seed for program execution +# stat_summary=true, # Whether to keep and print internal execution stats +# memory_limit = 10000, # Set upper bound memory usage +# time_limit = 10000, # Set upper bound on execution time +# terminal_values = "???", +# horizon = 10, # Sets the number of iterations of value iteration +# discount = 0.9, # Set the discount fact to use in value iteration +# stop_criteria = :weak, # Sets the value iteration stopping criteria +# stop_delta = 0.01, # Sets the precision for the stopping criteria check +# save_all = true, # Sets whether or not to save every iteration's solution +# vi_variation = :adjustable_epsilon, # Sets the general category of value iteration to use +# start_epsilon = 0.01, # Sets the starting precision for adjustable epsilon VI +# end_epsilon = 0.02, # Sets the ending precision for adjustable epsilon VI +# epsilon_adjust = 0.01, # Sets the precision increment for adjustable epsilon VI +# max_soln_size = 1000.0, # Sets the max size for the fixed solution size VI +# history_length = 2, # Sets history window to use for adjustable epsilon VI +# history_delta = 1, # Sets solution size delta to use for adjustable epsilon VI +# dom_check = false, # Controls whether simple domination check is done or not +# prune_epsilon = 1e-6, # Sets the precision level for the prune operations +# epsilon = 1e-6, # General solution precision level setting +# lp_epsilon = 1e-6, # Precision use in linear programs +# proj_purge = :normal_prune, # Type of pruning to use for pre-iteration solving +# q_purge = :normal_prune, # Type of pruning to use for a post-iteration solving +# witness_points = true, # Whether to include 'witness points' in solving +# alg_rand = 10, # How many points to use to seed value function creation +# prune_rand = 10, # How many points to use to seed pruning process +# method = :normal_prune, # Selects the main solution algorithm to use +# enum_purge = :epsilon_prune, # The pruning method to use when using the 'enum' algorithm +# inc_prune = :generalized, # The variation of the incremental pruning algorithm +# fg_type = :pairwise, # Finite grid method means to generate belief points +# fg_points = 10, # Maximal number of belief points to use in finite grid +# fg_save = true, # Whether to save the points used in finite grid +# mcgs_traj_length = 2, # Trajectory length for Monte Carlo belief generation +# mcgs_num_traj = 10, # Number of trajectories for Monte Carlo belief generation +# mcgs_traj_iter_count = 10, # Times to iterate on a trajectory for MCGS method +# mcgs_prune_freq = 2, # How frequently to prune during MCGS method +# fg_purge = :normal_prune, # Finite grid method means to prune value functions +# verbose = :witness, # Turns on extra debugging output for a module +# ) -@testset "rollout" begin - m = MiniHallway() +# test_solver(solver, pomdp) - p = solve(solver, m) +# @testset "rollout" begin +# m = MiniHallway() - sim = RolloutSimulator() - for s in states(m) - ret = simulate(sim, m, p, updater(p), Deterministic(s)) # only need to simulate once since MiniHallway is deterministic - @test ret ≈ value(p, Deterministic(s)) - end -end +# p = solve(solver, m) + +# sim = RolloutSimulator() +# for s in states(m) +# ret = simulate(sim, m, p, updater(p), Deterministic(s)) # only need to simulate once since MiniHallway is deterministic +# @test ret ≈ value(p, Deterministic(s)) +# end +# end + +# m = TigerPOMDP() + +# # solver = POMDPSolveSolver(; method=:normal_prune, stop_delta=1e-3, horizon=20) +# solver = POMDPSolveSolver(; time_limit=1, horizon=5) +# # m = MiniHallway() +# p = solve(solver, m) + +# using IncrementalPruning +# solver_ip = PruneSolver(; max_iterations=20, tolerance=1e-3, verbose=true) +# p_ip = solve(solver_ip, m) diff --git a/test/tiger.pomdp b/test/tiger.pomdp new file mode 100644 index 0000000..a963099 --- /dev/null +++ b/test/tiger.pomdp @@ -0,0 +1,40 @@ +# This is the tiger problem of AAAI paper fame in the new pomdp +# format. This format is still experimental and subject to change + +discount: 0.95 +values: reward +states: tiger-left tiger-right +actions: listen open-left open-right +observations: tiger-left tiger-right + +start: +0.5 0.5 + +T:listen +identity + +T:open-left +uniform + +T:open-right +uniform + +O:listen +0.85 0.15 +0.15 0.85 + +O:open-left +uniform + +O:open-right +uniform + +R:listen : * : * : * -1 + +R:open-left : tiger-left : * : * -100 + +R:open-left : tiger-right : * : * 10 + +R:open-right : tiger-left : * : * 10 + +R:open-right : tiger-right : * : * -100 From dd4537c3cc0abd290ab8590127e2a31cd9543f48 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Fri, 22 Dec 2023 17:38:46 -0800 Subject: [PATCH 03/21] constants update --- src/constants.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/constants.jl b/src/constants.jl index b0a0559..871b6b8 100644 --- a/src/constants.jl +++ b/src/constants.jl @@ -1,5 +1,3 @@ -const EXEC_POMDP_SOLVE = joinpath(dirname(pathof(POMDPSolve)), "..", "deps", "pomdp-solve-master", "src", "pomdp-solve") - const STOP_CRITERIA = [:exact, :weak, :bellman] const VI_VARIATION = [:normal, :zlz, :adjustable_epsilon, :fixed_soln_size] const METHOD = [:enum, :twopass, :linsup, :witness, :incprune, :grid, :mcgs] From 2d4ef3c2ccd348e551c3088177240ad0a8033136 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Sat, 23 Dec 2023 15:00:21 -0700 Subject: [PATCH 04/21] Updated constructor and docs --- Project.toml | 8 +- src/POMDPSolve.jl | 1 + src/constants.jl | 4 +- src/solver.jl | 777 ++++++++++++++++++++++++++++++++++++---------- src/utils.jl | 36 ++- 5 files changed, 650 insertions(+), 176 deletions(-) diff --git a/Project.toml b/Project.toml index 8b75011..025e117 100644 --- a/Project.toml +++ b/Project.toml @@ -5,22 +5,24 @@ version = "0.2.3" [deps] POMDPFiles = "9cf5b727-2e06-5671-8c87-8c6b0f729d5d" +POMDPSolve_jll = "7dc2201c-deb4-56f8-b3a0-2ab29a2c732a" # Need to update after registered POMDPTools = "7588e00f-9cae-40de-98dc-e0c70c48cdd7" POMDPs = "a93abf59-7444-517b-a68a-c42f96afdd7d" -Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" [compat] POMDPFiles = "0.2" +# Add compat for POMDPSolve_jll once registered POMDPTools = "0.1" POMDPs = "0.9" +Suppressor = "0.2" julia = "1.6" [extras] NativeSARSOP = "a07c76ea-660d-4c9a-8028-2e6dbd212cb8" POMDPModels = "355abbd5-f08e-5560-ac9e-8b5f2592a0ca" -Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["POMDPModels", "NativeSARSOP", "Suppressor", "Test"] +test = ["POMDPModels", "NativeSARSOP", "Test"] diff --git a/src/POMDPSolve.jl b/src/POMDPSolve.jl index dc50def..04984e0 100644 --- a/src/POMDPSolve.jl +++ b/src/POMDPSolve.jl @@ -12,6 +12,7 @@ using POMDPs using POMDPTools using POMDPFiles using Printf +using Suppressor export POMDPSolveSolver diff --git a/src/constants.jl b/src/constants.jl index 871b6b8..2ef4923 100644 --- a/src/constants.jl +++ b/src/constants.jl @@ -1,10 +1,10 @@ const STOP_CRITERIA = [:exact, :weak, :bellman] const VI_VARIATION = [:normal, :zlz, :adjustable_epsilon, :fixed_soln_size] -const METHOD = [:enum, :twopass, :linsup, :witness, :incprune, :grid, :mcgs] +const METHOD = [:enum, :twopass, :linsup, :witness, :incprune, :grid] const ALGORITHM = [:none, :domonly, :normal_prune, :epsilon_prune] const INC_PRUNE = [:normal, :restricted_region, :generalized] const FG_TYPE = [:simplex, :pairwise, :search, :initial] const VERBOSITY = [:context, :lp, :global, :timing, :stats, :cmdline, :main, :alpha, :proj, :crosssum, :agenda, :enum, :twopass, :linsup, :witness, :incprune, :lpinterface, :vertexenum, :mdp, :pomdp, :param, :parsimonious, :region, :approx_mcgs, - :zlz_speedup, :finite_grid, :mcgs] + :zlz_speedup, :finite_grid, :mcgs, :none] diff --git a/src/solver.jl b/src/solver.jl index 1ec088c..e95c005 100644 --- a/src/solver.jl +++ b/src/solver.jl @@ -1,185 +1,624 @@ mutable struct POMDPSolveSolver <: Solver - options::Dict{AbstractString, Any} +end + +""" + POMDPSolveSolver(; kwargs...) + +Constructs a `POMDPSolveSolver` object with the specified options. The options correspond to the command-line options for the `pomdp-solve` program, as described in the [POMDP-Solve documentation](http://www.pomdp.org/code/cmd-line.html). + +# Keyword Arguments +- `stdout::Union{Nothing, AbstractString}`: Redirect program's stdout to a file of this name. (default: `nothing`) +- `rand_seed::Union{Nothing, Tuple{Int, Int, Int}}`: Set the random seed for program execution. (default: `nothing`) +- `stat_summary::Bool`: Whether to keep and print internal execution stats. (default: `false`) +- `memory_limit::Int`: Set upper bound memory usage. (default: `-1` which results in no limit) +- `time_limit::Int`: Set upper bound on execution time. (default: `-1` which results in no limit) +- `terminal_values::Union{Nothing,AbstractString}`: Sets the terminal value function (starting point). (default: `nothing`) +- `horizon::Int`: Sets the number of iterations of value iteration. (default: `-1` which results in no limit) +- `discount::Float64`: Set the discount fact to use in value iteration (overrides POMDP discount). (default: `NaN` which doesn't override) +- `stop_criteria::Symbol`: Sets the value iteration stopping criteria. (default: `:default` -> :weak) +- `stop_delta::Float64`: Sets the precision for the stopping criteria check. (default: `NaN` -> 1e-9) +- `save_all::Bool`: Sets whether or not to save every iteration's solution. (default: `false`) +- `vi_variation::Symbol`: Sets the general category of value iteration to use. (default: `:default` -> :normal) +- `start_epsilon::Float64`: Sets the starting precision for adjustable epsilon VI. (default: `NaN`) +- `end_epsilon::Float64`: Sets the ending precision for adjustable epsilon VI. (default: `NaN`) +- `epsilon_adjust::Float64`: Sets the precision increment for adjustable epsilon VI. (default: `NaN`) +- `max_soln_size::Float64`: Sets the max size for the fixed solution size VI. (default: `NaN`) +- `history_length::Int`: Sets history window to use for adjustable epsilon VI. (default: `-1` -> do not use) +- `history_delta::Int`: Sets solution size delta to use for adjustable epsilon VI. (default: `-1` -> do not use) +- `dom_check::Bool`: Controls whether simple domination check is done or not. (default: `true`) +- `prune_epsilon::Float64`: Sets the precision level for the prune operations. (default: `NaN` -> 1e-9) +- `epsilon::Float64`: General solution precision level setting. (default: `NaN` -> 1e-9) +- `lp_epsilon::Float64`: Precision use in linear programs. (default: `NaN` -> 1e-9) +- `proj_purge::Symbol`: Type of pruning to use for pre-iteration solving. (default: `:default` -> :normal_prune) +- `q_purge::Symbol`: Type of pruning to use for a post-iteration solving. (default: `:default` -> :normal_prune) +- `witness_points::Bool`: Whether to include 'witness points' in solving. (default: `false`) +- `alg_rand::Int`: How many points to use to seed value function creation. (default: `-1` -> do not use) +- `prune_rand::Int`: How many points to use to seed pruning process. (default: `-1` -> do not use) +- `method::Symbol`: Selects the main solution algorithm to use. (default: `:default` -> :incprune) +- `enum_purge::Symbol`: The pruning method to use when using the 'enum' algorithm. (default: `:default` -> :normal_prune) +- `inc_prune::Symbol`: The variation of the incremental pruning algorithm. (default: `:default` -> normal) +- `fg_type::Symbol`: Finite grid method means to generate belief points. (default: `:default` -> :initial) +- `fg_points::Int`: Maximal number of belief points to use in finite grid. (default: `-1` -> 10000) +- `fg_save::Bool`: Whether to save the points used in finite grid. (default: `false`) +- `mcgs_traj_length::Int`: Trajectory length for Monte Carlo belief generation. (default: `-1` -> 100) +- `mcgs_num_traj::Int`: Number of trajectories for Monte Carlo belief generation. (default: `-1` -> 1000) +- `mcgs_traj_iter_count::Int`: Times to iterate on a trajectory for MCGS method. (default: `-1` -> 100) +- `mcgs_prune_freq::Int`: How frequently to prune during MCGS method. (default: `-1` -> 100) +- `fg_purge::Symbol`: Finite grid method means to prune value functions. (default: `:default` -> :normal_prune) +- `verbose::Bool`: Turns on extra debugging output for a module. (default: `:default`) + +# More detailed description of options +These are descriptions taken from the [POMDP-Solve documentation](http://www.pomdp.org/code/cmd-line.html). + +## `stdout::Union{Nothing, AbstractString}` +The pomdp-solve program displays much status and progress +information to stdout. If you want to have this redirected to a file +instead, provide the file name as this parameter. Not specifying +this option will simply make this information go to normal stdout. + +## `rand_seed::Union{Nothing, Tuple{Int,Int,Int}}` +For any functionality that requires random numbers, we want to be +able to reproduce a given run by executing with the same random +number seed. This parameter allows you to set the initial random +seed by specifying a string consisting of three integers separated by +a colon (e.g., "34523:12987:50732" ) Not setting this value will +result in the random seed being pseudo-randomized based on the system +clock. + +## `stat_summary::Bool` +The pomdp-solve program is capable of keeping various statistical +information as it solves the problem. If you want to track these +stats and print them, set this flag to true. + +## `memory_limit::Int` +*_This option has not been tested successfully using the jll package._* + +This parameter allows you to set an upper bound on the amount of +memory that this program uses. If the memory threshold is met, the +program execution is terminated. Without specifying this +parameter, there will be no upper bound imposed by the pomdp-solve +program (though the OS will naturally have something to say about +this). + +## `time_limit::Int` +This parameter allows you to set an upper bound on the amount of +time that this program will run. When this amount of time has +elapsed, the program execution is terminated. Without specifying +this parameter, there will be no upper bound imposed by the pomdp-solve +program. + +## `terminal_values::Union{Nothing,AbstractString}` +Value iteration assumes that at the end of the lifetime of the +decision maker that no more values will be accrued. This corresponds +to a terminal value function of all zeroes. This is essentially the +default starting point for the program. However, with this parameter, +you can set a different terminal value function, which serves as the +seed or initial starting point for value iteration. Effectively, this +allows you to take the output of one value iteration run and send it +as input to the next. The file format for this input file is +identical to the output file format of this program (the ".alpha" +file). + +## `horizon::Int` +Value iteration is iterative and thus we may want to find 'finite +horizon' solutions for various reasons. To make pomdp-solve terminate +after a fixed number of iterations (aka epochs) set this value to be +some positive number. By default, value iteration will run for as +many iterations as it take to 'converge' on the infinite horizon +solution. + +## `discount::Float64` +_Overrides the POMDP discount factor._ + +This sets the discount factor to use during value iteration which +dictates the relative usefulness of future rewards compared to +immediate rewards. + +## `stop_criteria::Symbol` +At the end of each epoch of value iteration, a check is done to +see whether the solutions have 'converged' to the (near) optimal +infinite horizon solution. there are more than one way to determine +this stopping condition. The exact semantics of each are not +described here at this time. + +Options: `:exact`, `:weak`, `:bellman` + +## `stop_delta::Float64` +When checking the stopping criteria at the end of each value +iteration epoch, some of the stopping condition types use a +tolerance/precision in their calculations. This parameter allows you +to set that precision. + +## `save_all::Bool` +Normally, only the final solution is saved to a file, but if you +would like to write out the solution to every epoch of value +iteration, then set this flag to true. The epoch number will be +appened to the filenames that are output. + +## `vi_variation::Symbol` +Independent of particular algortihms for computing one iteration +of value iteration are a number of variations of value iteration meant +to help speed up convergence. We do not yet attempt to give a full +description of the semantics of each here. + +Options: `:normal`, `:zlz`, `:adjustable_epsilon`, `:fixed_soln_size` + +## `start_epsilon::Float64` +When solving using the 'adjustable_epsilon' method of value +iteration, we need to specify both a staring and ending precision. +This is the starting precision. + +## `end_epsilon::Float64` +When solving using the 'adjustable_epsilon' method of value +iteration, we need to specify both a staring and ending precision. +This is the ending precision. + +## `epsilon_adjust::Float64` +When solving using the 'adjustable_epsilon' method of value +iteration, we need to specify a staring and ending precision as +well as the increment to use for each adjustment. +This is the precision increment. + +## `max_soln_size::Float64` +When solving using the 'fixed_soln_size' method we need to define +what the maximal size of a soltuion we will tolerate. This sets that +limit. + +## `history_length::Int` +When using the 'adjustable_epsilon' value iteration variant, we +need to compare solution sizes from the the rpevious epochs to see +whethere or not the solutions are staying relatively constant in +size. To do this, we need to define a past window length, as well as +a tolerance on how much variation in solution size we want to care +about. This parameter defines the length of the epoch window history +to use when determining whether it is time to adjust the precision of +the value iteration solution. + +## `history_delta::Int` +When using the 'adjustable_epsilon' value iteration variant, we +need to compare solution sizes from the the previous epochs to see +whether or not the solutions are staying relatively constant in +size. To do this, we need to define a past window length, as well as +a tolerance on how much variation in solution size we want to care +about. This parameter defines the tolerance on what we will +consider all solutions to be of the same size. + +## `dom_check::Bool` +check that can be done to discover useless components of a value +function. This is often useful, but there are circumstances in which +it is best to turn this off. + +## `prune_epsilon::Float64` +There are a number of ways to prune sets of value function +components. Each uses a precision actor which is this parameter. + +## `epsilon::Float64` +This is the main precision setting parameter which will effect the +preciseness fo the solution procedures. + +## `lp_epsilon::Float64` +Many solution procedures employ linear programming in their +algorithms. For those that do, thisk is the precision level used +inside the linear programming routines. + +## `proj_purge::Symbol` +The first step for most algorithms is to compute the forward +projection of the previous iteration solution components. +Combinations of these will comprise the current solution. Prior +to emplying any algorithm to find which combinations are needed (the +heart of the POMDP solution algorithms) we can employ a process of +pruning the projected set, often reducing the complexity of the +algorithms. This parameter decides what type of pruning to use at +this step. Details on the semantics of each type of pruning are not +yet given here. + +Options: `:none`, `:domonly`, `:normal_prune`, `:epsilon_prune` + +## `q_purge::Symbol` +Some algorithms will separately solve the problem for individual +actions, then merge these results together. The individual action +solutions are referred to as the "Q-functions". After merging, some +pruning process will likely take place, but we can also choose to do a +pre-merge pruning of these sets which often simplifies the merging +process. This parameter defines the method to use for this pre-merge +pruning. + +Options: `:none`, `:domonly`, `:normal_prune`, `:epsilon_prune` + +## `witness_points::Bool` +Keeping 'witness points' means to track individual points that +have been found that gave rise to individual value function +components. These can often be used to help speed up the solution +process. + +## `alg_rand::Int` +One can speed up the discovery of the initial shape of the value +function by randomly generating points and finding the value function +components needed for those points. This technique is used if this +parameter has a non-zero value. + +## `prune_rand::Int` +When pruning sets of value function components, we can use a +random set of points to help speed up the pruning process. This +parameter, if specified and non-zero, will define the number of random +points to use in this way. + +## `method::Symbol` +The pomdp-solve program implements a number of differnt +algorithms. This selects the one that should be used. Details of +each method not yet provided here. + +Options: `:enum`, `:twopass`, `:linsup`, `:witness`, `:incprune`, `:grid`, `:mcgs` + +## `enum_purge::Symbol` +When using the enumeration method, there will be times where the +set of value function components will need to be pruned or purged of +useless components. This define the pruning method to use for this +algorithm. + +Options: `:none`, `:domonly`, `:normal_prune`, `:epsilon_prune` + +## `inc_prune::Symbol` +The incremental pruning algorithm has a number of variations. +This parameter selects the variation. We do not yet discuss here the +nuances of these variations. + +Options: `:normal`, `:restricted_region`, `:generalized` + +## `fg_type::Symbol` +The finite grid method needs a set of belief points to compute +over. There are a number of ways to generate this grid, and this +parameter selects the technique to use. We do not yet here discuss +the details of each of these. + +Options: `:simplex`, `:pairwise`, `:search`, `:initial` + +## `fg_points::Int` +The finite grid method needs a set of belief points to compute +over. There are a number of ways to generate this grid, and this +parameter selects the maximum number of points that should be +generated during this process. + +## `fg_save::Bool` +The finite grid method needs a set of belief points to compute +over. This parameter will turn on and off the saving of these +belief points to an external file. + +## `mcgs_traj_length::Int` +The Monte-Carlo, Gauss-Seidel method using trajectories through the +belief space to lay down a grid of points that we will compute the +optimal value funciton for. This parameter defines the lengths of +the trajectories. + +## `mcgs_num_traj::Int` +The Monte-Carlo, Gauss-Seidel method using trajectories through the +belief space to lay down a grid of points that we will compute the +optimal value funciton for. This parameter defines the number of +trajectories to use. + +## `mcgs_traj_iter_count::Int` +The Monte-Carlo, Gauss-Seidel method using trajectories through the +belief space to lay down a grid of points that we will compute the +optimal value funciton for. This parameter defines the number of +value function update iterations to use on a given set of +trajectories. + +## `mcgs_prune_freq::Int` +The Monte-Carlo, Gauss-Seidel method using trajectories through the +belief space to lay down a grid of points that we will compute the +optimal value funciton for. This parameter defines how frequently +we should prune the set of newly created value function facets +during the generation of the value function points. + +## `fg_purge::Symbol` +Defines the technique to use during pruning when the finite grid +method is being used. + +Options: `:none`, `:domonly`, `:normal_prune`, `:epsilon_prune` + +## `verbose::Bool` +Each main module of pomdp-solve can be separately controlled as +far as extra debugging output is concerned. This option can be used +more than once to turn on debugging in more than one module. - function POMDPSolveSolver(; - stdout::Union{Nothing,AbstractString} = nothing, # Redirect programs stdout to a file of this name - rand_seed::Union{Nothing, Tuple{Int,Int,Int}} = nothing, # Set the random seed for program execution - stat_summary::Bool = false, # Whether to keep and print internal execution stats - memory_limit::Int = -1, # Set upper bound memory usage - time_limit::Int = -1, # Set upper bound on execution time - terminal_values::Union{Nothing,AbstractString}=nothing, # Sets the terminal value function (starting point.) - horizon::Int = -1, # Sets the number of iterations of value iteration - discount::Float64 = NaN, # Set the discount fact to use in value iteration - stop_criteria::Symbol = :default, # Sets the value iteration stopping criteria - stop_delta::Float64 = NaN, # Sets the precision for the stopping criteria check - save_all::Bool = false, # Sets whether or not to save every iteration's solution - vi_variation::Symbol = :default, # Sets the general category of value iteration to use - start_epsilon::Float64 = NaN, # Sets the starting precision for adjustable epsilon VI - end_epsilon::Float64 = NaN, # Sets the ending precision for adjustable epsilon VI - epsilon_adjust::Float64 = NaN, # Sets the precision increment for adjustable epsilon VI - max_soln_size::Float64 = NaN, # Sets the max size for the fixed solution size VI - history_length::Int = -1, # Sets history window to use for adjustable epsilon VI - history_delta::Int = -1, # Sets solution size delta to use for adjustable epsilon VI - dom_check::Bool = true, # Controls whether simple domination check is done or not - prune_epsilon::Float64 = NaN, # Sets the precision level for the prune operations - epsilon::Float64 = NaN, # General solution precision level setting - lp_epsilon::Float64 = NaN, # Precision use in linear programs - proj_purge::Symbol = :default, # Type of pruning to use for pre-iteration solving - q_purge::Symbol = :default, # Type of pruning to use for a post-iteration solving - witness_points::Bool = false, # Whether to include 'witness points' in solving - alg_rand::Int = -1, # How many points to use to seed value function creation - prune_rand::Int = -1, # How many points to use to seed pruning process - method::Symbol = :default, # Selects the main solution algorithm to use - enum_purge::Symbol = :default, # The pruning method to use when using the 'enum' algorithm - inc_prune::Symbol = :default, # The variation of the incremental pruning algorithm - fg_type::Symbol = :default, # Finite grid method means to generate belief points - fg_points::Int = -1, # Maximal number of belief points to use in finite grid - fg_save::Bool = false, # Whether to save the points used in finite grid - mcgs_traj_length::Int = -1, # Trajectory length for Monte Carlo belief generation - mcgs_num_traj::Int = -1, # Number of trajectories for Monte Carlo belief generation - mcgs_traj_iter_count::Int = -1, # Times to iterate on a trajectory for MCGS method - mcgs_prune_freq::Int = -1, # How frequently to prune during MCGS method - fg_purge::Symbol = :default, # Finite grid method means to prune value functions - verbose::Symbol = :default, # Turns on extra debugging output for a module - ) - - options = Dict{AbstractString, Any}() - - if isa(stdout, AbstractString) - options["stdout"] = stdout - end - if isa(rand_seed, Tuple{Int,Int,Int}) - options["rand_seed"] = @sprintf("%d:%d:%d", rand_seed...) - end - if stat_summary - options["stat_summary"] = stat_summary - end - if memory_limit > 0 - options["memory_limit"] = memory_limit - end - if time_limit > 0 - options["time_limit"] = time_limit - end - if isa(terminal_values, AbstractString) - options["terminal_values"] = terminal_values - end - if horizon > 0 - options["horizon"] = horizon - end - if !isnan(discount) - options["discount"] = discount - end - if in(stop_criteria, STOP_CRITERIA) - options["stop_criteria"] = stop_criteria - end - if !isnan(stop_delta) - options["stop_delta"] = stop_delta - end - if save_all - options["save_all"] = save_all - end - if in(vi_variation, VI_VARIATION) - options["vi_variation"] = vi_variation - end - if !isnan(start_epsilon) - options["start_epsilon"] = start_epsilon - end - if !isnan(end_epsilon) - options["end_epsilon"] = end_epsilon - end - if !isnan(epsilon_adjust) - options["epsilon_adjust"] = epsilon_adjust - end - if !isnan(max_soln_size) - options["max_soln_size"] = max_soln_size - end - if history_length > 0 - options["history_length"] = history_length - end - if history_delta > 0 - options["history_delta"] = history_delta - end - if !dom_check - options["dom_check"] = dom_check - end - if !isnan(prune_epsilon) - options["prune_epsilon"] = prune_epsilon - end - if !isnan(epsilon) - options["epsilon"] = epsilon - end - if !isnan(lp_epsilon) - options["lp_epsilon"] = lp_epsilon - end - if in(proj_purge, ALGORITHM) - options["proj_purge"] = proj_purge - end - if in(q_purge, ALGORITHM) - options["q_purge"] = q_purge - end - if witness_points - options["witness_points"] = witness_points - end - if alg_rand ≥ 0 - options["alg_rand"] = alg_rand - end - if prune_rand ≥ 0 - options["prune_rand"] = prune_rand - end - if in(method, METHOD) - options["method"] = method - end - if in(enum_purge, ALGORITHM) - options["enum_purge"] = enum_purge - end - if in(inc_prune, INC_PRUNE) - options["inc_prune"] = inc_prune - end - if in(fg_type, FG_TYPE) - options["fg_type"] = fg_type - end - if fg_points > 0 - options["fg_points"] = fg_points - end - if fg_save - options["fg_save"] = fg_save - end - if mcgs_traj_length > 0 - options["mcgs_traj_length"] = mcgs_traj_length - end - if mcgs_num_traj > 0 - options["mcgs_num_traj"] = mcgs_num_traj - end - if mcgs_traj_iter_count > 0 - options["mcgs_traj_iter_count"] = mcgs_traj_iter_count - end - if mcgs_prune_freq > 0 - options["mcgs_prune_freq"] = mcgs_prune_freq - end - if in(fg_purge, ALGORITHM) - options["fg_purge"] = fg_purge - end - if in(verbose, VERBOSITY) - options["verbose"] = verbose - end - - new(options) - end +The `:none` options is a julia specific option that turns off all output using Suppressor.jl. + +Options: `:context`, `:lp`, `:global`, `:timing`, `:stats`, `:cmdline`, `:main`, `:alpha`, `:proj`, + `:crosssum`, `:agenda`, `:enum`, `:twopass`, `:linsup`, `:witness`, `:incprune`, `:lpinterface`, + `:vertexenum`, `:mdp`, `:pomdp`, `:param`, `:parsimonious`, `:region`, `:approx_mcgs`, + `:zlz_speedup`, `:finite_grid`, `:mcgs`, `:none` +""" +function POMDPSolveSolver(; + stdout::Union{Nothing, AbstractString} = nothing, + rand_seed::Union{Nothing, Tuple{Int,Int,Int}} = nothing, + stat_summary::Bool = false, + memory_limit::Int = -1, + time_limit::Int = -1, + terminal_values::Union{Nothing,AbstractString}=nothing, + horizon::Int = -1, + discount::Float64 = NaN, + stop_criteria::Symbol = :default, + stop_delta::Float64 = NaN, + save_all::Bool = false, + vi_variation::Symbol = :default, + start_epsilon::Float64 = NaN, + end_epsilon::Float64 = NaN, + epsilon_adjust::Float64 = NaN, + max_soln_size::Float64 = NaN, + history_length::Int = -1, + history_delta::Int = -1, + dom_check::Bool = true, + prune_epsilon::Float64 = NaN, + epsilon::Float64 = NaN, + lp_epsilon::Float64 = NaN, + proj_purge::Symbol = :default, + q_purge::Symbol = :default, + witness_points::Bool = false, + alg_rand::Int = -1, + prune_rand::Int = -1, + method::Symbol = :default, + enum_purge::Symbol = :default, + inc_prune::Symbol = :default, + fg_type::Symbol = :default, + fg_points::Int = -1, + fg_save::Bool = false, + mcgs_traj_length::Int = -1, + mcgs_num_traj::Int = -1, + mcgs_traj_iter_count::Int = -1, + mcgs_prune_freq::Int = -1, + fg_purge::Symbol = :default, + verbose::Symbol = :default, +) + + options = Dict{AbstractString, Any}() + + if !isnothing(stdout) + options["stdout"] = stdout + end + + if !isnothing(rand_seed) + options["rand_seed"] = @sprintf("%d:%d:%d", rand_seed...) + end + + if stat_summary + options["stat_summary"] = stat_summary + end + + if memory_limit > 0 + @warn """memory_limit has not been tested successfully using the jll package. Use at your own risk. + Recommend using `time_limit` and/or `horizon` options instead. + """ + options["memory_limit"] = memory_limit + end + + if time_limit > 0 + options["time_limit"] = time_limit + end + + if !isnothing(terminal_values) + options["terminal_values"] = terminal_values + end + + if horizon > 0 + options["horizon"] = horizon + end + + if !isnan(discount) + @assert discount ≥ 0 && discount ≤ 1 "discount must be ∈ [0,1]" + options["discount"] = discount + end + + if in(stop_criteria, STOP_CRITERIA) + options["stop_criteria"] = stop_criteria + elseif stop_criteria != :default + invalid_option_error("stop_criteria", stop_criteria, STOP_CRITERIA) + end + + if !isnan(stop_delta) + @assert stop_delta ≥ 0.0 "stop_delta must be greater than or equal to 0.0" + options["stop_delta"] = stop_delta + end + + if save_all + options["save_all"] = save_all + end + + if in(vi_variation, VI_VARIATION) + options["vi_variation"] = vi_variation + elseif vi_variation != :default + invalid_option_error("vi_variation", vi_variation, VI_VARIATION) + end + + if !isnan(start_epsilon) + @assert start_epsilon ≥ 0.0 "start_epsilon must be greater than or equal to 0.0" + options["start_epsilon"] = start_epsilon + end + + if !isnan(end_epsilon) + @assert end_epsilon ≥ 0.0 "end_epsilon must be greater than or equal to 0.0" + options["end_epsilon"] = end_epsilon + end + + if !isnan(epsilon_adjust) + @assert epsilon_adjust ≥ 0.0 "epsilon_adjust must be greater than or equal to 0.0" + options["epsilon_adjust"] = epsilon_adjust + end + + if !isnan(max_soln_size) + @assert max_soln_size ≥ 0.0 "max_soln_size must be greater than or equal to 0.0" + options["max_soln_size"] = max_soln_size + end + + if history_length > 0 + options["history_length"] = history_length + end + + if history_delta > 0 + options["history_delta"] = history_delta + end + + if !dom_check + options["dom_check"] = dom_check + end + + if !isnan(prune_epsilon) + @assert prune_epsilon ≥ 0.0 "prune_epsilon must be greater than or equal to 0.0" + options["prune_epsilon"] = prune_epsilon + end + + if !isnan(epsilon) + @assert epsilon ≥ 0.0 "epsilon must be greater than or equal to 0.0" + options["epsilon"] = epsilon + end + + if !isnan(lp_epsilon) + @assert lp_epsilon ≥ 0.0 "lp_epsilon must be greater than or equal to 0.0" + options["lp_epsilon"] = lp_epsilon + end + + if in(proj_purge, ALGORITHM) + options["proj_purge"] = proj_purge + elseif proj_purge != :default + invalid_option_error("proj_purge", proj_purge, ALGORITHM) + end + + if in(q_purge, ALGORITHM) + options["q_purge"] = q_purge + elseif q_purge != :default + invalid_option_error("q_purge", q_purge, ALGORITHM) + end + + if witness_points + options["witness_points"] = witness_points + end + + if alg_rand ≥ 0 + options["alg_rand"] = alg_rand + end + + if prune_rand ≥ 0 + options["prune_rand"] = prune_rand + end + + if in(method, METHOD) + if method == :linsup + @info "The linsup method requires CPLEX." + elseif method == :grid + @warn "The grid method requires a .belief file to be generated and this process is not currently automated in POMDPSolve.jl or POMDPFiles.jl." + end + options["method"] = method + elseif method != :default + if method == :mcgs + throw(ArgumentError("The mcgs method is not implmented in 5.4.1.")) + end + invalid_option_error("method", method, METHOD) + end + + if in(enum_purge, ALGORITHM) + options["enum_purge"] = enum_purge + elseif enum_purge != :default + invalid_option_error("enum_purge", enum_purge, ALGORITHM) + end + + if in(inc_prune, INC_PRUNE) + options["inc_prune"] = inc_prune + elseif inc_prune != :default + invalid_option_error("inc_prune", inc_prune, INC_PRUNE) + end + + if in(fg_type, FG_TYPE) + options["fg_type"] = fg_type + elseif fg_type != :default + invalid_option_error("fg_type", fg_type, FG_TYPE) + end + + if fg_points > 0 + options["fg_points"] = fg_points + end + + if fg_save + options["fg_save"] = fg_save + end + + if mcgs_traj_length > 0 + options["mcgs_traj_length"] = mcgs_traj_length + end + + if mcgs_num_traj > 0 + options["mcgs_num_traj"] = mcgs_num_traj + end + + if mcgs_traj_iter_count > 0 + options["mcgs_traj_iter_count"] = mcgs_traj_iter_count + end + + if mcgs_prune_freq > 0 + options["mcgs_prune_freq"] = mcgs_prune_freq + end + + if in(fg_purge, ALGORITHM) + options["fg_purge"] = fg_purge + elseif fg_purge != :default + invalid_option_error("fg_purge", fg_purge, ALGORITHM) + end + + if in(verbose, VERBOSITY) + options["verbose"] = verbose + elseif verbose != :default + invalid_option_error("verbose", verbose, VERBOSITY) + end + + return POMDPSolveSolver(options) end +""" + POMDPSolveHelp() + +This function runs the `pomdpsolve` command with the `-h` option, which displays help information for `pomdpsolve`. +""" +function POMDPSolveHelp() + try + run(`$(pomdpsolve()) -h`) + catch err + if !isa(err, ProcessFailedException) + rethrow() + end + end +end + +""" + POMDPs.solve(solver::POMDPSolveSolver, pomdp::POMDP) + +Solves the given `pomdp` using the `pomdpsolve` program and`AlphaVectorPolicy`. The solver +depends on translating the POMDP to the `.pomdp` file format. Please reference POMDPFiles.jl +for any issues with the translation. +""" function POMDPs.solve(solver::POMDPSolveSolver, pomdp::POMDP) + # Check for verbose option of :none + verbose_override = false + if haskey(solver.options, "verbose") + if solver.options["verbose"] == :none + verbose_override = true + end + end + fileprefix = tempname() pomdp_filename = fileprefix*".pomdp" open(pomdp_filename, "w") do f write(f, pomdp) end - if isempty(solver.options) - run(`$(pomdpsolve()) -pomdp $(pomdp_filename) -o $(fileprefix)`) - else + run_cmd = `$(pomdpsolve()) -pomdp $(pomdp_filename) -o $(fileprefix)` + if !isempty(solver.options) options_list = _get_options_list(solver.options) - run(`$(pomdpsolve()) -pomdp $(pomdp_filename) -o $(fileprefix) $options_list`) + run_cmd = `$(run_cmd) $options_list` + end + + if verbose_override + @suppress run(run_cmd) + else + run(run_cmd) end alpha_vectors, alpha_actions = read_alpha(fileprefix * ".alpha") diff --git a/src/utils.jl b/src/utils.jl index ccff7d1..973a281 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,10 +1,42 @@ # returns the list of solver command-line options function _get_options_list(options::Dict{AbstractString,Any}) - options_list = Array{AbstractString}(undef, 2*length(options)) + vec_len = 2 * length(options) + if "verbose" in keys(options) && options["verbose"] == :none + vec_len -= 2 + end + options_list = Array{AbstractString}(undef, vec_len) count = 0 for (k,v) in options + if k == "verbose" && v == :none + continue + end options_list[count+=1] = "-" * k options_list[count+=1] = string(v) end - options_list[1:count] + return options_list[1:count] +end + +""" + invalid_option_error(option::AbstractString, option_selected::Symbol, option_constant::Vector) + +Formats and throws an error for an invalid option. +""" +function invalid_option_error( + option::AbstractString, option_selected::Symbol, option_constant::Vector +) + err = ArgumentError("""Invalid $option=:$option_selected option selected. + Valid options are: \n\t:default\n$(list_options(option_constant)) + """) + throw(err) +end + +""" + list_options(option_constant::Vector) + +Takes the list of options and returns a string of them separated by new line characters. +""" +function list_options(option_constant::Vector) + # Prepend a colon to each option to appear as a Symbol + option_constant = ["\t:" * String(option) for option in option_constant] + return join(option_constant, "\n") end From afca16cd3b0e14e0e7d55aeacee1fd44b18295ef Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Sat, 23 Dec 2023 15:00:30 -0700 Subject: [PATCH 05/21] added tests --- test/runtests.jl | 248 ++++++++++++++++++++++++++++++----------------- 1 file changed, 159 insertions(+), 89 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index fce3d41..ab1cf90 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -16,15 +16,124 @@ using NativeSARSOP using Suppressor using Test + +@testset "POMDPSolve Wrapper" begin + @testset "Options" begin + # Option list formatting + options = Dict{AbstractString, Any}() + options["A"] = "optionA" + options["B"] = 2 + order1 = POMDPSolve._get_options_list(options) == ["-A", "optionA", "-B", "2"] + order2 = POMDPSolve._get_options_list(options) == ["-B", "2", "-A", "optionA"] + @test order1 || order2 + options = Dict{AbstractString, Any}() + options["verbose"] = :none + options["A"] = "optionA" + @test POMDPSolve._get_options_list(options) == ["-A", "optionA"] + + @test_throws ArgumentError POMDPSolve.invalid_option_error("option", :invalid, [:valid]) + @test POMDPSolve.list_options([:valid]) == "\t:valid" + end + + @testset "Constructor" begin + println("grid method and memory_limit warnings are expected") + + @test_warn "memory_limit has not been" POMDPSolveSolver(; memory_limit=1) + @test_throws AssertionError POMDPSolveSolver(; discount = 1.1) + @test_throws AssertionError POMDPSolveSolver(; discount = -0.1) + @test_throws ArgumentError POMDPSolveSolver(; stop_criteria = :invalid) + @test_throws AssertionError POMDPSolveSolver(; stop_delta = -0.1) + @test_throws ArgumentError POMDPSolveSolver(; vi_variation = :invalid) + @test_throws AssertionError POMDPSolveSolver(; start_epsilon = -0.1) + @test_throws AssertionError POMDPSolveSolver(; end_epsilon = -0.1) + @test_throws AssertionError POMDPSolveSolver(; epsilon_adjust = -0.1) + @test_throws AssertionError POMDPSolveSolver(; max_soln_size = -0.1) + @test_throws AssertionError POMDPSolveSolver(; prune_epsilon = -0.1) + @test_throws AssertionError POMDPSolveSolver(; epsilon = -0.1) + @test_throws AssertionError POMDPSolveSolver(; lp_epsilon = -0.1) + @test_throws ArgumentError POMDPSolveSolver(; proj_purge = :invalid) + @test_throws ArgumentError POMDPSolveSolver(; q_purge = :invalid) + @test_throws ArgumentError POMDPSolveSolver(; method = :invalid) + @test_throws ArgumentError POMDPSolveSolver(; enum_purge = :invalid) + @test_throws ArgumentError POMDPSolveSolver(; inc_prune = :invalid) + @test_throws ArgumentError POMDPSolveSolver(; fg_type = :invalid) + @test_throws ArgumentError POMDPSolveSolver(; fg_purge = :invalid) + @test_throws ArgumentError POMDPSolveSolver(; verbose = :invalid) + + @test_throws ArgumentError POMDPSolveSolver(; method = :mcgs) + @test_warn "The grid method requires a .belief" POMDPSolveSolver(; method = :grid) + + solver = POMDPSolveSolver(; + stdout = "out.txt", + rand_seed = (1,2,3), + stat_summary=true, + memory_limit = 10000, + time_limit = 10000, + terminal_values = "temp_holder_for_test", + horizon = 10, + discount = 0.9, + stop_criteria = :bellman, + stop_delta = 0.01, + save_all = true, + vi_variation = :adjustable_epsilon, + start_epsilon = 0.01, + end_epsilon = 0.02, + epsilon_adjust = 0.01, + max_soln_size = 1000.0, + history_length = 2, + history_delta = 1, + dom_check = false, + prune_epsilon = 1e-6, + epsilon = 1e-6, + lp_epsilon = 1e-6, + proj_purge = :none, + q_purge = :domonly, + witness_points = true, + alg_rand = 10, + prune_rand = 10, + method = :grid, + enum_purge = :epsilon_prune, + inc_prune = :generalized, + fg_type = :pairwise, + fg_points = 10, + fg_save = true, + mcgs_traj_length = 2, + mcgs_num_traj = 10, + mcgs_traj_iter_count = 10, + mcgs_prune_freq = 2, + fg_purge = :domonly, + verbose = :cmdline + ) + @test length(solver.options) == 39 + @test solver.options["memory_limit"] == 10000 + @test solver.options["time_limit"] == 10000 + @test solver.options["terminal_values"] == "temp_holder_for_test" + @test solver.options["horizon"] == 10 + @test solver.options["enum_purge"] == :epsilon_prune + + end + + pomdp = TigerPOMDP() + solver = POMDPSolveSolver(; verbose=:none) + try + policy = solve(solver, pomdp) + @test true + catch err + @test false + rethrow(err) + end + output = @capture_out test_solver(solver, pomdp) + @test output == "" +end + @testset "Solver jll Test" begin mktempdir() do dir @testset "Tiger" begin - + print("Testing TigerPOMDP...") pomdp = TigerPOMDP() - fname = joinpath(dir, "tiger_test") - run(`$(pomdpsolve()) -pomdp tiger.pomdp -o $fname`) + @suppress run(`$(pomdpsolve()) -pomdp tiger.pomdp -o $fname`) @test isfile(joinpath(dir, "tiger_test.alpha")) @test isfile(joinpath(dir, "tiger_test.pg")) @@ -33,7 +142,7 @@ using Test p1 = AlphaVectorPolicy(pomdp, alpha_vectors, ord_acts[alpha_actions.+1]) @test length(p1.alphas) == 9 - solver = POMDPSolveSolver() + solver = POMDPSolveSolver(; verbose=:none) p2 = solve(solver, pomdp) @test length(p2.alphas) == 9 for (α1, α2) in zip(p1.alphas, p2.alphas) @@ -46,11 +155,12 @@ using Test v_ip = value(p2, initialstate(pomdp)) v_ss = value(p_ss, initialstate(pomdp)) @test isapprox(v_ip, v_ss; atol=1e-3) - + println("done!") end @testset "4x4.95" begin + print("Testing 4x4.95...") fname = joinpath(dir, "4x4.95_test") - run(`$(pomdpsolve()) -pomdp 4x4.95.pomdp -o $fname`) + @suppress run(`$(pomdpsolve()) -pomdp 4x4.95.pomdp -o $fname`) @test isfile(joinpath(dir, "4x4.95_test.alpha")) @test isfile(joinpath(dir, "4x4.95_test.pg")) @@ -59,24 +169,28 @@ using Test alpha_actions = ord_acts[alpha_actions.+1] # All actions should be :down or :left (15th state is bottom left) @test all((alpha_actions .== :down) .| (alpha_actions .== :left)) + println("done!") end @testset "Baby POMDP" begin + print("Testing BabyPOMDP...") pomdp = BabyPOMDP() solver_sarsop = SARSOPSolver() policy_sarsop = solve(solver_sarsop, pomdp) v_sarsop = value(policy_sarsop, initialstate(pomdp)) - solver_ip = POMDPSolveSolver() + solver_ip = POMDPSolveSolver(; verbose=:none) policy_ip = solve(solver_ip, pomdp) v_ip = value(policy_ip, initialstate(pomdp)) @test isapprox(v_sarsop, v_ip; atol=1e-3) + println("done!") end @testset "Stopping Options" begin + print("Testing stopping options...") p = TigerPOMDP() - solver = POMDPSolveSolver(; time_limit=1) + solver = POMDPSolveSolver(; time_limit=1, verbose=:none) start_time = time() policy = solve(solver, p) end_time = time() @@ -89,88 +203,44 @@ using Test end @test occursin("Epoch: 1", output) @test occursin("Epoch: 19", output) - @test !occursin("Epoch: 20", output) + @test !occursin("Epoch: 20", output) + println("done!") end + @testset "Methods" begin + p = TigerPOMDP() + + # NOT TESTING :linsup because it requires CPLEX + # NOT TESTING :grid because it requires a .belief file + + print("Testing :inc_prune on TigerPOMDP...") + solver = POMDPSolveSolver(; method=:incprune, verbose=:none) + policy = solve(solver, p) + v_incprune = value(policy, initialstate(p)) + println("done!") + + print("Testing :enum on TigerPOMDP...") + solver = POMDPSolveSolver(; method=:enum, verbose=:none) + policy = solve(solver, p) + v_enum = value(policy, initialstate(p)) + println("done!") + + print("Testing :witness on TigerPOMDP...") + solver = POMDPSolveSolver(; method=:witness, verbose=:none) + policy = solve(solver, p) + v_witness = value(policy, initialstate(p)) + println("done!") + + print("Testing :twopass on TigerPOMDP with 30 sec timer...") + solver = POMDPSolveSolver(; method=:twopass, time_limit=30, verbose=:none) + policy = solve(solver, p) + v_twopass = value(policy, initialstate(p)) + println("done!") + @test v_twopass > 0.0 + + @test isapprox(v_incprune, v_enum; atol=1e-3) + @test isapprox(v_incprune, v_witness; atol=1e-3) + @test v_incprune > v_twopass + end end - end - - -# show(stdout, MIME("text/plain"), collect(alphapairs(policy))) - -# # test _get_options_list -# options = Dict{AbstractString, Any}() -# options["A"] = "optionA" -# options["B"] = 2 -# println(POMDPSolve._get_options_list(options)) -# @test POMDPSolve._get_options_list(options) == ["-A", "optionA", "-B", "2"] || -# POMDPSolve._get_options_list(options) == ["-B", "2", "-A", "optionA"] - -# # NOTe: following are arbitrarily set, values are probably not useful -# solver2 = POMDPSolveSolver( -# stdout = "out.txt", # Redirect programs stdout to a file of this name -# rand_seed = (1,2,3), # Set the random seed for program execution -# stat_summary=true, # Whether to keep and print internal execution stats -# memory_limit = 10000, # Set upper bound memory usage -# time_limit = 10000, # Set upper bound on execution time -# terminal_values = "???", -# horizon = 10, # Sets the number of iterations of value iteration -# discount = 0.9, # Set the discount fact to use in value iteration -# stop_criteria = :weak, # Sets the value iteration stopping criteria -# stop_delta = 0.01, # Sets the precision for the stopping criteria check -# save_all = true, # Sets whether or not to save every iteration's solution -# vi_variation = :adjustable_epsilon, # Sets the general category of value iteration to use -# start_epsilon = 0.01, # Sets the starting precision for adjustable epsilon VI -# end_epsilon = 0.02, # Sets the ending precision for adjustable epsilon VI -# epsilon_adjust = 0.01, # Sets the precision increment for adjustable epsilon VI -# max_soln_size = 1000.0, # Sets the max size for the fixed solution size VI -# history_length = 2, # Sets history window to use for adjustable epsilon VI -# history_delta = 1, # Sets solution size delta to use for adjustable epsilon VI -# dom_check = false, # Controls whether simple domination check is done or not -# prune_epsilon = 1e-6, # Sets the precision level for the prune operations -# epsilon = 1e-6, # General solution precision level setting -# lp_epsilon = 1e-6, # Precision use in linear programs -# proj_purge = :normal_prune, # Type of pruning to use for pre-iteration solving -# q_purge = :normal_prune, # Type of pruning to use for a post-iteration solving -# witness_points = true, # Whether to include 'witness points' in solving -# alg_rand = 10, # How many points to use to seed value function creation -# prune_rand = 10, # How many points to use to seed pruning process -# method = :normal_prune, # Selects the main solution algorithm to use -# enum_purge = :epsilon_prune, # The pruning method to use when using the 'enum' algorithm -# inc_prune = :generalized, # The variation of the incremental pruning algorithm -# fg_type = :pairwise, # Finite grid method means to generate belief points -# fg_points = 10, # Maximal number of belief points to use in finite grid -# fg_save = true, # Whether to save the points used in finite grid -# mcgs_traj_length = 2, # Trajectory length for Monte Carlo belief generation -# mcgs_num_traj = 10, # Number of trajectories for Monte Carlo belief generation -# mcgs_traj_iter_count = 10, # Times to iterate on a trajectory for MCGS method -# mcgs_prune_freq = 2, # How frequently to prune during MCGS method -# fg_purge = :normal_prune, # Finite grid method means to prune value functions -# verbose = :witness, # Turns on extra debugging output for a module -# ) - -# test_solver(solver, pomdp) - -# @testset "rollout" begin -# m = MiniHallway() - -# p = solve(solver, m) - -# sim = RolloutSimulator() -# for s in states(m) -# ret = simulate(sim, m, p, updater(p), Deterministic(s)) # only need to simulate once since MiniHallway is deterministic -# @test ret ≈ value(p, Deterministic(s)) -# end -# end - -# m = TigerPOMDP() - -# # solver = POMDPSolveSolver(; method=:normal_prune, stop_delta=1e-3, horizon=20) -# solver = POMDPSolveSolver(; time_limit=1, horizon=5) -# # m = MiniHallway() -# p = solve(solver, m) - -# using IncrementalPruning -# solver_ip = PruneSolver(; max_iterations=20, tolerance=1e-3, verbose=true) -# p_ip = solve(solver_ip, m) From 4fbc4a880e2866468be982ab67533ff6ac80a77d Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Sat, 23 Dec 2023 15:03:49 -0700 Subject: [PATCH 06/21] updated POMDPSolve_jll using satements --- src/POMDPSolve.jl | 11 +++-------- test/runtests.jl | 10 +--------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/POMDPSolve.jl b/src/POMDPSolve.jl index 04984e0..503beea 100644 --- a/src/POMDPSolve.jl +++ b/src/POMDPSolve.jl @@ -1,13 +1,6 @@ module POMDPSolve -using Pkg -try - using POMDPSolve_jll -catch - Pkg.add(url="https://github.com/dylan-asmar/POMDPSolve_jll.jl.git") - using POMDPSolve_jll -end - +using POMDPSolve_jll using POMDPs using POMDPTools using POMDPFiles @@ -16,6 +9,8 @@ using Suppressor export POMDPSolveSolver + POMDPSolveHelp + include("constants.jl") include("utils.jl") diff --git a/test/runtests.jl b/test/runtests.jl index ab1cf90..a2c0068 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,13 +1,5 @@ using POMDPSolve - -using Pkg -try - using POMDPSolve_jll -catch - Pkg.add(url="https://github.com/dylan-asmar/POMDPSolve_jll.jl.git") - using POMDPSolve_jll -end - +using POMDPSolve_jll using POMDPs using POMDPModels using POMDPFiles From 86502231065f899755b21cea212b94b44b29ca99 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Sun, 24 Dec 2023 19:12:34 -0700 Subject: [PATCH 07/21] forgot comma on export list --- src/POMDPSolve.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/POMDPSolve.jl b/src/POMDPSolve.jl index 503beea..fcbca0e 100644 --- a/src/POMDPSolve.jl +++ b/src/POMDPSolve.jl @@ -8,7 +8,7 @@ using Printf using Suppressor export - POMDPSolveSolver + POMDPSolveSolver, POMDPSolveHelp From 47f5584e46bd53638cf0a5cddc2af0b05aa9baa6 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Sun, 24 Dec 2023 23:34:48 -0700 Subject: [PATCH 08/21] added POMDPSolve_jll deps and compat --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 025e117..8eee909 100644 --- a/Project.toml +++ b/Project.toml @@ -5,7 +5,7 @@ version = "0.2.3" [deps] POMDPFiles = "9cf5b727-2e06-5671-8c87-8c6b0f729d5d" -POMDPSolve_jll = "7dc2201c-deb4-56f8-b3a0-2ab29a2c732a" # Need to update after registered +POMDPSolve_jll = "7dc2201c-deb4-56f8-b3a0-2ab29a2c732a" POMDPTools = "7588e00f-9cae-40de-98dc-e0c70c48cdd7" POMDPs = "a93abf59-7444-517b-a68a-c42f96afdd7d" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" @@ -13,7 +13,7 @@ Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" [compat] POMDPFiles = "0.2" -# Add compat for POMDPSolve_jll once registered +POMDPSolve_jll = "5.4.1" POMDPTools = "0.1" POMDPs = "0.9" Suppressor = "0.2" From 354aca67318aac1f19bdca852ab2006586dec481 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 01:57:51 -0700 Subject: [PATCH 09/21] gitignore update --- .gitignore | 6 ++---- test/.gitignore | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 test/.gitignore diff --git a/.gitignore b/.gitignore index c516fa0..5220427 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ -*.jl.cov -*.jl.*.cov -*.jl.mem *.alpha *.pg **/.DS_Store .vscode -Manifest.toml \ No newline at end of file +Manifest.toml +docs/build/ \ No newline at end of file diff --git a/test/.gitignore b/test/.gitignore deleted file mode 100644 index ae3dfb4..0000000 --- a/test/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.pg -*.alpha From b74b1bb7f7645c017e2a29b36f8af615c76c1243 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 01:58:04 -0700 Subject: [PATCH 10/21] function name change --- test/runtests.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index a2c0068..28fe787 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,13 +15,13 @@ using Test options = Dict{AbstractString, Any}() options["A"] = "optionA" options["B"] = 2 - order1 = POMDPSolve._get_options_list(options) == ["-A", "optionA", "-B", "2"] - order2 = POMDPSolve._get_options_list(options) == ["-B", "2", "-A", "optionA"] + order1 = POMDPSolve.get_options_list(options) == ["-A", "optionA", "-B", "2"] + order2 = POMDPSolve.get_options_list(options) == ["-B", "2", "-A", "optionA"] @test order1 || order2 options = Dict{AbstractString, Any}() options["verbose"] = :none options["A"] = "optionA" - @test POMDPSolve._get_options_list(options) == ["-A", "optionA"] + @test POMDPSolve.get_options_list(options) == ["-A", "optionA"] @test_throws ArgumentError POMDPSolve.invalid_option_error("option", :invalid, [:valid]) @test POMDPSolve.list_options([:valid]) == "\t:valid" From 25bed228ca00edb1ac16bba0f03e35c13dec76a0 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 01:58:20 -0700 Subject: [PATCH 11/21] added doc strings --- src/solver.jl | 7 ++++++- src/utils.jl | 8 ++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/solver.jl b/src/solver.jl index e95c005..2cb8b50 100644 --- a/src/solver.jl +++ b/src/solver.jl @@ -1,3 +1,8 @@ +""" + POMDPSolveSolver + +Type that holds the options for the `pomdpsolve` program. The options correspond to command-line options for the `pomdp-solve` program. +""" mutable struct POMDPSolveSolver <: Solver options::Dict{AbstractString, Any} end @@ -611,7 +616,7 @@ function POMDPs.solve(solver::POMDPSolveSolver, pomdp::POMDP) run_cmd = `$(pomdpsolve()) -pomdp $(pomdp_filename) -o $(fileprefix)` if !isempty(solver.options) - options_list = _get_options_list(solver.options) + options_list = get_options_list(solver.options) run_cmd = `$(run_cmd) $options_list` end diff --git a/src/utils.jl b/src/utils.jl index 973a281..13b2ddf 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,5 +1,9 @@ -# returns the list of solver command-line options -function _get_options_list(options::Dict{AbstractString,Any}) +""" + get_options_list(options::Dict{AbstractString,Any}) + +Takes a dictionary of options and returns a list of strings of the form "-option value". +""" +function get_options_list(options::Dict{AbstractString,Any}) vec_len = 2 * length(options) if "verbose" in keys(options) && options["verbose"] == :none vec_len -= 2 From b0ad5b6d8100ef4f72b8db98946ea2138e487ed1 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 01:58:40 -0700 Subject: [PATCH 12/21] documentation update --- docs/make.jl | 8 +++++--- docs/src/api.md | 15 +++++++++++++++ docs/src/index.md | 33 ++++++++++++++++++++++++--------- docs/src/reference.md | 12 ------------ 4 files changed, 44 insertions(+), 24 deletions(-) create mode 100644 docs/src/api.md delete mode 100644 docs/src/reference.md diff --git a/docs/make.jl b/docs/make.jl index 739d7e7..8124ee5 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,4 +1,5 @@ using POMDPSolve +using POMDPs using Documenter makedocs(; @@ -7,12 +8,13 @@ makedocs(; format=Documenter.HTML(), pages=[ "Home" => "index.md", - "API Reference" => "reference.md", + "API Reference" => "api.md", ], + checkdocs = :none, ) deploydocs(; repo="github.com/JuliaPOMDP/POMDPSolve.jl.git", devbranch = "master", - devurl = "latest", -) \ No newline at end of file + versions = ["stable" => "v^", "v#.#"] +) diff --git a/docs/src/api.md b/docs/src/api.md new file mode 100644 index 0000000..5df176e --- /dev/null +++ b/docs/src/api.md @@ -0,0 +1,15 @@ +# API Reference + +## Exported Functions +```@docs +POMDPSolveSolver() +POMDPSolveHelp() +POMDPs.solve(::POMDPSolveSolver, pomdp::POMDP) +``` + +## Internal Functions +```@docs +POMDPSolve.get_options_list(::Dict{AbstractString,Any}) +POMDPSolve.invalid_option_error(::AbstractString,::Symbol, ::Vector) +POMDPSolve.list_options(::Vector) +``` \ No newline at end of file diff --git a/docs/src/index.md b/docs/src/index.md index 946801a..d2c7369 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,15 +1,30 @@ -```@meta -CurrentModule = POMDPSolve -``` - # POMPDPSolve.jl -This package is a Julia wrapper for pomdp-solve that interfaces with the POMDPs.jl framework +This is a Julia wrapper for the POMDP-Solve program, orginally developed at Brown University that uses the [POMDPs.jl](https://github.com/JuliaPOMDP/POMDPs.jl) interface. This package uses the [POMDPSolve_jll](https://github.com/JuliaBinaryWrappers/POMDPSolve_jll.jl) package, which was build using modifications from the code available from Tony Cassandra's [pomdp.org page](http://www.pomdp.org/code/index.html). The modfications are available in the [JuliaPOMDP fork of pomdp-solve](https://github.com/JuliaPOMDP/pomdp-solve). + +The pomdp-solve program solves partially observable Markov decision processes (POMDPs), taking a model specification and producing a value function and action policy. It employs many different algorithms, some exact and some approximate. + +Parameters and parameter options are documented in the [`POMDPSolveSolver`](@ref) docstring. If the information cannot be found there, please refer to the JuliaPOMDP fork of pomdp-solve or the original pomdp-solve documentation. +## Installation +You can use the Julia package manager to install POMDPSolve.jl: -## API Reference +```julia +using Pkg +Pkg.add("POMDPSolve") +``` + +## Example -```@contents -Pages = ["reference.md"] -Depth = 2 +```julia +using POMDPSolve +using POMDPModels # for TigerPOMDP +pomdp = TigerPOMDP() +solver = POMDPSolveSolver() +policy = solve(solver, pomdp) # returns an AlphaVectorPolicy ``` + +## Index + +```@index +``` \ No newline at end of file diff --git a/docs/src/reference.md b/docs/src/reference.md deleted file mode 100644 index 94aab4e..0000000 --- a/docs/src/reference.md +++ /dev/null @@ -1,12 +0,0 @@ -# API Reference - -## Index - -```@index -``` - -## Docs - -```@autodocs -Modules = [POMDPSolve] -``` \ No newline at end of file From 2caa6f263104d49116654565b0e2541e367f595c Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 02:03:34 -0700 Subject: [PATCH 13/21] readme updates --- README.md | 508 ++---------------------------------------------------- 1 file changed, 16 insertions(+), 492 deletions(-) diff --git a/README.md b/README.md index 17d5ff6..0219c5d 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # POMDPSolve.jl -[![Build Status](https://github.com/JuliaPOMDP/POMDPSolve.jl/actions/workflows/CI.yml/badge.svg)](https://github.com/JuliaPOMDP/POMDPSolve.jl) -[![Coverage Status](https://codecov.io/gh/JuliaPOMDP/POMDPSolve.jl/badge.svg)](https://coveralls.io/r/JuliaPOMDP/POMDPSolve.jl) +[![CI](https://github.com/JuliaPOMDP/POMDPSolve.jl/actions/workflows/CI.yml/badge.svg)](https://github.com/JuliaPOMDP/POMDPSolve.jl/actions/workflows/CI.yml) +[![codecov.io](http://codecov.io/github/JuliaPOMDP/POMDPSolve.jl/coverage.svg?branch=master)](http://codecov.io/github/JuliaPOMDP/POMDPSolve.jl?branch=master) +[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaPOMDP.github.io/POMDPSolve.jl/stable) +[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaPOMDP.github.io/POMDPSolve.jl/dev) -This is a Julia wrapper for the POMDP-Solve program, orginally developed at Brown University that uses the [POMDPs.jl](https://github.com/JuliaPOMDP/POMDPs.jl) interface. -This package uses the code available from Tony Cassandra's [pomdp.org page](http://www.pomdp.org/code/index.html). +This is a Julia wrapper for the POMDP-Solve program, orginally developed at Brown University that uses the [POMDPs.jl](https://github.com/JuliaPOMDP/POMDPs.jl) interface. This package uses the [POMDPSolve_jll](https://github.com/JuliaBinaryWrappers/POMDPSolve_jll.jl) package, which was build using modifications from the code available from Tony Cassandra's [pomdp.org page](http://www.pomdp.org/code/index.html). The modfications are available in the [JuliaPOMDP fork of pomdp-solve](https://github.com/JuliaPOMDP/pomdp-solve). The pomdp-solve program solves partially observable Markov decision processes (POMDPs), taking a model specification and producing a value @@ -11,506 +12,29 @@ function and action policy. It employs many different algorithms, some exact and some approximate. ## Installation: -After installing [POMDPs.jl](https://github.com/JuliaPOMDP/POMDPs.jl) run the following commands in the Julia REPL: +You can use the Julia package manager to install POMDPSolve.jl: ```julia -] add POMDPSolve +using Pkg +Pkg.add("POMDPSolve") ``` ## Example: ```julia using POMDPSolve -using POMDPModels # this defines TigerPOMDP +using POMDPModels # for TigerPOMDP pomdp = TigerPOMDP() solver = POMDPSolveSolver() -solve(solver, pomdp) # returns an AlphaVectorPolicy +policy = solve(solver, pomdp) # returns an AlphaVectorPolicy ``` ## Parameters: -The following parameters come from http://www.pomdp.org/code/cmd-line.html: +Reference this package documentation for information on parameters. -``` -stdout - type = AbstractString - units = filename - default = STDOUT -``` - -The pomdp-solve program displays much status and progress -information to stdout. If you want to have this redirected to a file -instead, provide the file name as this parameter. Not specifying -this option will simply make this information go to normal STDOUT. - -``` -rand_seed - type = Tuple{Int,Int,Int} - default = init via system time -``` -For any functionality that requires random numbers, we want to be -able to reproduce a given run by executing with the same random -number seed. This parameter allows you to set the initial random -seed by specifying a string consisting of three integers separated by -a colon (e.g., "34523:12987:50732" ) Not setting this value will -result in the random seed being pseudo-randomized based on the system -clock. - -``` -stat_summary - type = Bool - default = false -``` - -The pomdp-solve program is capable of keeping various statistical -information as it solves the problem. If you want to track these -stats and print them, set this flag to true. - -``` -memory_limit - type = Int - units = bytes - valid = 1:typemax(Int) - default = Inf -``` - -This parameter allows you to set an upper bound on the amount of -memory that this program uses. If the memory threshold is met, the -program execution is terminated. Without specifying this -parameter, there will be no upper bound imposed by the pomdp-solve -program (though the OS will naturally have something to say about -this). - -``` -time_limit - type = Int - units = seconds - valid = 1:typemax(Int) - default = Inf -``` - -This parameter allows you to set an upper bound on the amount of -time that this program will run. When this amount of time has -elapsed, the program execution is terminated. Without specifying -this parameter, there will be no upper bound imposed by the pomdp-solve -program. - -``` -terminal_values - type = AbstractString - units = filename - -``` - -Value iteration assumes that at the end of the lifetime of the -decision maker that no more values will be accrued. This corresponds -to a terminal value function of all zeroes. This is essentially the -default starting point for the program. However, with this parameter, -you can set a different terminal value function, which serves as the -seed or initial starting point for value iteration. Effectively, this -allows you to take the output of one value iteration run and send it -as input to the next. The file format for this input file is -identical to the output file format of this program (the ".alpha" -file). - -``` -horizon - type = Int - units = iteration - valid = 1:typemax(Int) - default = run until convergence -``` - -Value iteration is iterative and thus we may want to find 'finite -horizon' solutions for various reasons. To make pomdp-solve terminate -after a fixed number of iterations (aka epochs) set this value to be -some positive number. By default, value iteration will run for as -many iterations as it take to 'converge' on the infinite horizon -solution. - -``` -discount - type = Float64 - valid = (0:1) - default = -1 -``` - -This sets the discount factor to use during value iteration which -dictates the relative usefulness of future rewards compared to -immediate rewards. - -``` -stop_criteria - type = Symbol - valid = {:exact, :weak, :bellman} - default = :weak -``` - -At the end of each epoch of value iteration, a check is done to -see whether the solutions have 'converged' to the (near) optimal -infinite horizon solution. there are more than one way to determine -this stopping condition. The exact semantics of each are not -described here at this time. - -``` -stop_delta - type = Float64 - valid = 0:Inf - default = 1e-9 -``` - -When checking the stopping criteria at the end of each value -iteration epoch, some of the stopping condition types use a -tolerance/precision in their calculations. This parameter allows you -to set that precision. - -``` -save_all - type = Bool - default = false -``` - -Normally, only the final solution is saved to a file, but if you -would like to write out the solution to every epoch of value -iteration, then set this flag to true. The epoch number will be -appened to the filenames that are output. - -``` -vi_variation - type = Symbol - valid = {:normal, :zlz, :adjustable_epsilon, :fixed_soln_size} - default = :normal -``` - -Independent of particular algortihms for computing one iteration -of value iteration are a number of variations of value iteration meant -to help speed up convergence. We do not yet attempt to give a full -description of the semantics of each here. - -``` -start_epsilon - type = Float64 - valid = 0:typemax{Float64} -``` - -When solving using the 'adjustable_epsilon' method of value -iteration, we need to specify both a staring and ending precision. -This is the starting precision. - -``` -end_epsilon - type = Float64 - valid = 0:typemax{Float64} -``` - -When solving using the 'adjustable_epsilon' method of value -iteration, we need to specify both a staring and ending precision. -This is the ending precision. - -``` -epsilon_adjust - type = Float64 - valid = 0:typemax{Float64} -``` - -When solving using the 'adjustable_epsilon' method of value -iteration, we need to specify a staring and ending precision as -well as the increment to use for each adjustment. -This is the precision increment. - -``` -max_soln_size - type = Float64 - valid = 0:typemax{Float64} -``` - -When solving using the 'fixed_soln_size' method we need to define -what the maximal size of a soltuion we will tolerate. This sets that -limit. - -``` -history_length - type = Int - units = epochs - valid = 1:typemax{Int} -``` - -When using the 'adjustable_epsilon' value iteration variant, we -need to compare solution sizes from the the rpevious epochs to see -whethere or not the solutions are staying relatively constant in -size. To do this, we need to define a past window length, as well as -a tolerance on how much variation in solution size we want to care -about. This parameter defines the length of the epoch window history -to use when determining whether it is time to adjust the precision of -the value iteration solution. - -``` -history_delta - type = Int - valid = 1:typemax{Int} -``` - -When using the 'adjustable_epsilon' value iteration variant, we -need to compare solution sizes from the the previous epochs to see -whether or not the solutions are staying relatively constant in -size. To do this, we need to define a past window length, as well as -a tolerance on how much variation in solution size we want to care -about. This parameter defines the tolerance on what we will -consider all solutions to be of the same size. - -``` -dom_check - type = Bool - default = true -``` - -There is a computationally simple, but not precision domination -check that can be done to discover useless components of a value -function. This is often useful, but there are circumstances in which -it is best to turn this off. - -``` -prune_epsilon - type = Float64 - valid = 0:typemax{Float64} - default = 1e-9 -``` - -There are a number of ways to prune sets of value function -components. Each uses a precision actor which is this parameter. - -``` -epsilon - type = Float64 - valid = 0:typemax{Float64} - default = 1e-9 -``` - -This is the main precision setting parameter which will effect the -preciseness for the solution procedures. - -``` -lp_epsilon - type = Float64 - valid = 0:typemax{Float64} - default = 1e-9 -``` - -Many solution procedures employ linear programming in their -algorithms. For those that do, thisk is the precision level used -inside the linear programming routines. - -``` -proj_purge - type = Symbol - valid = {:none, :domonly, :normal_prune, :epsilon_prune} - default = :normal_prune -``` - -The first step for most algorithms is to compute the forward -projection of the previous iteration solution components. -Combinations of these will comprise the current solution. Prior -to emplying any algorithm to find which combinations are needed (the -heart of the POMDP solution algorithms) we can employ a process of -pruning the projected set, often reducing the complexity of the -algorithms. This parameter decides what type of pruning to use at -this step. Details on the semantics of each type of pruning are not -yet given here. - -``` -q_purge - type = Symbol - valid = {:none, :domonly, :normal_prune, :epsilon_prune} - default = :normal_prune -``` - -Some algorithms will separately solve the problem for individual -actions, then merge these results together. The individual action -solutions are referred to as the "Q-functions". After merging, some -pruning process will likely take place, but we can also choose to do a -pre-merge pruning of these sets which often simplifies the merging -process. This parameter defines the method to use for this pre-merge -pruning. - -``` -witness_points - type = Bool - default = false -``` - -Keeping 'witness points' means to track individual points that -have been found that gave rise to individual value function -components. These can often be used to help speed up the solution -process. - -``` -alg_rand - type = Int - units = points - valid = 0:typemax{Int} -``` - -One can speed up the discovery of the initial shape of the value -function by randomly generating points and finding the value function -components needed for those points. This technique is used if this -parameter has a non-zero value. - -``` -prune_rand - type = Int - units = points - valid = 0:typemax{Int} -``` - -When pruning sets of value function components, we can use a -random set of points to help speed up the pruning process. This -parameter, if specified and non-zero, will define the number of random -points to use in this way. - -``` -method - type = Symbol - valid = {:enum, :twopass, :linsup, :witness, :incprune, :grid, :mcgs} - default = :incprune -``` - -The pomdp-solve program implements a number of differnt -algorithms. This selects the one that should be used. Details of -each method not yet provided here. - -``` -enum_purge - type = Symbol - valid = {:none, :domonly, :normal_prune, :epsilon_prune} - default = :normal_prune -``` - -When using the enumeration method, there will be times where the -set of value function components will need to be pruned or purged of -useless components. This define the pruning method to use for this -algorithm. - -``` -inc_prune - type = Symbol - valid = {:normal, :restricted_region, :generalized} - default = :normal -``` - -The incremental pruning algorithm has a number of variations. -This parameter selects the variation. We do not yet discuss here the -nuances of these variations. - -``` -fg_type - type = Symbol - valid = {:simplex, :pairwise, :search, :initial} - default = :initial -``` - -The finite grid method needs a set of belief points to compute -over. There are a number of ways to generate this grid, and this -parameter selects the technique to use. We do not yet here discuss -the details of each of these. - -``` -fg_points - type = Int - valid = 1:typemax{Int} - default = 10000 -``` - -The finite grid method needs a set of belief points to compute -over. There are a number of ways to generate this grid, and this -parameter selects the maximum number of points that should be -generated during this process. - -``` -fg_save - type = Bool - default = false -``` - -The finite grid method needs a set of belief points to compute -over. This parameter will turn on and off the saving of these -belief points to an external file. - -``` -mcgs_traj_length - type = Int - valid = 1:typemax{Int} - default = 100 -``` - -The Monte-Carlo, Gauss-Seidel method using trajectories through the -belief space to lay down a grid of points that we will compute the -optimal value funciton for. This parameter defines the lengths of -the trajectories. - -``` -mcgs_num_traj - type = Int - valid = 1:typemax{Int} - default = 1000 -``` - -The Monte-Carlo, Gauss-Seidel method use trajectories through the -belief space to lay down a grid of points that we will compute the -optimal value funciton for. This parameter defines the number of -trajectories to use. - -``` -mcgs_traj_iter_count - type = Int - valid = 1:typemax{Int} - default = 100 -``` - -The Monte-Carlo, Gauss-Seidel method using trajectories through the -belief space to lay down a grid of points that we will compute the -optimal value funciton for. This parameter defines the number of -value function update iterations to use on a given set of -trajectories. - -``` -mcgs_prune_freq - type = Int - valid = 1:typemax{Int} - default = 100 -``` - -The Monte-Carlo, Gauss-Seidel method using trajectories through the -belief space to lay down a grid of points that we will compute the -optimal value funciton for. This parameter defines how frequently -we should prune the set of newly created value function facets -during the generation of the value function points. - -``` -fg_purge - type = Symbol - valid = {:none, :domonly, :normal_prune, :epsilon_prune} - default = :normal_prune -``` - -Defines the technique to use during pruning when the finite grid -method is being used. - -``` -verbose - type = Symbol - valid = {:context, :lp, :global, :timing, :stats, :cmdline, :main, :alpha, :proj, :crosssum, :agenda, :enum, :twopass, :linsup, :witness, :incprune, :lpinterface, :vertexenum, :mdp, :pomdp, :param, :parsimonious, :region, :approx_mcgs, :zlz_speedup, :finite_grid, :mcgs} -``` - -Each main module of pomdp-solve can be separately controlled as -far as extra debugging output is concerned. This option can be used -more than once to turn on debugging in more than one module. -This input is technically repeatable in pomdp-solve. - -## License - -POMDPSolve.jl uses Tony Cassandra's pomdp-solve [library](http://www.pomdp.org/code/). - -pompd-solve library uses the following external libraries, which have their own licenses: - -- [lp_solve](https://sourceforge.net/projects/lpsolve/) Which has an unclear license (this is an older version for which the source is no longer available). -- [laspack](http://www.netlib.org/utk/misc/sw_survey/urc/html/LASPack.1.html) Which uses a custom license. +## POMDPSolve_jll +The supporting [POMDPSolve_jll](https://github.com/JuliaBinaryWrappers/POMDPSolve_jll.jl) package was created using [BinaryBuilder.jl](https://github.com/JuliaPackaging/BinaryBuilder.jl). The [build_tarballs.jl](https://github.com/JuliaPackaging/Yggdrasil/blob/master/P/POMDPSolve/build_tarballs.jl) script can be found on [Yggdrasil](https://github.com/JuliaPackaging/Yggdrasil/), the community build tree. To update and build new binaries: + - Modify the JuliaPOMDP fork of [pomdp-solve](https://github.com/JuliaPOMDP/pomdp-solve) + - Fork and update the Yggdrasil POMDPSolve_jll [build_tarballs.jl](https://github.com/JuliaPackaging/Yggdrasil/blob/master/P/POMDPSolve/build_tarballs.jl) script + - Create a pull request on [JuliaPackaging/Yggdrasil](https://github.com/JuliaPackaging/Yggdrasil) From 0903e6d7450f5c7fbffb011a8656675e261fee76 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 02:03:48 -0700 Subject: [PATCH 14/21] ci workflow changes/updates --- .github/workflows/CI.yml | 68 +++++++++-------------------- .github/workflows/CompatHelper.yml | 22 +++++++++- .github/workflows/Documentation.yml | 22 ++++++++++ 3 files changed, 63 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/Documentation.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index a8a91e7..4e2a1dd 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,68 +1,42 @@ name: CI - -# Run on master, tags, or any pull request on: push: - branches: [master] - tags: ["*"] + branches: + - master + tags: '*' pull_request: - jobs: - # unit tests with coverage test: - name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: version: - - "1.6" # Latest + - "1" + - "1.6" os: + - ubuntu-latest + - macOS-latest - windows-latest arch: - x64 + - aarch64 + excldue: + - os: ubuntu-latest + arch: aarch64 + - os: windows-latest + arch: aarch64 steps: - # check out the project and install Julia - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - # using a cache can speed up execution times - - uses: actions/cache@v2 - env: - cache-name: cache-artifacts + - uses: julia-actions/cache@v1 + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v3 with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-${{ matrix.arch }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.arch }}-test-${{ env.cache-name }}- - ${{ runner.os }}-${{ matrix.arch }}-test- - ${{ runner.os }}-${{ matrix.arch }}- - ${{ runner.os }}- - - uses: julia-actions/julia-buildpkg@latest - - run: | - git config --global user.name Tester - git config --global user.email te@st.er - - name: Run Tests - uses: julia-actions/julia-runtest@latest - docs: - name: Documentation - runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 - with: - version: '1' - - run: | - julia --project=docs -e ' - using Pkg - Pkg.develop(PackageSpec(path=pwd())) - Pkg.instantiate()' - - run: julia --project=docs docs/make.jl - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} - DOCUMENTER_DEBUG: true \ No newline at end of file + files: lcov.info \ No newline at end of file diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml index 68ca87e..6f52ed5 100644 --- a/.github/workflows/CompatHelper.yml +++ b/.github/workflows/CompatHelper.yml @@ -3,10 +3,29 @@ on: schedule: - cron: 0 0 * * * workflow_dispatch: +permissions: + contents: write + pull-requests: write jobs: CompatHelper: runs-on: ubuntu-latest steps: + - name: Check if Julia is already available in the PATH + id: julia_in_path + run: which julia + continue-on-error: true + - name: Install Julia, but only if it is not already available in the PATH + uses: julia-actions/setup-julia@v1 + with: + version: '1' + arch: ${{ runner.arch }} + if: steps.julia_in_path.outcome != 'success' + - name: "Add the General registry via Git" + run: | + import Pkg + ENV["JULIA_PKG_SERVER"] = "" + Pkg.Registry.add("General") + shell: julia --color=yes {0} - name: "Install CompatHelper" run: | import Pkg @@ -22,5 +41,4 @@ jobs: shell: julia --color=yes {0} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} - # COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }} + COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} \ No newline at end of file diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml new file mode 100644 index 0000000..c16d395 --- /dev/null +++ b/.github/workflows/Documentation.yml @@ -0,0 +1,22 @@ +name: Documentation +on: + push: + branches: + - main + tags: [v*] + pull_request: + +jobs: + build: + permissions: + contents: write + statuses: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v1 + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-docdeploy@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} \ No newline at end of file From 260d988649953d095cc2168da18494bfb9588b95 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 02:04:12 -0700 Subject: [PATCH 15/21] doc deps update --- docs/Project.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Project.toml b/docs/Project.toml index 0180201..f2e7e66 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,3 +1,4 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -POMDPSolve = "a575d7f4-a5df-53f5-8ba4-9d691c1ba8ff" \ No newline at end of file +POMDPSolve = "a575d7f4-a5df-53f5-8ba4-9d691c1ba8ff" +POMDPs = "a93abf59-7444-517b-a68a-c42f96afdd7d" \ No newline at end of file From c0413a4ab7a7af06bb2429c03a219827b68d8edd Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 02:05:20 -0700 Subject: [PATCH 16/21] version bump --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 8eee909..5efa945 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "POMDPSolve" uuid = "a575d7f4-a5df-53f5-8ba4-9d691c1ba8ff" repo = "https://github.com/JuliaPOMDP/POMDPSolve.jl" -version = "0.2.3" +version = "0.3.0" [deps] POMDPFiles = "9cf5b727-2e06-5671-8c87-8c6b0f729d5d" From 371a04d66ac39695b3c250fb91ca629005a50a9f Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 02:07:30 -0700 Subject: [PATCH 17/21] readme update --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0219c5d..f4c6230 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ processes (POMDPs), taking a model specification and producing a value function and action policy. It employs many different algorithms, some exact and some approximate. -## Installation: +## Installation You can use the Julia package manager to install POMDPSolve.jl: ```julia @@ -19,8 +19,7 @@ using Pkg Pkg.add("POMDPSolve") ``` -## Example: - +## Example ```julia using POMDPSolve using POMDPModels # for TigerPOMDP @@ -29,9 +28,8 @@ solver = POMDPSolveSolver() policy = solve(solver, pomdp) # returns an AlphaVectorPolicy ``` -## Parameters: - -Reference this package documentation for information on parameters. +## Parameters +Reference this package documentation for information on parameters and parameter options for the solver. If the information cannot be found there, please refer to the JuliaPOMDP fork of pomdp-solve or the original pomdp-solve documentation. ## POMDPSolve_jll The supporting [POMDPSolve_jll](https://github.com/JuliaBinaryWrappers/POMDPSolve_jll.jl) package was created using [BinaryBuilder.jl](https://github.com/JuliaPackaging/BinaryBuilder.jl). The [build_tarballs.jl](https://github.com/JuliaPackaging/Yggdrasil/blob/master/P/POMDPSolve/build_tarballs.jl) script can be found on [Yggdrasil](https://github.com/JuliaPackaging/Yggdrasil/), the community build tree. To update and build new binaries: From 8bf5191bb979da017fa551719250e8856107a7bb Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 02:16:56 -0700 Subject: [PATCH 18/21] aarch64 removed --- .github/workflows/CI.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 4e2a1dd..341c7c7 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -21,12 +21,6 @@ jobs: - windows-latest arch: - x64 - - aarch64 - excldue: - - os: ubuntu-latest - arch: aarch64 - - os: windows-latest - arch: aarch64 steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v1 From b879ad02a8912357b60c2cd4fc54dee42c96af04 Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 02:28:01 -0700 Subject: [PATCH 19/21] Switched to using SAROP vs NativeSARSOP based on Julia compat for tests --- .gitignore | 4 +++- Project.toml | 4 ++-- test/runtests.jl | 8 +++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 5220427..c53c4ea 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ **/.DS_Store .vscode Manifest.toml -docs/build/ \ No newline at end of file +docs/build/ +test/*.pomdpx +test/*.out \ No newline at end of file diff --git a/Project.toml b/Project.toml index 5efa945..7c3c4d1 100644 --- a/Project.toml +++ b/Project.toml @@ -20,9 +20,9 @@ Suppressor = "0.2" julia = "1.6" [extras] -NativeSARSOP = "a07c76ea-660d-4c9a-8028-2e6dbd212cb8" +SARSOP = "cef570c6-3a94-5604-96b7-1a5e143043f2" POMDPModels = "355abbd5-f08e-5560-ac9e-8b5f2592a0ca" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["POMDPModels", "NativeSARSOP", "Test"] +test = ["POMDPModels", "SARSOP", "Test"] diff --git a/test/runtests.jl b/test/runtests.jl index 28fe787..9f2371e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,7 +4,7 @@ using POMDPs using POMDPModels using POMDPFiles using POMDPTools -using NativeSARSOP +using SARSOP using Suppressor using Test @@ -141,8 +141,9 @@ end @test isapprox(α1, α2; atol=1e-6) end + local p_ss solver_sarsop = SARSOPSolver() - p_ss = solve(solver_sarsop, pomdp) + @suppress p_ss = solve(solver_sarsop, pomdp) v_ip = value(p2, initialstate(pomdp)) v_ss = value(p_ss, initialstate(pomdp)) @@ -168,7 +169,8 @@ end print("Testing BabyPOMDP...") pomdp = BabyPOMDP() solver_sarsop = SARSOPSolver() - policy_sarsop = solve(solver_sarsop, pomdp) + local policy_sarsop + @suppress policy_sarsop = solve(solver_sarsop, pomdp) v_sarsop = value(policy_sarsop, initialstate(pomdp)) solver_ip = POMDPSolveSolver(; verbose=:none) From bc988e7f7a92e0cb1248cb5121278266a814bd2e Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 02:44:41 -0700 Subject: [PATCH 20/21] @test_warn changed to @test_logs for 1.6 tests --- test/runtests.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 9f2371e..85183f9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -30,7 +30,9 @@ using Test @testset "Constructor" begin println("grid method and memory_limit warnings are expected") - @test_warn "memory_limit has not been" POMDPSolveSolver(; memory_limit=1) + @test_logs (:warn, """memory_limit has not been tested successfully using the jll package. Use at your own risk. + Recommend using `time_limit` and/or `horizon` options instead. + """) POMDPSolveSolver(; memory_limit=1) @test_throws AssertionError POMDPSolveSolver(; discount = 1.1) @test_throws AssertionError POMDPSolveSolver(; discount = -0.1) @test_throws ArgumentError POMDPSolveSolver(; stop_criteria = :invalid) @@ -53,7 +55,7 @@ using Test @test_throws ArgumentError POMDPSolveSolver(; verbose = :invalid) @test_throws ArgumentError POMDPSolveSolver(; method = :mcgs) - @test_warn "The grid method requires a .belief" POMDPSolveSolver(; method = :grid) + @test_logs (:warn, "The grid method requires a .belief file to be generated and this process is not currently automated in POMDPSolve.jl or POMDPFiles.jl.") POMDPSolveSolver(; method = :grid) solver = POMDPSolveSolver(; stdout = "out.txt", From 20caae571a9db6ce6c96094637134c9df17aecdf Mon Sep 17 00:00:00 2001 From: Dylan Asmar Date: Mon, 25 Dec 2023 02:53:57 -0700 Subject: [PATCH 21/21] added test for POMDPHelp --- test/runtests.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 85183f9..ea45a6b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -105,6 +105,9 @@ using Test @test solver.options["horizon"] == 10 @test solver.options["enum_purge"] == :epsilon_prune + output = @capture_out POMDPSolveHelp() + @test occursin("-stdout ", output) + @test occursin("-max_soln_size ", output) end pomdp = TigerPOMDP()