diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..bbcba11f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+docs/build/
+docs/site/
diff --git a/.travis.yml b/.travis.yml
index ee8cecd1..9809acf8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,11 @@ julia:
- release
notifications:
email: false
+before_script:
+ - export PATH=$HOME/.local/bin:$PATH
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia --check-bounds=yes -e 'Pkg.clone(pwd()); Pkg.test("POMDPs")'
+after_success:
+ - julia -e 'Pkg.clone("https://github.com/MichaelHatherly/Documenter.jl")'
+ - julia -e 'cd(Pkg.dir("POMDPs")); include(joinpath("docs", "make.jl"))'
diff --git a/README.md b/README.md
index 96cffda3..51a51f0e 100644
--- a/README.md
+++ b/README.md
@@ -4,12 +4,15 @@
This package provides a basic interface for working with partially observable Markov decision processes (POMDPs).
+NEWS: We recently made a significant change to the interface, introducing parametric types (see issue #56). If you wish to continue using the old interface, the v0.1 release may be used, but we recommend that all projects update to the new version.
+
The goal is to provide a common programming vocabulary for researchers and students to use primarily for three tasks:
1. Expressing problems using the POMDP format.
2. Writing solver software.
3. Running simulations efficiently.
+For problems and solvers that only use a generative model (rather than explicit transition and observation distributions), see also [GenerativeModels.jl](https://github.com/JuliaPOMDP/GenerativeModels.jl).
## Installation
```julia
@@ -35,7 +38,6 @@ using POMDPs
POMDPs.add("SARSOP")
```
-
## Tutorials
The following tutorials aim to get you up to speed with POMDPs.jl:
@@ -45,142 +47,6 @@ The following tutorials aim to get you up to speed with POMDPs.jl:
of using SARSOP and QMDP to solve the tiger problem
-## Core Interface
-
-The core interface provides tools to express problems, program solvers, and setup simulations.
-
-**TODO** this list is not complete! there are some functions in src missing documentation that were not included here
-
-
-### Distributions
-
-`AbstractDistribution` - Base type for a probability distribution
-
-- `rand(rng::AbstractRNG, d::AbstractDistribution, sample::Any)` fill with random sample from distribution and return the sample
-- `pdf(d::AbstractDistribution, x)` value of probability distribution function at x
-
-**XXX** There are functions missing from this list that are included in `src/distribution.jl`
-
-### Problem Model
-
-`POMDP` - Base type for a problem definition
-`AbstractSpace` - Base type for state, action, and observation spaces
-`State` - Base type for states
-`Action` - Base type for actions
-`Observation` - Base type for observations
-
-- `states(pomdp::POMDP)` returns the complete state space
-- `states(pomdp::POMDP, state::State, sts::AbstractSpace=states(pomdp))` modifies `sts` to the state space accessible from the given state and returns it
-- `actions(pomdp::POMDP)` returns the complete action space
-- `actions(pomdp::POMDP, state::State, aspace::AbstractSpace=actions(pomdp))` modifies `aspace` to the action space accessible from the given state and returns it
-- `actions(pomdp::POMDP, belief::Belief, aspace::AbstractSpace=actions(pomdp))` modifies `aspace` to the action space accessible from the states with nonzero belief and returns it
-- `observations(pomdp::POMDP)` returns the complete observation space
-- `observations(pomdp::POMDP, state::State, ospace::AbstractSpace)` modifies `ospace` to the observation space accessible from the given state and returns it
-- `reward(pomdp::POMDP, state::State, action::Action, statep::State)` returns the immediate reward for the s-a-s' triple
-- `transition(pomdp::POMDP, state::State, action::Action, distribution=create_transition_distribution(pomdp))` modifies `distribution` to the transition distribution from the current state-action pair and returns it
-- `observation(pomdp::POMDP, state::State, action::Action, statep::State, distribution=create_observation_distribution(pomdp))` modifies `distribution` to the observation distribution for the s-a-s' tuple (state, action, and next state) and returns it
-- `observation(pomdp::POMDP, state::State, action::Action, distribution=create_observation_distribution(pomdp))` modifies `distribution` to the observation distribution for the s-a pair (state and action) and returns it
-- `discount(pomdp::POMDP)` returns the discount factor
-- `isterminal(pomdp::POMDP, state::State)` checks if a state is terminal
-- `isterminal(pomdp::POMDP, observation::Observation)` checks if an observation is terminal. A terminal observation should be generated only upon transition to a terminal state.
-
-**XXX** Missing functions such as `n_states`, `n_actions` (see `src/pomdp.jl`)
-
-### Solvers and Polices
-
-`Solver` - Base type a solver
-`Policy` - Base type for a policy (a map from every possible belief, or more abstract policy state, to an optimal or suboptimal action)
-
-- `solve(solver::Solver, pomdp::POMDP, policy::Policy=create_policy(solver, pomdp))` solves the POMDP and modifies `policy` to be the solution of `pomdp` and returns it
-- `action(policy::Policy, belief::Belief)` or `action(policy::Policy, belief::Belief, act::Action)` returns an action for the current belief given the policy (the method with three arguments modifies `act` and returns it)
-- `action(policy::Policy, state::State)` or `action(policy::Policy, state::State, act::Action)` returns an action for the current state given the policy
-
-### Belief
-
-`Belief` - Base type for an object representing some knowledge about the state (often a probability distribution)
-`BeliefUpdater` - Base type for an object that defines how a belief should be updated
-
-- `update(updater::BeliefUpdater, belief_old::Belief, action::Action, obs::Observation, belief_new::Belief=create_belief(updater))` modifies `belief_new` to the belief given the old belief (`belief_old`) and the latest action and observation and returns the updated belief.
-
-### Simulation
-
-`Simulator` - Base type for an object defining how a simulation should be carried out
-
-- `simulate(simulator::Simulator, pomdp::POMDP, policy::Policy, updater::BeliefUpdater, initial_belief::Belief)` runs a simulation using the specified policy and returns the accumulated reward
-
-## Minor Components
+## Documentation
-### Convenience Functions
-
-Several convenience functions are also provided in the interface to provide standard vocabulary for common tasks and may be used by some solvers or in simulation, but they are not strictly necessary for expressing problems.
-
-- `index(pomdp::POMDP, state::State)` returns the index of the given state for a discrete POMDP
-- `initial_belief(pomdp::POMDP)` returns an example initial belief for the pomdp
-- `iterator(space::AbstractSpace)` returns an iterator over a space or an iterable object containing the space (such as an array)
-- `dimensions(s::AbstractSpace)` returns the number (integer) of dimensions in a space
-- `lowerbound(s::AbstractSpace, i::Int)` returns the lower bound of dimension `i`
-- `upperbound(s::AbstractSpace, i::Int)` returns the upper bound of dimension `i`
-- `rand(rng::AbstractRNG, d::AbstractSpace, sample::Any)` fill with random sample from space and return the sample
-- `value(policy::Policy, belief::Belief)` returns the utility value from policy p given the belief
-- `value(policy::Policy, state::State)` returns the utility value from policy p given the state
-- `convert_belief(updater::BeliefUpdater, b::Belief)` returns a belief that can be updated using `updater` that has a similar distribution to `b` (this conversion may be lossy)
-- `updater(p::Policy)` returns a default BeliefUpdater appropriate for a belief type that policy `p` can use
-
-### Object Creators
-
-In many cases, it is more efficient to fill pre-allocated objects with new data rather than create new objects at each iteration of an algorithm or simulation. When a new object is needed, the following functions may be called. They should return an object of the appropriate type as efficiently as possible. The data in the object does not matter - it will be overwritten when the object is used.
-
-- `create_state(pomdp::POMDP)` creates a single state object (for preallocation purposes)
-- `create_observation(pomdp::POMDP)` creates a single observation object (for preallocation purposes)
-- `create_transition_distribution(pomdp::POMDP)` returns a transition distribution
-- `create_observation_distribution(pomdp::POMDP)` returns an observation distribution
-- `create_policy(solver::Solver, pomdp::POMDP)` creates a policy object (for preallocation purposes)
-- `create_action(pomdp::POMDP)` creates an action object (for preallocation purposes)
-- `create_belief(updater::BeliefUpdater)` creates a belief object of the type used by `updater` (for preallocation purposes)
-- `create_belief(pomdp::POMDP)` creates an empty problem-native belief object (for preallocation purposes)
-
-
-## Reference Simulation Implementation
-
-This reference simulation implementation shows how the various functions will be used. Please note that this example is written for clarity and not efficiency (see [TODO: link to main doc] for efficiency tips).
-
-```julia
-type ReferenceSimulator
- rng::AbstractRNG
- max_steps
-end
-
-function simulate(simulator::ReferenceSimulator, pomdp::POMDP, policy::Policy, updater::BeliefUpdater, initial_belief::Belief)
-
- s = create_state(pomdp)
- o = create_observation(pomdp)
- rand(sim.rng, initial_belief, s)
-
- b = convert_belief(updater, initial_belief)
-
- step = 1
- disc = 1.0
- r = 0.0
-
- while step <= sim.max_steps && !isterminal(pomdp, s)
- a = action(policy, b)
-
- sp = create_state(pomdp)
- trans_dist = transition(pomdp, s, a)
- rand(sim.rng, trans_dist, sp)
-
- r += disc*reward(pomdp, s, a, sp)
-
- obs_dist = observation(pomdp, s, a, sp)
- rand(sim.rng, obs_dist, o)
-
- b = update(updater, b, a, o)
-
- s = sp
- disc *= discount(pomdp)
- step += 1
- end
-
-end
-
-```
+Detailed documentation can be found [here](http://juliapomdp.github.io/POMDPs.jl/latest/).
diff --git a/docs/make.jl b/docs/make.jl
new file mode 100644
index 00000000..b15725ae
--- /dev/null
+++ b/docs/make.jl
@@ -0,0 +1,12 @@
+using Documenter, POMDPs
+
+makedocs(
+ # options
+ modules = [POMDPs]
+)
+
+deploydocs(
+ repo = "github.com/JuliaPOMDP/POMDPs.jl.git",
+ julia = "release",
+ osname = "linux"
+)
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
new file mode 100644
index 00000000..9ae0ffd9
--- /dev/null
+++ b/docs/mkdocs.yml
@@ -0,0 +1,32 @@
+site_name: POMDPs.jl
+repo_url: https://github.com/JuliaPOMDP/POMDPs.jl
+site_description: API for solving partially observable Markov decision processes in Julia.
+site_author: Maxim Egorov
+
+theme: readthedocs
+
+extra:
+ palette:
+ primary: 'indigo'
+ accent: 'blue'
+
+extra_css:
+ - assets/Documenter.css
+
+markdown_extensions:
+ - codehilite
+ - extra
+ - tables
+ - fenced_code
+
+extra_javascript:
+ - https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML
+ - assets/mathjaxhelper.js
+
+docs_dir: 'build'
+
+pages:
+- Home: index.md
+- Manual: guide.md
+- API: api.md
+
diff --git a/docs/src/api.md b/docs/src/api.md
new file mode 100644
index 00000000..b0b31e60
--- /dev/null
+++ b/docs/src/api.md
@@ -0,0 +1,112 @@
+# Solver Documentation
+
+Documentation for the `POMDPs.jl` user interface. You can get help for any type or
+function in the module by typing `?` in the Julia REPL followed by the name of
+type or function. For example:
+
+```julia
+julia>using POMDPs
+julia>?
+help?>reward
+search: reward
+
+ reward{S,A,O}(pomdp::POMDP{S,A,O}, state::S, action::A, statep::S)
+
+ Returns the immediate reward for the s-a-s triple
+
+ reward{S,A,O}(pomdp::POMDP{S,A,O}, state::S, action::A)
+
+ Returns the immediate reward for the s-a pair
+
+```
+
+ {meta}
+ CurrentModule = POMDPs
+
+## Contents
+
+ {contents}
+ Pages = ["api.md"]
+
+## Index
+
+ {index}
+ Pages = ["api.md"]
+
+
+## Types
+
+ {docs}
+ POMDP
+ MDP
+ AbstractSpace
+ AbstractDistribution
+ Solver
+ Policy
+ Belief
+ BeliefUpdater
+
+## Model Functions
+
+ {docs}
+ states
+ actions
+ observations
+ reward
+ transition
+ observation
+ isterminal
+ isterminal_obs
+ n_states
+ n_actions
+ n_observations
+ state_index
+ action_index
+ obs_index
+ discount
+
+## Distribution/Space Functions
+
+ {docs}
+ rand
+ pdf
+ dimensions
+ iterator
+ create_transition_distribution
+ create_observation_distribution
+
+## Belief Functions
+
+ {docs}
+ initial_belief
+ create_belief
+ update
+ convert_belief
+
+## Policy and Solver Functions
+
+ {docs}
+ create_policy
+ solve
+ updater
+ action
+ value
+
+## Simulator
+
+ {docs}
+ Simulator
+ simulate
+
+## Utility Tools
+
+ {docs}
+ add
+ @pomdp_func
+ strip_arg
+
+## Constants
+
+ {docs}
+ REMOTE_URL
+ SUPPORTED_SOLVERS
diff --git a/docs/src/guide.md b/docs/src/guide.md
new file mode 100644
index 00000000..765811fa
--- /dev/null
+++ b/docs/src/guide.md
@@ -0,0 +1,78 @@
+# Package Guide
+
+## Installation
+
+The package can be installed by cloning the code from the github repository
+[POMDPs.jl](https://github.com/JuliaPOMDP/POMDPs.jl)
+
+Installation with POMDPs.jl:
+```julia
+Pkg.clone("https://github.com/JuliaPOMDP/POMDPs.jl.git")
+```
+
+The package is currently not registered in meta-data.
+
+## Usage
+
+POMDPs serves as the interface used by a number of packages under the [JuliaPOMDP]() framework. It is essentially the
+agreed upon API used by all the other packages in JuliaPOMDP. If you are using this framework, you may be trying to
+accomplish one or more of the following three goals:
+
+- Solve a decision or planning problem with stochastic dynamics (MDP) or partial observability (POMDP)
+- Evaluate a solution in simulation
+- Test your custom algorithm for solving MDPs or POMDPs against other state-of-the-art algorithms
+
+If you are attempting to complete the first two goals, take a look at these Jupyer Notebook tutorials:
+
+* [MDP Tutorial](http://nbviewer.ipython.org/github/sisl/POMDPs.jl/blob/master/examples/GridWorld.ipynb) for beginners gives an overview of using Value Iteration and Monte-Carlo Tree Search with the classic grid world problem
+* [POMDP Tutorial](http://nbviewer.ipython.org/github/sisl/POMDPs.jl/blob/master/examples/Tiger.ipynb) gives an overview of using SARSOP and QMDP to solve the tiger problem
+
+If you are trying to write your own algorithm for solving MDPs or POMDPs with this interface take a look at the API
+section of this guide.
+
+## Example Simulation Implementation
+
+
+This reference simulation implementation shows how the various functions will be used. Please note that this example is
+written for clarity and not efficiency.
+
+```julia
+type ReferenceSimulator
+ rng::AbstractRNG
+ max_steps
+end
+
+function simulate(simulator::ReferenceSimulator, pomdp::POMDP, policy::Policy, updater::BeliefUpdater, initial_belief::Belief)
+
+ s = create_state(pomdp)
+ o = create_observation(pomdp)
+ rand(sim.rng, initial_belief, s)
+
+ b = convert_belief(updater, initial_belief)
+
+ step = 1
+ disc = 1.0
+ r = 0.0
+
+ while step <= sim.max_steps && !isterminal(pomdp, s)
+ a = action(policy, b)
+
+ sp = create_state(pomdp)
+ trans_dist = transition(pomdp, s, a)
+ rand(sim.rng, trans_dist, sp)
+
+ r += disc*reward(pomdp, s, a, sp)
+
+ obs_dist = observation(pomdp, s, a, sp)
+ rand(sim.rng, obs_dist, o)
+
+ b = update(updater, b, a, o)
+
+ s = sp
+ disc *= discount(pomdp)
+ step += 1
+ end
+
+end
+
+```
diff --git a/docs/src/index.md b/docs/src/index.md
new file mode 100644
index 00000000..72f88bf7
--- /dev/null
+++ b/docs/src/index.md
@@ -0,0 +1,29 @@
+# POMDPs
+*A Julia interface for defining, solving and simulating partially observable Markov decision processes and their fully
+observable counterparts.*
+
+## Package Features
+
+- General interface that can handle problems with discrete and continuous state/action/observation spaces
+- A number of popular state-of-the-art solvers availiable to use out of the box
+- Tools that make it easy to define problems and simulate solutions
+- Simple integration of custom solvers into the existing interface
+
+## Availible Solvers
+
+The following MDP solvers support this interface:
+
+- [Value Iteration](https://github.com/JuliaPOMDP/DiscreteValueIteration.jl)
+- [Monte Carlo Tree Search](https://github.com/JuliaPOMDP/MCTS.jl)
+
+The following POMDP solvers support this interface:
+
+- [QMDP](https://github.com/JuliaPOMDP/QMDP.jl)
+- [SARSOP](https://github.com/JuliaPOMDP/SARSOP.jl)
+- [POMCP](https://github.com/JuliaPOMDP/POMCP.jl)
+- [POMDPSolve](https://github.com/JuliaPOMDP/POMDPSolve.jl)
+
+## Manual Outline
+
+ {contents}
+
diff --git a/src/POMDPs.jl b/src/POMDPs.jl
index 2001c9c3..32f40632 100644
--- a/src/POMDPs.jl
+++ b/src/POMDPs.jl
@@ -1,3 +1,6 @@
+"""
+Provides a basic interface for defining and solving MDPs/POMDPs
+"""
module POMDPs
import Base.rand
@@ -5,7 +8,7 @@ import Base.rand
export
# Abstract type
POMDP,
- DiscretePOMDP,
+ MDP,
# Discrete Functions
n_states,
@@ -21,12 +24,8 @@ export
observation,
reward,
isterminal,
+ isterminal_obs,
- # Need below?;
- create_state,
- create_observation,
- create_action,
-
# Spaces, Distributions and accessor functions
AbstractDistribution,
DiscreteDistribution,
@@ -34,7 +33,9 @@ export
# Discrete Functions
length,
- index,
+ state_index,
+ action_index,
+ obs_index,
weight,
# Common Functions
@@ -45,6 +46,9 @@ export
upperbound,
getindex,
iterator,
+ create_state,
+ create_action,
+ create_observation,
create_transition_distribution,
create_observation_distribution,
create_belief,
@@ -54,19 +58,6 @@ export
Solver,
solve,
- # States
- State,
-
- # Actions
- Action,
- create_action,
-
- # Observations
- Observation,
-
- # Rewards
- Reward,
-
# Beliefs
Belief,
BeliefUpdater,
@@ -97,7 +88,5 @@ include("space.jl")
include("solver.jl")
include("policy.jl")
include("simulator.jl")
-include("docs.jl")
end
-
diff --git a/src/belief.jl b/src/belief.jl
index 486aafe3..a72cffe8 100644
--- a/src/belief.jl
+++ b/src/belief.jl
@@ -6,20 +6,50 @@
# For discrete problems, it can be usually be represented as a vector.
# For tools supportng belief updates see POMDPToolbox.jl
-abstract Belief <: AbstractDistribution
+"""
+Abstract type for an object representing some knowledge about the state (often a probability distribution)
+"""
+abstract Belief
+
+"""
+Abstract type for an object that defines how a belief should be updated
+"""
abstract BeliefUpdater
-# returns an example initial belief for the pomdp
+"""
+ initial_belief(pomdp::POMDP, belief::Belief = create_belief(pomdp))
+
+Returns an initial belief for the pomdp.
+"""
@pomdp_func initial_belief(pomdp::POMDP, belief::Belief = create_belief(pomdp))
-# allocates and returns an empty problem-native belief structure
+"""
+ create_belief(pomdp::POMDP)
+
+Creates a belief either to be used by updater or pomdp
+"""
@pomdp_func create_belief(pomdp::POMDP)
-# creates a belief object of the type used by `updater` (for preallocation purposes)
+"""
+ create_belief(updater::BeliefUpdater)
+
+Creates a belief object of the type used by `updater` (preallocates memory)
+"""
@pomdp_func create_belief(updater::BeliefUpdater)
-# updates the belief given the old belief (belief_old), the action and the observation
-@pomdp_func update(updater::BeliefUpdater, belief_old::Belief, action::Action, obs::Observation, belief_new::Belief=create_belief(updater))
+"""
+ update(updater::BeliefUpdater, belief_old::Belief, action, obs,
+ belief_new::Belief=create_belief(updater))
+
+Returns a new instance of an updated belief given `belief_old` and the latest action and observation.
+"""
+@pomdp_func update(updater::BeliefUpdater, belief_old::Belief, action::Any, obs::Any, belief_new::Belief=create_belief(updater))
# returns a belief that can be updated using `updater` that has a similar distribution to `b` (this conversion may be lossy)
+"""
+ convert_belief(updater::BeliefUpdater, belief::Belief,
+ new_belief::Belief=create_belief(updater)) = belief
+
+Returns a belief that can be updated using `updater` that has a similar distribution to `belief`.
+"""
@pomdp_func convert_belief(updater::BeliefUpdater, belief::Belief, new_belief::Belief=create_belief(updater)) = belief
diff --git a/src/constants.jl b/src/constants.jl
index d47ba65a..f1d98e07 100644
--- a/src/constants.jl
+++ b/src/constants.jl
@@ -1,7 +1,15 @@
-# url to remote organization repo
+"""
+url to remote JuliaPOMDP organization repo
+"""
const REMOTE_URL = "https://github.com/JuliaPOMDP/"
-# supported solvers
+"""
+Set containing string names of officially supported solvers
+(e.g. `MCTS`, `SARSOP`, etc).
+If you have a validated solver that supports the POMDPs.jl API,
+contact the developers to add your solver to this list.
+"""
+# TODO (max): would it be better to have a dict of form: string => url for solvers?
const SUPPORTED_SOLVERS = Set{AbstractString}(
["DiscreteValueIteration",
"MCTS",
diff --git a/src/distribution.jl b/src/distribution.jl
index 22bfc20e..244234eb 100644
--- a/src/distribution.jl
+++ b/src/distribution.jl
@@ -4,15 +4,41 @@
# DiscreteDistribution: discrete distributions support state indexing and length functions
#################################################################
-@pomdp_func create_transition_distribution(pomdp::POMDP)
-@pomdp_func create_observation_distribution(pomdp::POMDP)
-@pomdp_func rand(rng::AbstractRNG, d::AbstractDistribution, sample::Any)
-@pomdp_func pdf(d::AbstractDistribution, x::Any)
-@pomdp_func iterator(d::AbstractDistribution)
-@pomdp_func domain(d::AbstractDistribution)
-
-abstract DiscreteDistribution <: AbstractDistribution
-
-@pomdp_func Base.length(d::DiscreteDistribution)
-@pomdp_func weight(d::DiscreteDistribution, i::Int)
-@pomdp_func index(pomdp::POMDP, d::DiscreteDistribution, i::Int)
+"""
+ create_transition_distribution(problem::POMDP)
+ create_transition_distribution(problem::MDP)
+
+Returns a transition distribution (for memory preallocation).
+"""
+@pomdp_func create_transition_distribution(problem::Union{POMDP,MDP})
+
+"""
+ create_observation_distribution(problem::POMDP)
+ create_observation_distribution(problem::MDP)
+
+Returns an observation distribution (for memory preallocation).
+"""
+@pomdp_func create_observation_distribution(problem::Union{POMDP,MDP})
+
+"""
+ rand{T}(rng::AbstractRNG, d::AbstractDistribution{T}, sample::T)
+
+Fill `sample` with a random element from distribution `d`. The sample can be a state, action or observation.
+"""
+@pomdp_func rand{T}(rng::AbstractRNG, d::AbstractDistribution{T}, sample::T)
+
+"""
+ pdf{T}(d::AbstractDistribution{T}, x::T)
+
+Value of probability distribution `d` function at sample `x`.
+"""
+@pomdp_func pdf{T}(d::AbstractDistribution{T}, x::T)
+
+# TODO (max): does this have a purpose now that we have iterator?
+@pomdp_func domain{T}(d::AbstractDistribution{T})
+
+# TODO (max): need an explicit treamtent of discrete distributions?
+abstract DiscreteDistribution{T} <: AbstractDistribution{T}
+@pomdp_func Base.length{T}(d::DiscreteDistribution{T})
+@pomdp_func weight{T}(d::DiscreteDistribution{T}, i::Int)
+@pomdp_func index{T}(problem::Union{POMDP,MDP}, d::DiscreteDistribution{T}, i::Int)
diff --git a/src/docs.jl b/src/docs.jl
deleted file mode 100644
index 9b6de446..00000000
--- a/src/docs.jl
+++ /dev/null
@@ -1,390 +0,0 @@
-"""
-Provides a basic interface for working with MDPs/POMDPs
-"""
-POMDPs
-
-#################################################################
-####################### Problem Model ###########################
-#################################################################
-
-"""
-Base type for a POMDP model, defined by the user
-"""
-POMDP
-
-
-"""
-Base type for state, action and observation spaces
-"""
-AbstractSpace
-
-
-"""
-Base type for states
-"""
-State
-
-
-"""
-Base type for actions
-"""
-Action
-
-
-"""
-Base type for observation
-"""
-Observation
-
-
-"""
- states(pomdp::POMDP)
-
-Returns the complete state space of a POMDP.
-"""
-states
-
-
-"""
- actions(pomdp::POMDP)
-
-Returns the entire action space of a POMDP.
-"""
-actions(pomdp::POMDP)
-
-
-"""
- actions(pomdp::POMDP, state::State, aspace::AbstractSpace)
-
-Modifies aspace to the action space accessible from the given state and returns it.
-"""
-actions(pomdp::POMDP, state::State, aspace::AbstractSpace)
-
-
-"""
- actions(pomdp::POMDP, belief::Belief, aspace::AbstractSpace)
-
-Modifies aspace to the action space accessible from the states with nonzero belief and returns it.
-"""
-actions(pomdp::POMDP, belief::Belief, aspace::AbstractSpace)
-
-
-"""
- observations(pomdp::POMDP)
-
-Returns the entire observation space.
-"""
-observations(pomdp::POMDP)
-
-
-"""
- observations(pomdp::POMDP, state::State, ospace::AbstractSpace)
-
-Modifies ospace to the observation space accessible from the given state and returns it.
-"""
-observations(pomdp::POMDP, state::State, ospace::AbstractSpace)
-
-
-"""
- reward(pomdp::POMDP, state::State, action::Action, statep::State)
-
-Returns the immediate reward for the s-a-s' triple
-"""
-reward
-
-
-"""
- transition(pomdp::POMDP, state::State, action::Action)
-
-Returns the transition distribution from the current state-action pair
-"""
-transition(pomdp::POMDP, state::State, action::Action)
-
-"""
- transition(pomdp::POMDP, state::State, action::Action, distribution::AbstractDistribution)
-
-Modifies distribution to the transition distribution from the current state-action pair and returns it
-"""
-transition(pomdp::POMDP, state::State, action::Action, distribution::AbstractDistribution)
-
-
-"""
- observation(pomdp::POMDP, state::State, action::Action, statep::State)
-
-Returns the observation distribution for the s-a-s' tuple (state, action, and next state)
-"""
-observation(pomdp::POMDP, state::State, action::Action, statep::State)
-
-
-"""
- observation(pomdp::POMDP, state::State, action::Action, statep::State, distribution::AbstractDistribution)
-
-Modifies distribution to the observation distribution for the s-a-s' tuple (state, action, and next state) and returns it
-"""
-observation(pomdp::POMDP, state::State, action::Action, statep::State, distribution::AbstractDistribution)
-
-
-"""
- discount(pomdp::POMDP)
-
-Returns the discount factor
-"""
-discount
-
-
-"""
- isterminal(pomdp::POMDP, s::State)
-
-Checks if state s is terminal
-"""
-isterminal
-
-
-
-#################################################################
-####################### Distributions ###########################
-#################################################################
-
-"""
-Base type for a probability distribution
-"""
-AbstractDistribution
-
-"""
- rand(rng::AbstractRNG, d::AbstractDistribution, sample)
-
-Fill sample with a random element from distribution d. The sample can be a state, action or observation.
-"""
-rand(rng::AbstractRNG, d::AbstractDistribution, sample)
-
-"""
- rand(rng::AbstractRNG, s::AbstractSpace, sample)
-
-Fill sample with a random element from space s. The sample can be a state, action or observation.
-"""
-rand(rng::AbstractRNG, s::AbstractSpace, sample)
-
-"""
- pdf(d::AbstractDistribution, x)
-
-Value of probability distribution function at x
-"""
-pdf
-
-
-
-
-#################################################################
-##################### Solvers and Policies ######################
-#################################################################
-
-"""
-Base type for an MDP/POMDP solver
-"""
-Solver
-
-"""
-Base type for a policy (a map from every possible belief, or more abstract policy state, to an optimal or suboptimal action)
-"""
-Policy
-
-"""
- solve(solver::Solver, pomdp::POMDP)
-
-Solves the POMDP using method associated with solver, and returns a policy.
-"""
-solve(solver::Solver, pomdp::POMDP)
-
-"""
- solve(solver::Solver, pomdp::POMDP, policy::Policy)
-
-Solves the POMDP and modifies policy to be the solution of pomdp and returns it
-"""
-solve(solver::Solver, pomdp::POMDP, policy::Policy)
-
-
-"""
- action(policy::Policy, belief::Belief)
-
-Returns an action for the current belief, given the policy
-
-"""
-action(policy::Policy, belief::Belief)
-
-"""
- action(policy::Policy, belief::Belief, a::Action)
-
-Fills and returns action a for the current belief, given the policy
-"""
-action(policy::Policy, belief::Belief, a::Action)
-
-"""
- action(policy::Policy, s::State)
-
-Returns an action for the current state, given the policy
-
-"""
-action(policy::Policy, s::State)
-
-"""
- action(policy::Policy, s::State, a::Action)
-
-Fills and returns action a for the current state, given the policy
-"""
-action(policy::Policy, s::State, a::Action)
-
-"""
- value(policy::Policy, s::State)
-
-Returns the utility value from a given state
-"""
-value(policy::Policy, s::State)
-
-"""
- value(policy::Policy, b::Belief)
-
-Returns the utility value from a given belief
-"""
-value(policy::Policy, b::Belief)
-
-
-
-#################################################################
-############################ Belief #############################
-#################################################################
-
-"""
-Base type for an object representing some knowledge about the state (often a probability distribution)
-"""
-Belief
-
-"""
-Base type for an object that defines how a belief should be updated
-"""
-BeliefUpdater
-
-"""
- update(updater::BeliefUpdater, belief_old::Belief, action::Action, obs::Observation)
-
-Returns a new instance of an updated belief given the old belief (belief_old) and the latest action and observation
-"""
-update(updater::BeliefUpdater, belief_old::Belief, action::Action, obs::Observation)
-
-"""
- update(updater::BeliefUpdater, belief_old::Belief, action::Action, obs::Observation, belief_new::Belief)
-
-Modifies belief_new to the belief given the old belief (belief_old) and the latest action and observation and returns
-the updated belief
-"""
-update(updater::BeliefUpdater, belief_old::Belief, action::Action, obs::Observation, belief_new::Belief)
-
-"""
- initial_belief(pomdp::POMDP)
-
-Returns an initial belief for the pomdp
-"""
-initial_belief
-
-"""
- convert_belief(updater::BeliefUpdater, b::Belief)
-
-Returns a belief that can be updated using updater that has a similar distribution to b
-"""
-convert_belief
-
-"""
- updater(p::Policy)
-Returns a default BeliefUpdater appropriate for the passed in policy
-"""
-updater
-
-#################################################################
-############################ Simulation #########################
-#################################################################
-
-"""
-Base type for an object defining how a simulation should be carried out
-"""
-Simulator
-
-"""
- simulate(simulator::Simulator, pomdp::POMDP, policy::Policy, updater::BeliefUpdater, initial_belief::Belief)
-
-Runs a simulation using the specified policy and returns the accumulated reward
-"""
-simulate
-
-
-
-#################################################################
-######################### Convenience ###########################
-#################################################################
-
-"""
- index(pomdp::POMDP, state::State)
-
-Returns the index of the given state for a discrete POMDP
-"""
-index(pomdp::POMDP, s::State)
-
-"""
- iterator(space::AbstractSpace)
-
-Returns an iterator over a space
-"""
-iterator(space::AbstractSpace)
-
-
-
-#################################################################
-############################ Creators ###########################
-#################################################################
-
-"""
- create_state(pomdp::POMDP)
-
-Creates a single state object (for preallocation purposes)
-"""
-create_state(pomdp::POMDP)
-
-"""
- create_observation(pomdp::POMDP)
-
-Creates a single observation object (for preallocation purposes)
-"""
-create_observation(pomdp::POMDP)
-
-"""
- create_transition_distribution(pomdp::POMDP)
-
-Returns a transition distribution
-"""
-create_transition_distribution(pomdp::POMDP)
-
-"""
- create_observation_distribution(pomdp::POMDP)
-
-Returns an observation distribution
-"""
-create_observation_distribution(pomdp::POMDP)
-
-"""
- create_policy(solver::Solver, pomdp::POMDP)
-
-Creates a policy object (for preallocation purposes)
-"""
-create_policy(solver::Solver, pomdp::POMDP)
-
-"""
- create_action(pomdp::POMDP)
-
-Creates an action object (for preallocation purposes)
-"""
-create_action(pomdp::POMDP)
-
-"""
- create_belief(pomdp::POMDP)
-
-Creates a belief either to be used by updater or pomdp
-"""
-create_belief(pomdp::POMDP)
diff --git a/src/errors.jl b/src/errors.jl
index 47dd0f48..bfba5a15 100644
--- a/src/errors.jl
+++ b/src/errors.jl
@@ -3,6 +3,9 @@
# throws an error if the interface function is not implemented.
###############################################################
+"""
+Provide a default function implementation that throws an error when called.
+"""
macro pomdp_func(signature)
if signature.head == :(=) # in this case a default implementation has already been supplied
return esc(signature)
@@ -34,17 +37,18 @@ macro pomdp_func(signature)
body = Expr(:call, :error, parse("\"$error_string\""))
- return Expr(:function, esc(signature), body)
+ return Expr(:function, esc(signature), esc(body))
end
-# strip_arg strips anything extra (type annotations, default values, etc) from an argument
-# for now this cannot handle keyword arguments (it will throw an error)
+"""
+Strip anything extra (type annotations, default values, etc) from an argument.
+For now this cannot handle keyword arguments (it will throw an error).
+"""
strip_arg(arg::Symbol) = arg # once we have a symbol, we have stripped everything, so we can just return it
-
function strip_arg(arg_expr::Expr)
- if arg_expr.head == :parameters # keywork argument
- error("extract_arg_names can't handle keyword args yet (parsing arg expression $(arg_expr))")
+ if arg_expr.head == :parameters # keyword argument
+ error("strip_arg can't handle keyword args yet (parsing arg expression $(arg_expr))")
elseif arg_expr.head == :(::) # argument is type annotated, remove the annotation
return strip_arg(arg_expr.args[1])
elseif arg_expr.head == :kw # argument has a default value, remove the default
diff --git a/src/io.jl b/src/io.jl
index 0bf46a51..cf627c2a 100644
--- a/src/io.jl
+++ b/src/io.jl
@@ -1,2 +1,2 @@
-# TODO (max): how to best handle io: HDF5? or something else
+# TODO (max): do we need a unified API for io?
diff --git a/src/policy.jl b/src/policy.jl
index 11b69c10..bddf5870 100644
--- a/src/policy.jl
+++ b/src/policy.jl
@@ -4,21 +4,54 @@
# The policy is extracted through calls to the action() function.
#################################################################
+"""
+Base type for a policy (a map from every possible belief, or more abstract policy state, to an optimal or suboptimal action)
+"""
abstract Policy
-# creates an action object (for preallocation purposes)
-@pomdp_func create_action(pomdp::POMDP)
+"""
+ create_action(problem::POMDP)
+ create_action(problem::MDP)
-# returns a default BeliefUpdater appropriate for a belief type that policy `p` can use
-@pomdp_func action(p::Policy, s::State, a::Action)
-@pomdp_func action(p::Policy, s::State)
-@pomdp_func action(p::Policy, b::Belief, a::Action)
-@pomdp_func action(p::Policy, b::Belief)
+Creates an action object (for preallocation purposes)
+"""
+@pomdp_func create_action(problem::Union{POMDP,MDP})
-# returns a default BeliefUpdater appropriate for a belief type that policy `p` can use
+# default implementation for numeric types
+create_action{S,A<:Number}(problem::Union{POMDP{S,A},MDP{S,A}}) = zero(A)
+
+"""
+ action(p::Policy, x::Any, action)
+ action(p::Policy, x::Belief, action)
+
+Fills and returns action based on the current state or belief, given the policy.
+
+If an MDP is being simulated, x will be a state; if a POMDP is being simulated, x will be a Belief
+"""
+@pomdp_func action(policy::Policy, x::Any, action::Any)
+
+"""
+ action(policy::Policy, x::Any)
+ action(policy::Policy, x::Belief)
+
+Returns an action for the current state or belief, given the policy
+
+If an MDP is being simulated, x will be a state; if a POMDP is being simulated, x will be a Belief
+"""
+@pomdp_func action(policy::Policy, x::Any)
+
+
+"""
+ updater(policy::Policy)
+
+Returns a default BeliefUpdater appropriate for a belief type that policy `p` can use
+"""
@pomdp_func updater(policy::Policy)
-# returns the utility value from policy p given the belief
-@pomdp_func value(p::Policy, belief::Belief)
-# returns the utility value from policy p given the state
-@pomdp_func value(p::Policy, state::State)
+"""
+ value{S}(p::Policy, x::Any)
+ value{S}(p::Policy, x::Belief)
+
+Returns the utility value from policy p given the state
+"""
+@pomdp_func value(p::Policy, x::Any)
diff --git a/src/pomdp.jl b/src/pomdp.jl
index e2f32cd4..54d9cc19 100644
--- a/src/pomdp.jl
+++ b/src/pomdp.jl
@@ -1,31 +1,154 @@
# POMDP model functions
+"""
+Abstract base type for a partially observable Markov decision process.
-abstract POMDP
+ S: state type
+ A: action type
+ O: observation type
+"""
+abstract POMDP{S,A,O}
-abstract State
-abstract Action
-abstract Observation
-typealias Reward Float64
+"""
+Abstract base type for a fully observable Markov decision process.
-abstract AbstractDistribution
+ S: state type
+ A: action type
+"""
+abstract MDP{S,A}
-# return the space sizes
-@pomdp_func n_states(pomdp::POMDP)
-@pomdp_func n_actions(pomdp::POMDP)
-@pomdp_func n_observations(pomdp::POMDP)
+"""
+Abstract type for a probability distribution.
-# return the discount factor
-@pomdp_func discount(pomdp::POMDP)
+ T: type over which distribution is over (state, action, or observation)
+"""
+abstract AbstractDistribution{T}
-@pomdp_func transition(pomdp::POMDP, state::State, action::Action, distribution::AbstractDistribution=create_transition_distribution(pomdp))
-@pomdp_func observation(pomdp::POMDP, state::State, action::Action, statep::State, distribution::AbstractDistribution=create_observation_distribution(pomdp))
-@pomdp_func observation(pomdp::POMDP, state::State, action::Action, distribution::AbstractDistribution=create_observation_distribution(pomdp))
-@pomdp_func reward(pomdp::POMDP, state::State, action::Action, statep::State)
+"""
+ n_states(problem::POMDP)
+ n_states(problem::MDP)
-@pomdp_func create_state(pomdp::POMDP)
-@pomdp_func create_observation(pomdp::POMDP)
+Returns the number of states in `problem`. Used for discrete models only.
+"""
+@pomdp_func n_states(problem::Union{POMDP,MDP})
-@pomdp_func isterminal(pomdp::POMDP, state::State) = false
-@pomdp_func isterminal(pomdp::POMDP, observation::Observation) = false
+"""
+ n_actions(problem::POMDP)
+ n_actions(problem::MDP)
-@pomdp_func index(pomdp::POMDP, state::State)
+Returns the number of actions in `problem`. Used for discrete models only.
+"""
+@pomdp_func n_actions(problem::Union{POMDP,MDP})
+
+"""
+ n_observations(problem::POMDP)
+
+Returns the number of actions in `problem`. Used for discrete models only.
+"""
+@pomdp_func n_observations(problem::POMDP)
+
+"""
+ discount(problem::POMDP)
+ discount(problem::MDP)
+
+Return the discount factor for the problem.
+"""
+@pomdp_func discount(problem::Union{POMDP,MDP})
+
+"""
+ transition{S,A,O}(problem::POMDP{S,A,O}, state::S, action::A,
+distribution::AbstractDistribution{S}=create_transition_distribution(problem))
+ transition{S,A}(problem::MDP{S,A}, state::S, action::A,
+distribution::AbstractDistribution{S}=create_transition_distribution(problem))
+
+Returns the transition distribution from the current state-action pair
+"""
+@pomdp_func transition{S,A}(problem::Union{POMDP{S,A},MDP{S,A}}, state::S, action::A, distribution::AbstractDistribution{S}=create_transition_distribution(problem))
+
+"""
+ observation{S,A,O}(problem::POMDP{S,A,O}, action::A, statep::S, distribution::AbstractDistribution{O}=create_observation_distribution(problem))
+
+Modifies distribution to the observation distribution for the a-s' tuple (action and next state) and returns it
+"""
+@pomdp_func observation{S,A,O}(problem::POMDP{S,A,O}, action::A, statep::S, distribution::AbstractDistribution{O}=create_observation_distribution(problem))
+
+"""
+ observation{S,A,O}(problem::POMDP{S,A,O}, state::S, action::A, statep::S, distribution::AbstractDistribution{O}=create_observation_distribution(problem))
+
+Returns the observation distribution for the s-a-s' tuple (state, action, and next state)
+"""
+@pomdp_func observation{S,A,O}(problem::POMDP{S,A,O}, state::S, action::A, statep::S, distribution::AbstractDistribution{O}) # removed =create_observation_distribution(problem) to resolve ambiguity - problems should still implement this with an optional 5th argument
+
+"""
+ reward{S,A,O}(problem::POMDP{S,A,O}, state::S, action::A, statep::S)
+ reward{S,A}(problem::MDP{S,A}, state::S, action::A, statep::S)
+
+Returns the immediate reward for the s-a-s' triple
+"""
+@pomdp_func reward{S,A}(problem::Union{POMDP{S,A},MDP{S,A}}, state::S, action::A, statep::S)
+
+"""
+ reward{S,A,O}(problem::POMDP{S,A,O}, state::S, action::A)
+ reward{S,A}(problem::MDP{S,A}, state::S, action::A)
+
+Returns the immediate reward for the s-a pair
+"""
+@pomdp_func reward{S,A}(problem::Union{POMDP{S,A},MDP{S,A}}, state::S, action::A)
+
+"""
+ create_state(problem::POMDP)
+ create_state(problem::MDP)
+
+Create a state object (for preallocation purposes).
+"""
+@pomdp_func create_state(problem::Union{POMDP,MDP})
+
+# default implementation for numeric types
+create_state{S<:Number,A}(problem::Union{POMDP{S,A},MDP{S,A}}) = zero(S)
+
+"""
+ create_observation(problem::POMDP)
+
+Create an observation object (for preallocation purposes).
+"""
+@pomdp_func create_observation(problem::POMDP)
+
+# default implementation for numeric types
+create_observation{S,A,O<:Number}(problem::POMDP{S,A,O}) = zero(O)
+
+"""
+ isterminal_obs{S,A,O}(problem::POMDP{S,A,O}, observation::O)
+
+Checks if an observation is terminal.
+"""
+@pomdp_func isterminal_obs{S,A,O}(problem::POMDP{S,A,O}, observation::O) = false
+
+"""
+ isterminal{S,A,O}(problem::POMDP{S,A,O}, state::S)
+ isterminal{S,A}(problem::MDP{S,A}, state::S)
+
+Checks if state s is terminal
+"""
+@pomdp_func isterminal{S,A}(problem::Union{POMDP{S,A},MDP{S,A}}, state::S) = false
+
+"""
+ state_index{S,A,O}(problem::POMDP{S,A,O}, s::S)
+ state_index{S,A}(problem::MDP{S,A}, s::S)
+
+Returns the integer index of state `s`. Used for discrete models only.
+"""
+@pomdp_func state_index{S,A}(problem::Union{POMDP{S,A},MDP{S,A}}, s::S)
+
+"""
+ action_index{S,A,O}(problem::POMDP{S,A,O}, a::A)
+ action_index{S,A}(problem::MDP{S,A}, a::A)
+
+Returns the integer index of action `a`. Used for discrete models only.
+"""
+@pomdp_func action_index{S,A}(problem::Union{POMDP{S,A},MDP{S,A}}, a::A)
+
+"""
+ obs_index{S,A,O}(problem::POMDP{S,A,O}, o::O)
+
+Returns the integer index of observation `o`. Used for discrete models only.
+"""
+@pomdp_func obs_index{S,A,O}(problem::POMDP{S,A,O}, o::O)
diff --git a/src/simulator.jl b/src/simulator.jl
index 1db1fa48..b252ec6b 100644
--- a/src/simulator.jl
+++ b/src/simulator.jl
@@ -4,8 +4,15 @@
# creating Simulator types
#################################################################
-# Base type for an object defining how a simulation should be carried out
+"""
+Base type for an object defining how a simulation should be carried out
+"""
abstract Simulator
-# runs a simulation using the specified policy and returns the accumulated reward
-@pomdp_func simulate(simulator::Simulator, pomdp::POMDP, policy::Policy, updater::BeliefUpdater, initial_belief::Belief)
+"""
+ simulate{S,A,O}(simulator::Simulator, problem::POMDP{S,A,O}, policy::Policy, updater::BeliefUpdater, initial_belief::Belief)
+ simulate{S,A}(simulator::Simulator, problem::MDP{S,A}, policy::Policy, updater::BeliefUpdater, initial_belief::Belief)
+
+Runs a simulation using the specified policy and returns the accumulated reward
+"""
+@pomdp_func simulate(simulator::Simulator, problem::Union{POMDP,MDP}, policy::Policy, updater::BeliefUpdater, initial_belief::Belief)
diff --git a/src/solver.jl b/src/solver.jl
index b96e6930..393bc3f1 100644
--- a/src/solver.jl
+++ b/src/solver.jl
@@ -1,5 +1,20 @@
+"""
+Base type for an MDP/POMDP solver
+"""
abstract Solver
-create_policy(solver::Solver, pomdp::POMDP) = error("$(typeof(pomdp)) does not implement create_policy")
-solve(solver::Solver, pomdp::POMDP, policy=create_policy(solver, pomdp)) = error("$(typeof(solver)) does not implement solve for model $(typeof(pomdp))")
+"""
+ create_policy(solver::Solver, problem::POMDP)
+ create_policy(solver::Solver, problem::MDP)
+
+Creates a policy object (for preallocation purposes)
+"""
+@pomdp_func create_policy(solver::Solver, problem::Union{POMDP,MDP})
+
+"""
+ solve(solver::Solver, problem::POMDP, policy=create_policy(solver, problem))
+
+Solves the POMDP using method associated with solver, and returns a policy.
+"""
+@pomdp_func solve(solver::Solver, problem::Union{POMDP,MDP}, policy=create_policy(solver, problem))
diff --git a/src/space.jl b/src/space.jl
index 550788dd..c4269c1f 100644
--- a/src/space.jl
+++ b/src/space.jl
@@ -3,24 +3,86 @@
# AbstractSpace: the abstract super type for the state, action and observation spaces
#################################################################
-abstract AbstractSpace
-
-# returns an integer
-@pomdp_func dimensions(s::AbstractSpace)
-# returns bound of dim i
-@pomdp_func lowerbound(s::AbstractSpace, i::Int)
-# returns bound of dim i
-@pomdp_func upperbound(s::AbstractSpace, i::Int)
-# sample a space and return the sample
-@pomdp_func rand(rng::AbstractRNG, d::AbstractSpace, state::Any)
-# return an iterable object corresponding to the space
-@pomdp_func iterator(s::AbstractSpace)
-
-# return a space type
-@pomdp_func states(pomdp::POMDP)
-@pomdp_func states(pomdp::POMDP, state::State, sts::AbstractSpace=states(pomdp))
-@pomdp_func actions(pomdp::POMDP)
-@pomdp_func actions(pomdp::POMDP, state::State, acts::AbstractSpace=actions(pomdp))
-@pomdp_func actions(pomdp::POMDP, belief::Belief, acts::AbstractSpace=actions(pomdp))
-@pomdp_func observations(pomdp::POMDP)
-@pomdp_func observations(pomdp::POMDP, state::State, obs::AbstractSpace=observations(pomdp))
+"""
+Base type for state, action and observation spaces.
+
+ T: type that parametarizes the space (state, action, or observation)
+"""
+abstract AbstractSpace{T}
+
+"""
+ dimensions{T}(s::AbstractSpace{T})
+
+Returns the number of dimensions in space `s`.
+"""
+@pomdp_func dimensions{T}(s::AbstractSpace{T})
+
+"""
+ rand{T}(rng::AbstractRNG, d::AbstractSpace{T}, sample::T)
+
+Returns a random `sample` from space `s`.
+"""
+@pomdp_func rand{T}(rng::AbstractRNG, d::AbstractSpace{T}, sample::T)
+
+"""
+ iterator{T}(s::AbstractSpace{T})
+
+Returns an iterable type (array or custom iterator) corresponding to space `s`.
+"""
+@pomdp_func iterator{T}(s::AbstractSpace{T})
+
+@pomdp_func lowerbound{T}(s::AbstractSpace{T}, i::Int)
+@pomdp_func upperbound{T}(s::AbstractSpace{T}, i::Int)
+
+"""
+ states(problem::POMDP)
+ states(problem::MDP)
+
+Returns the complete state space of a POMDP.
+"""
+@pomdp_func states(problem::Union{POMDP,MDP})
+
+"""
+ states{S,A,O}(problem::POMDP{S,A,O}, state::S)
+ states{S,A}(problem::MDP{S,A}, state::S)
+
+Returns a subset of the state space reachable from `state`.
+"""
+@pomdp_func states{S,A}(problem::Union{POMDP{S,A},MDP{S,A}}, state::S, sts::AbstractSpace{S}=states(problem))
+
+"""
+ actions(problem::POMDP)
+ actions(problem::MDP)
+
+Returns the entire action space of a POMDP.
+"""
+@pomdp_func actions(problem::Union{POMDP,MDP})
+
+"""
+ actions{S,A,O}(problem::POMDP{S,A,O}, state::S, aspace::AbstractSpace{A})
+ actions{S,A}(problem::MDP{S,A}, state::S, aspace::AbstractSpace{A})
+
+Modifies aspace to the action space accessible from the given state and returns it.
+"""
+@pomdp_func actions{S,A}(problem::Union{MDP{S,A},POMDP{S,A}}, state::S, acts::AbstractSpace{A}=actions(problem))
+
+"""
+ actions{S,A,O}(problem::POMDP{S,A,O}, belief::Belief, aspace::AbstractSpace{A})
+
+Modifies aspace to the action space accessible from the states with nonzero belief and returns it.
+"""
+@pomdp_func actions{S,A,O}(problem::POMDP{S,A,O}, belief::Belief, acts::AbstractSpace{A}=actions(problem))
+
+"""
+ observations(problem::POMDP)
+
+Returns the entire observation space.
+"""
+@pomdp_func observations(problem::POMDP)
+
+"""
+ observations{S,A,O}(problem::POMDP{S,A,O}, state::S, obs::AbstractSpace{O}=observations(problem))
+
+Modifies ospace to the observation space accessible from the given state and returns it.
+"""
+@pomdp_func observations{S,A,O}(problem::POMDP{S,A,O}, state::S, obs::AbstractSpace{O}=observations(problem))
diff --git a/src/utils.jl b/src/utils.jl
index 045f2c02..b4f61479 100644
--- a/src/utils.jl
+++ b/src/utils.jl
@@ -1,4 +1,13 @@
-# adds a registered solver
+"""
+ add(solver_name::AbstractString)
+
+Downloads and installs a registered solver with name `solver_name`.
+This function is not exported, and must be called:
+```julia
+julia> using POMDPs
+julia> POMDPs.add("MCTS")
+```
+"""
function add(solver_name::AbstractString)
@assert solver_name in SUPPORTED_SOLVERS string("The solver: ", solver_name, " is not supported")
full_url = string(REMOTE_URL, solver_name, ".jl")
diff --git a/test/runtests.jl b/test/runtests.jl
index 91a5b399..a2951703 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -1,2 +1,13 @@
-# just test to see if the import works
-import POMDPs
+using Base.Test
+
+using POMDPs
+type A <: POMDP{Bool,Bool,Bool} end
+@test_throws ErrorException discount(A())
+
+@test POMDPs.strip_arg(:a) == :a
+@test POMDPs.strip_arg(parse("a::Int")) == :a
+kw_expr = Expr(:kw, parse("a::Int"), false, Any)
+@test POMDPs.strip_arg(kw_expr) == :a
+
+POMDPs.@pomdp_func testfunc(a, b::Int, c::Bool=false)
+@test_throws ErrorException testfunc(1,2)