POMDPs.jl

repository·master·Indexed 21 days ago

https://github.com/juliapomdp/pomdps.jl

A standardized programming interface for working with Markov Decision Processes (MDPs) and Partially Observable Markov Decision Processes (POMDPs) in Julia. It provides a core architecture for expressing problems, developing solvers, and running simulations. The ecosystem includes POMDPTools for utility functions, QuickPOMDPs for rapid problem definition, and various solvers such as QMDP, SARSOP, and POMCPOW, as well as integrations with Reinforcement Learning via CommonRLInterface.jl.

Tokens
30K
Snippets
74
Records
134
Agent score
73%

What's inside POMDPs.jl

  1. Overview of POMDPs.jl ecosystem

    master

    POMDPs.jl provides a core interface for Markov decision processes (MDPs) and partially observable Markov decision processes (POMDPs). It is designed for:

    1. Expressing problems as MDPs and POMDPs.
    2. Writing solver software.
    3. Running simulations efficiently.

    Key ecosystem components:

    • POMDPTools: Acts as a 'standard library' providing implementations for policies, belief updaters, distributions, and simulators.
    • QuickPOMDPs: Allows for quick definition of POMDPs (as seen in the Quick Start).
    • QMDP: A solver package.
    • SymbolicMDPs: Provides an interface for PDDL models.

    Integrations:

    • Python: Use quickpomdps or pyjulia to define/solve problems via Python.
    • Reinforcement Learning: POMDPTools provides two-way integration with CommonRLInterface.jl and the JuliaReinforcementLearning ecosystem.
  2. Explore supported POMDPs.jl tools, models, and solvers

    master

    The POMDPs.jl ecosystem consists of several specialized packages that implement the core interface. Depending on your needs, you can choose from tools for belief filtering, pre-implemented models, MDP/POMDP solvers, or Reinforcement Learning algorithms.

    Tools

    Used for implementing commonly-used components like filters:

    • POMDPTools: Core interface components.
    • ParticleFilters: Particle filter implementations.
    • GaussianFilters: Gaussian filter implementations.

    Implemented Models

    Commonly used POMDP models implemented via the interface:

    • POMDPModels, LaserTag, RockSample, TagPOMDPProblem, DroneSurveillance, ContinuumWorld, VDPTag2, RoombaPOMDPs.

    Solvers

    MDP Solvers

    • DiscreteValueIteration: Offline, discrete states/actions (High reliability).
    • LocalApproximationValueIteration: Offline, continuous states, discrete actions.
    • GlobalApproximationValueIteration: Offline, continuous states, discrete actions.
    • MCTS: Online, continuous states/actions (Monte Carlo Tree Search).

    POMDP Solvers

    • QMDP: Offline, discrete (Suboptimal).
    • AdaOPS: Online, continuous states/observations.
    • ARDESPOT: Online, continuous states.
    • BasicPOMCP: Online, continuous states.
    • CompressedBeliefMDPs: Offline, continuous states/actions/observations.
    • NativeSARSOP: Offline, discrete.
    • SARSOP: Offline, discrete.
    • POMCPOW: Online, continuous states/actions.
    • ParticleFilterTrees: Online, continuous states/actions.

    Reinforcement Learning

    • TabularTDLearning: Discrete states/actions.
    • DeepQLearning: Continuous states (uses observations as input).
    • Crux: Continuous states and actions.
  3. Understand the POMDPs.jl ecosystem and package roles

    master

    The JuliaPOMDP ecosystem is split into specialized packages to separate the core interface from implementations:

    • POMDPs.jl: The core interface package. It defines the standard way to express and solve both Markov Decision Processes (MDPs) and Partially Observable Markov Decision Processes (POMDPs). It supports both discrete and continuous state, action, and observation spaces.
    • POMDPTools.jl: Acts as the 'standard library' for the ecosystem. It provides common implementations that work with the POMDPs.jl interface, including policies, belief updaters, distributions, and simulators.
    • Solver/Support Packages: Various community-maintained packages that provide specific state-of-the-art solvers that plug into the POMDPs.jl interface.
  4. Understand the difference between `transition`, `gen`, and `@gen`

    master

    The distinction between these functions depends on whether you are implementing a problem (the model) or a solver/simulator.

    For Problem Implementers

    • transition: Implement this to define the state transition distribution. You can provide an explicit distribution or use an ImplicitDistribution if you only have a sampler.
    • gen: Implement this only if your simulator outputs multiple values (next state, observation, and reward) simultaneously (e.g., when rewards are tied to the movement between states).
    • @gen: Do not implement or modify this. It is a tool used by solvers and simulators.

    For Solver/Simulator Implementers

    • @gen: Call this to sample the next state, observation, and/or reward. It automatically orchestrates calls to rand, transition, observation, reward, and gen without overhead.
    • transition: Call this only when you need the explicit transition probability distribution.
    • gen: Do not call this directly. It is intended for problem implementers to use when defining joint distributions.
  5. Implement Distributions for POMDPs

    master

    A distribution object represents a probability distribution used within a POMDP (e.g., for transition or observation models). To ensure compatibility with solvers, your distribution object should implement the following functions:

    • rand([rng,] d): Samples from the distribution. Note: It is highly recommended to implement Base.rand(rng::AbstractRNG, s::Random.SamplerTrivial{<:YourDistribution}) to support both rand(d) and rand(rng, d) via the standard Julia rand interface.
    • support(d): Returns the set of values for which the distribution is defined.
    • pdf(d, x): Returns the probability density/mass function at x.
    • mode(d): Returns the mode of the distribution.
    • mean(d): Returns the mean of the distribution.

    For pre-made distributions, you can use Distributions.jl or POMDPTools.

  6. Understand the POMDPs.jl workflow

    master

    The standard workflow for using POMDPs.jl follows three sequential steps:

    1. Define a POMDP: Specify the problem structure (states, actions, observations, transitions, etc.).
    2. Solve the POMDP: Use a solver to compute an optimal or near-optimal policy from the defined problem.
    3. Simulate the policy: Run simulations using the computed policy to evaluate its performance in the environment.

    Most examples in the documentation are designed to be executed in this order. For instance, simulation examples typically assume a POMDP has already been defined and a policy has been computed using a solver.

  7. POMDP Simulation Inputs and Defaults

    master

    A POMDP simulation typically requires a pomdp model and a policy. Other inputs are optional and should be inferred using standard POMDPs.jl functions if not provided:

    InputTypeDefault/Inference Logic
    pomdpPOMDPRequired
    policyPolicyRequired
    upUpdaterup = updater(policy)
    b0Initial Beliefb0 = initialstate(pomdp)
    sInitial States = rand(initialstate(pomdp))
  8. How to define a solver in POMDPs.jl

    master

    To implement a new solver, you must provide four distinct components that work together to bridge the gap between problem definition and action selection:

    1. A Solver type: A subtype of Solver that stores the solver's configuration parameters and options.
    2. A Policy type: A subtype of Policy that holds the data/structures required to select actions (e.g., a value function for offline solvers or a search tree for online solvers).
    3. A solve method: A function with the signature solve(solver, problem) that performs the offline computation and returns the Policy object.
    4. An action method: A function with the signature action(policy, state_or_belief) that returns an action based on the current state or belief.

    Tip: You can often reuse existing Policy types from the POMDPTools package to satisfy requirements 2 and 4, allowing you to focus on the solve logic.

    # Conceptual structure of a solver
    # 1. Solver type (configuration)
    # 2. Policy type (data for action selection)
    # 3. solve(solver, problem) -> policy (offline work)
    # 4. action(policy, state_or_belief) -> action (online work)
  9. How solvers and policies work

    master

    Decision-making in POMDPs.jl is divided into offline and online components:

    Policy (Online)

    An agent uses a Policy (a subtype of the Policy abstract type) to make decisions during execution. The core method is action(policy, belief), which maps a belief to an action.

    • For online solvers (e.g., POMCP), most computation happens inside action.
    • For offline solvers (e.g., SARSOP), action performs minimal computation.

    Solver (Offline)

    A Solver (a subtype of the Solver abstract type) performs the heavy lifting of finding a policy. The core method is solve(solver, problem), which carries out the offline optimization or search.

  10. Use interface extensions for optimized model operations

    master

    POMDPTools provides interface extensions that act as shortcuts for common tasks. While these have default implementations based on the core POMDPs.jl interface, you should use them whenever possible because they allow for optimized implementations if available.

    Key extensions include:

    • Weighted Iteration: Use weighted_iterator to iterate through value => probability pairs of a distribution. This is more efficient than looking up probability mass for every value when the distribution support is large.
    • Observation Weight: Use obs_weight to get the relative likelihood of an observation. This is useful for algorithms like particle filtering where you need the likelihood without implementing a full custom observation distribution.
    • Ordered Spaces: Since POMDPs.jl does not guarantee that spaces are ordered consistently with their index function, use ordered_actions, ordered_states, or ordered_observations to get lists that are guaranteed to match the indexing order.
  11. Represent state, action, and observation spaces

    master

    In POMDPs.jl, states, actions, and observations can be any Julia object (integers, strings, vectors, etc.).

    Best Practices

    • Immutability: Use immutable objects (like Int, Float64, or StaticArrays) for states, actions, and observations. They are often used as dictionary keys or in histories. If you must use mutable objects, ensure hash and == are correctly implemented (e.g., using AutoHashEquals.jl).
    • Explicit vs. Implicit Spaces: You can define spaces using the states, actions, or observations keyword arguments with a Vector. However, for continuous or hybrid spaces, you often only need to specify the type using statetype or obstype (e.g., obstype = Float64). Many solvers do not require an explicit enumeration of the space.

    State- or Belief-dependent Action Spaces

    If the available actions depend on the current state (MDP) or belief (POMDP), pass a function to the actions argument instead of a vector.

    For MDPs (state-dependent):

    actions = function (s = nothing) 
        if s == 1
            return [1]
        else
            return [1,2,3]
        end
    end

    For POMDPs (belief-dependent):

    actions = function (b)
        if pdf(b, 1) > 0.0
            return [1,2,3]
        else
            return [2,3]
        end
    end