border_core/base/policy.rs
1//! Policy interface for reinforcement learning.
2//!
3//! This module defines the core interface for policies in reinforcement learning.
4//! A policy represents a decision-making strategy that maps observations to actions,
5//! which can be either deterministic or stochastic.
6
7use super::Env;
8use anyhow::Result;
9use serde::de::DeserializeOwned;
10use std::path::Path;
11
12/// A policy that maps observations to actions in a reinforcement learning environment.
13///
14/// This trait defines the interface for policies, which are the core decision-making
15/// components in reinforcement learning. A policy can be:
16/// - Deterministic: Always returns the same action for a given observation
17/// - Stochastic: Returns actions sampled from a probability distribution
18///
19/// # Type Parameters
20///
21/// * `E` - The environment type that this policy operates on
22///
23/// # Examples
24///
25/// A simple deterministic policy might look like:
26/// ```ignore
27/// struct SimplePolicy;
28///
29/// impl<E: Env> Policy<E> for SimplePolicy {
30/// fn sample(&mut self, obs: &E::Obs) -> E::Act {
31/// // Always return the same action for a given observation
32/// E::Act::default()
33/// }
34/// }
35/// ```
36///
37/// A stochastic policy might look like:
38/// ```ignore
39/// struct StochasticPolicy;
40///
41/// impl<E: Env> Policy<E> for StochasticPolicy {
42/// fn sample(&mut self, obs: &E::Obs) -> E::Act {
43/// // Sample an action from a probability distribution
44/// // based on the observation
45/// E::Act::random()
46/// }
47/// }
48/// ```
49pub trait Policy<E: Env> {
50 /// Samples an action given an observation from the environment.
51 ///
52 /// This method is the core of the policy interface, defining how the policy
53 /// makes decisions based on the current state of the environment.
54 ///
55 /// # Arguments
56 ///
57 /// * `obs` - The current observation from the environment
58 ///
59 /// # Returns
60 ///
61 /// An action to be taken in the environment
62 fn sample(&mut self, obs: &E::Obs) -> E::Act;
63}
64
65/// A trait for objects that can be configured and built from configuration files.
66///
67/// This trait provides a standardized way to create objects from configuration
68/// parameters, either directly or from YAML files. It is commonly used for
69/// creating policies, environments, and other components of a reinforcement
70/// learning system.
71///
72/// # Associated Types
73///
74/// * `Config` - The configuration type that can be deserialized from YAML
75///
76/// # Examples
77///
78/// ```ignore
79/// #[derive(Clone, Deserialize)]
80/// struct MyConfig {
81/// learning_rate: f32,
82/// hidden_size: usize,
83/// }
84///
85/// struct MyObject {
86/// config: MyConfig,
87/// }
88///
89/// impl Configurable for MyObject {
90/// type Config = MyConfig;
91///
92/// fn build(config: Self::Config) -> Self {
93/// Self { config }
94/// }
95/// }
96///
97/// // Build from a YAML file
98/// let obj = MyObject::build_from_path("config.yaml")?;
99/// ```
100pub trait Configurable {
101 /// The configuration type for this object.
102 ///
103 /// This type must implement `Clone` and `DeserializeOwned` to support
104 /// building from configuration files.
105 type Config: Clone + DeserializeOwned;
106
107 /// Builds a new instance of this object from the given configuration.
108 ///
109 /// # Arguments
110 ///
111 /// * `config` - The configuration parameters
112 ///
113 /// # Returns
114 ///
115 /// A new instance of the object
116 fn build(config: Self::Config) -> Self;
117
118 /// Builds a new instance from a YAML configuration file.
119 ///
120 /// This is a convenience method that reads a YAML file and builds
121 /// the object using the deserialized configuration.
122 ///
123 /// # Arguments
124 ///
125 /// * `path` - Path to the YAML configuration file
126 ///
127 /// # Returns
128 ///
129 /// A new instance of the object or an error if the file cannot be read
130 /// or parsed
131 fn build_from_path(path: impl AsRef<Path>) -> Result<Self>
132 where
133 Self: Sized,
134 {
135 let file = std::fs::File::open(path)?;
136 let rdr = std::io::BufReader::new(file);
137 let config = serde_yaml::from_reader(rdr)?;
138 Ok(Self::build(config))
139 }
140}