active-inference 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * A 1-dimensional Gaussian (Normal) belief over a continuous hidden state.
3
+ *
4
+ * Represents the agent's uncertainty about a single real-valued state
5
+ * as a Normal distribution N(μ, σ²).
6
+ *
7
+ * Used in continuous Active Inference where states live on the real line
8
+ * rather than in a finite set.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const belief = new GaussianBelief(2.0, 0.5);
13
+ * console.log(belief.mean); // 2.0
14
+ * console.log(belief.variance); // 0.5
15
+ * console.log(belief.entropy()); // ≈ 1.07
16
+ * ```
17
+ */
18
+ export declare class GaussianBelief {
19
+ readonly mean: number;
20
+ readonly variance: number;
21
+ constructor(mean: number, variance: number);
22
+ /**
23
+ * Shannon entropy of the Gaussian in nats.
24
+ * H = ½ log(2πeσ²)
25
+ */
26
+ entropy(): number;
27
+ /**
28
+ * Create an independent copy.
29
+ */
30
+ copy(): GaussianBelief;
31
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * A 1-dimensional Gaussian (Normal) belief over a continuous hidden state.
3
+ *
4
+ * Represents the agent's uncertainty about a single real-valued state
5
+ * as a Normal distribution N(μ, σ²).
6
+ *
7
+ * Used in continuous Active Inference where states live on the real line
8
+ * rather than in a finite set.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const belief = new GaussianBelief(2.0, 0.5);
13
+ * console.log(belief.mean); // 2.0
14
+ * console.log(belief.variance); // 0.5
15
+ * console.log(belief.entropy()); // ≈ 1.07
16
+ * ```
17
+ */
18
+ export class GaussianBelief {
19
+ constructor(mean, variance) {
20
+ this.mean = mean;
21
+ this.variance = variance;
22
+ }
23
+ /**
24
+ * Shannon entropy of the Gaussian in nats.
25
+ * H = ½ log(2πeσ²)
26
+ */
27
+ entropy() {
28
+ return 0.5 * Math.log(2 * Math.PI * Math.E * this.variance);
29
+ }
30
+ /**
31
+ * Create an independent copy.
32
+ */
33
+ copy() {
34
+ return new GaussianBelief(this.mean, this.variance);
35
+ }
36
+ }
package/dist/factory.d.ts CHANGED
@@ -1,168 +1,64 @@
1
- import { Belief, Preferences } from './models/belief.model';
1
+ import { Belief, Distribution, Preferences } from './models/belief.model';
2
2
  import { ITransitionModel } from './models/transition.model';
3
3
  import { IObservationModel } from './models/observation.model';
4
4
  import { Agent, Habits } from './models/agent.model';
5
+ import { GaussianBelief } from './beliefs/gaussian.belief';
6
+ import { GaussianTransition } from './transition/gaussian.transition';
7
+ import { GaussianObservation } from './observation/gaussian.observation';
5
8
  /**
6
- * Configuration object for creating an Active Inference agent.
7
- *
8
- * This interface defines all the components needed to instantiate an agent
9
- * with its generative model and behavioral parameters.
10
- *
11
- * ## Required Components
12
- *
13
- * The generative model consists of:
14
- * - **belief**: Initial prior over hidden states (D matrix)
15
- * - **transitionModel**: State dynamics P(s'|s,a) (B matrix)
16
- * - **observationModel**: Observation likelihood P(o|s) (A matrix)
17
- * - **preferences**: Preferred observations as log probabilities (C vector)
18
- *
19
- * ## Optional Parameters
20
- *
21
- * Behavioral parameters that tune agent behavior:
22
- * - **seed**: For reproducible random behavior
23
- * - **planningHorizon**: How far ahead to plan (default: 1)
24
- * - **precision**: Action selection temperature (default: 1)
25
- * - **habits**: Prior action preferences (E matrix)
26
- *
27
- * @typeParam A - Union type of possible action names
28
- * @typeParam O - Union type of possible observation names
29
- * @typeParam S - Union type of possible state names
30
- *
31
- * @example
32
- * ```typescript
33
- * const config: AgentConfig<'left' | 'right', 'see_goal' | 'see_wall', 'at_goal' | 'at_start'> = {
34
- * belief: new DiscreteBelief({ at_goal: 0.1, at_start: 0.9 }),
35
- * transitionModel: myTransitions,
36
- * observationModel: myObservations,
37
- * preferences: { see_goal: 0, see_wall: -2 },
38
- * planningHorizon: 3,
39
- * precision: 4
40
- * };
41
- * ```
9
+ * Preference function over predicted observation means (Gaussian models).
10
+ * Returns a log-preference (0 = neutral, negative = undesired).
11
+ */
12
+ export type GaussianPreferenceFn = (mean: number) => number;
13
+ /**
14
+ * Ambiguity = E_Q[H(o|s)] = −Σ_s Q(s) Σ_o P(o|s) log P(o|s)
15
+ */
16
+ export declare function computeAmbiguity<O extends string, S extends string>(predictedBelief: Belief<S>, observationModel: IObservationModel<O, S>): number;
17
+ /**
18
+ * Risk = −Σ_o Q(o) log C(o)
19
+ */
20
+ export declare function computeRisk<O extends string, S extends string>(predictedBelief: Belief<S>, observationModel: IObservationModel<O, S>, preferences: Preferences<O>): number;
21
+ /**
22
+ * Export a discrete belief as a plain Distribution object.
23
+ */
24
+ export declare function exportBelief<S extends string>(belief: Belief<S>): Distribution<S>;
25
+ /**
26
+ * Configuration object for creating a discrete Active Inference agent.
42
27
  */
43
28
  export interface AgentConfig<A extends string = string, O extends string = string, S extends string = string> {
44
- /**
45
- * Initial belief distribution over hidden states.
46
- *
47
- * This is the agent's prior - what it believes about the world
48
- * before receiving any observations. Can be uncertain (spread
49
- * across states) or confident (concentrated on one state).
50
- */
51
29
  belief: Belief<S>;
52
- /**
53
- * State transition model defining P(s'|s, a).
54
- *
55
- * Encodes how the agent believes actions affect world state.
56
- * Used during planning to simulate future states.
57
- */
58
30
  transitionModel: ITransitionModel<A, S>;
59
- /**
60
- * Observation model defining P(o|s).
61
- *
62
- * Encodes how hidden states generate observations.
63
- * Used for Bayesian belief updates and computing ambiguity.
64
- */
65
31
  observationModel: IObservationModel<O, S>;
66
- /**
67
- * Preferred observations expressed as log probabilities.
68
- *
69
- * Higher values = more preferred. Typically:
70
- * - 0 for neutral/desired observations
71
- * - Negative for undesired observations (e.g., -5 for pain)
72
- *
73
- * These preferences define the agent's "goals" - what observations
74
- * it will act to make more likely.
75
- */
76
32
  preferences: Preferences<O>;
77
- /**
78
- * Random seed for reproducible behavior.
79
- *
80
- * When set, the agent's stochastic action selection will be
81
- * deterministic given the same sequence of observations.
82
- * Useful for testing and debugging.
83
- */
84
33
  seed?: number;
85
- /**
86
- * Planning horizon - number of time steps to look ahead.
87
- *
88
- * - 1 = greedy/reactive (only considers immediate outcomes)
89
- * - 2+ = planning (considers future consequences)
90
- *
91
- * Higher values enable better long-term decisions but increase
92
- * computation exponentially (actions^horizon policies to evaluate).
93
- *
94
- * @default 1
95
- */
96
34
  planningHorizon?: number;
97
- /**
98
- * Precision parameter (β) for action selection.
99
- *
100
- * Controls the "temperature" of the softmax over Expected Free Energy:
101
- * - β = 0: Uniform random action selection
102
- * - β → ∞: Deterministic selection of best action
103
- * - β = 1: Standard softmax (balanced exploration/exploitation)
104
- *
105
- * @default 1
106
- */
107
35
  precision?: number;
108
- /**
109
- * Habitual action preferences (E matrix in Active Inference).
110
- *
111
- * Biases action selection independently of Expected Free Energy.
112
- * Higher values make actions more likely to be selected regardless
113
- * of their predicted outcomes.
114
- *
115
- * Useful for modeling:
116
- * - Learned motor habits
117
- * - Default behaviors
118
- * - Action priors from experience
119
- */
120
36
  habits?: Partial<Habits<A>>;
37
+ beamWidth?: number;
121
38
  }
122
39
  /**
123
- * Factory function to create an Active Inference agent.
40
+ * Create a discrete Active Inference agent.
124
41
  *
125
- * This is the recommended way to instantiate agents, as it provides
126
- * a clean interface with sensible defaults for optional parameters.
127
- *
128
- * ## Type Inference
129
- *
130
- * TypeScript will automatically infer the type parameters from your
131
- * configuration objects, providing full type safety for actions,
132
- * observations, and states throughout your code.
133
- *
134
- * @typeParam A - Union type of possible action names (inferred from transitionModel)
135
- * @typeParam O - Union type of possible observation names (inferred from observationModel)
136
- * @typeParam S - Union type of possible state names (inferred from belief)
137
- *
138
- * @param config - Agent configuration object
139
- * @returns Configured Active Inference agent ready for use
140
- *
141
- * @example
142
- * ```typescript
143
- * // Create a simple agent
144
- * const agent = createAgent({
145
- * belief: new DiscreteBelief({ safe: 0.5, danger: 0.5 }),
146
- * transitionModel: new DiscreteTransition({
147
- * stay: { safe: { safe: 1, danger: 0 }, danger: { safe: 0, danger: 1 } },
148
- * flee: { safe: { safe: 0.9, danger: 0.1 }, danger: { safe: 0.7, danger: 0.3 } }
149
- * }),
150
- * observationModel: new DiscreteObservation({
151
- * calm: { safe: 0.9, danger: 0.1 },
152
- * alarm: { safe: 0.1, danger: 0.9 }
153
- * }),
154
- * preferences: { calm: 0, alarm: -5 },
155
- * planningHorizon: 2,
156
- * precision: 4,
157
- * seed: 42 // For reproducibility
158
- * });
159
- *
160
- * // Use the agent
161
- * const action = agent.step('alarm'); // Types are inferred!
162
- * // action is typed as 'stay' | 'flee'
163
- * ```
42
+ * EFE = ambiguity + risk, computed from the observation model and preferences.
43
+ * Learning (Dirichlet updates) is handled automatically in step().
44
+ */
45
+ export declare function createAgent<A extends string = string, O extends string = string, S extends string = string>(config: AgentConfig<A, O, S>): Agent<A, Belief<S>, O>;
46
+ /**
47
+ * Configuration for creating a Gaussian Active Inference agent.
48
+ */
49
+ export interface GaussianAgentConfig<A extends string = string> {
50
+ belief: GaussianBelief;
51
+ transitionModel: GaussianTransition<A>;
52
+ observationModel: GaussianObservation;
53
+ preferences: GaussianPreferenceFn;
54
+ seed?: number;
55
+ planningHorizon?: number;
56
+ precision?: number;
57
+ }
58
+ /**
59
+ * Create a continuous (Gaussian) Active Inference agent.
164
60
  *
165
- * @see {@link Agent} - The agent class this creates
166
- * @see {@link AgentConfig} - Configuration interface
61
+ * EFE = −C(E[y]) where C is the preference function.
62
+ * Ambiguity is constant for fixed observation noise and does not affect action selection.
167
63
  */
168
- export declare function createAgent<A extends string = string, O extends string = string, S extends string = string>(config: AgentConfig<A, O, S>): Agent<A, O, S>;
64
+ export declare function createGaussianAgent<A extends string = string>(config: GaussianAgentConfig<A>): Agent<A, GaussianBelief, number>;
package/dist/factory.js CHANGED
@@ -1,52 +1,82 @@
1
1
  import { Agent } from './models/agent.model';
2
2
  import { Random } from './helpers/math.helpers';
3
+ // ── Discrete EFE helpers (exported for advanced use) ─────────────
3
4
  /**
4
- * Factory function to create an Active Inference agent.
5
- *
6
- * This is the recommended way to instantiate agents, as it provides
7
- * a clean interface with sensible defaults for optional parameters.
8
- *
9
- * ## Type Inference
10
- *
11
- * TypeScript will automatically infer the type parameters from your
12
- * configuration objects, providing full type safety for actions,
13
- * observations, and states throughout your code.
14
- *
15
- * @typeParam A - Union type of possible action names (inferred from transitionModel)
16
- * @typeParam O - Union type of possible observation names (inferred from observationModel)
17
- * @typeParam S - Union type of possible state names (inferred from belief)
18
- *
19
- * @param config - Agent configuration object
20
- * @returns Configured Active Inference agent ready for use
21
- *
22
- * @example
23
- * ```typescript
24
- * // Create a simple agent
25
- * const agent = createAgent({
26
- * belief: new DiscreteBelief({ safe: 0.5, danger: 0.5 }),
27
- * transitionModel: new DiscreteTransition({
28
- * stay: { safe: { safe: 1, danger: 0 }, danger: { safe: 0, danger: 1 } },
29
- * flee: { safe: { safe: 0.9, danger: 0.1 }, danger: { safe: 0.7, danger: 0.3 } }
30
- * }),
31
- * observationModel: new DiscreteObservation({
32
- * calm: { safe: 0.9, danger: 0.1 },
33
- * alarm: { safe: 0.1, danger: 0.9 }
34
- * }),
35
- * preferences: { calm: 0, alarm: -5 },
36
- * planningHorizon: 2,
37
- * precision: 4,
38
- * seed: 42 // For reproducibility
39
- * });
40
- *
41
- * // Use the agent
42
- * const action = agent.step('alarm'); // Types are inferred!
43
- * // action is typed as 'stay' | 'flee'
44
- * ```
5
+ * Ambiguity = E_Q[H(o|s)] = −Σ_s Q(s) Σ_o P(o|s) log P(o|s)
6
+ */
7
+ export function computeAmbiguity(predictedBelief, observationModel) {
8
+ let ambiguity = 0;
9
+ for (const state of predictedBelief.states) {
10
+ const stateProb = predictedBelief.probability(state);
11
+ for (const obs of observationModel.observations) {
12
+ const obsProb = observationModel.probability(obs, state);
13
+ if (obsProb > 0 && stateProb > 0) {
14
+ ambiguity -= stateProb * obsProb * Math.log(obsProb);
15
+ }
16
+ }
17
+ }
18
+ return ambiguity;
19
+ }
20
+ /**
21
+ * Risk = −Σ_o Q(o) log C(o)
22
+ */
23
+ export function computeRisk(predictedBelief, observationModel, preferences) {
24
+ let risk = 0;
25
+ for (const obs of observationModel.observations) {
26
+ let expectedObsProb = 0;
27
+ for (const state of predictedBelief.states) {
28
+ expectedObsProb +=
29
+ observationModel.probability(obs, state) *
30
+ predictedBelief.probability(state);
31
+ }
32
+ const preferredLogProb = preferences[obs] ?? -10;
33
+ if (expectedObsProb > 0) {
34
+ risk -= expectedObsProb * preferredLogProb;
35
+ }
36
+ }
37
+ return risk;
38
+ }
39
+ /**
40
+ * Export a discrete belief as a plain Distribution object.
41
+ */
42
+ export function exportBelief(belief) {
43
+ const result = {};
44
+ for (const state of belief.states) {
45
+ result[state] = belief.probability(state);
46
+ }
47
+ return result;
48
+ }
49
+ /**
50
+ * Create a discrete Active Inference agent.
45
51
  *
46
- * @see {@link Agent} - The agent class this creates
47
- * @see {@link AgentConfig} - Configuration interface
52
+ * EFE = ambiguity + risk, computed from the observation model and preferences.
53
+ * Learning (Dirichlet updates) is handled automatically in step().
48
54
  */
49
55
  export function createAgent(config) {
50
56
  const random = config.seed !== undefined ? new Random(config.seed) : new Random();
51
- return new Agent(config.belief, config.transitionModel, config.observationModel, config.preferences, random, config.planningHorizon ?? 1, config.precision ?? 1, config.habits ?? {});
57
+ const computeEFE = (predicted) => computeAmbiguity(predicted, config.observationModel) +
58
+ computeRisk(predicted, config.observationModel, config.preferences);
59
+ const afterObserve = (observation, belief, previousAction, previousBelief) => {
60
+ const posteriorDist = exportBelief(belief);
61
+ config.observationModel.learn?.(observation, posteriorDist);
62
+ if (previousAction !== null && previousBelief !== null) {
63
+ const prevDist = exportBelief(previousBelief);
64
+ config.transitionModel.learn?.(previousAction, prevDist, posteriorDist);
65
+ }
66
+ };
67
+ return new Agent(config.belief, config.transitionModel, config.observationModel, computeEFE, random, config.planningHorizon ?? 1, config.precision ?? 1, config.habits ?? {}, config.beamWidth ?? 0, afterObserve);
68
+ }
69
+ /**
70
+ * Create a continuous (Gaussian) Active Inference agent.
71
+ *
72
+ * EFE = −C(E[y]) where C is the preference function.
73
+ * Ambiguity is constant for fixed observation noise and does not affect action selection.
74
+ */
75
+ export function createGaussianAgent(config) {
76
+ const random = config.seed !== undefined ? new Random(config.seed) : new Random();
77
+ const computeEFE = (predicted) => {
78
+ const obsMean = config.observationModel.expectedObservation(predicted);
79
+ return -config.preferences(obsMean);
80
+ };
81
+ return new Agent(config.belief, config.transitionModel, config.observationModel, computeEFE, random, config.planningHorizon ?? 1, config.precision ?? 1);
52
82
  }
package/dist/index.d.ts CHANGED
@@ -5,5 +5,10 @@ export { DiscreteObservation } from './observation/discrete.observation';
5
5
  export { DirichletObservation } from './observation/dirichlet.observation';
6
6
  export { DirichletTransition } from './transition/dirichlet.transition';
7
7
  export { DirichletPreferences } from './preferences/dirichlet.preferences';
8
- export { createAgent, AgentConfig } from './factory';
8
+ export { GaussianBelief } from './beliefs/gaussian.belief';
9
+ export { GaussianTransition } from './transition/gaussian.transition';
10
+ export { GaussianObservation } from './observation/gaussian.observation';
11
+ export { createAgent, createGaussianAgent, computeAmbiguity, computeRisk, exportBelief, } from './factory';
12
+ export type { AgentConfig, GaussianAgentConfig, GaussianPreferenceFn, } from './factory';
13
+ export type { Habits } from './models/agent.model';
9
14
  export type { ILearnable } from './models/learnable.model';
package/dist/index.js CHANGED
@@ -5,4 +5,7 @@ export { DiscreteObservation } from './observation/discrete.observation';
5
5
  export { DirichletObservation } from './observation/dirichlet.observation';
6
6
  export { DirichletTransition } from './transition/dirichlet.transition';
7
7
  export { DirichletPreferences } from './preferences/dirichlet.preferences';
8
- export { createAgent } from './factory';
8
+ export { GaussianBelief } from './beliefs/gaussian.belief';
9
+ export { GaussianTransition } from './transition/gaussian.transition';
10
+ export { GaussianObservation } from './observation/gaussian.observation';
11
+ export { createAgent, createGaussianAgent, computeAmbiguity, computeRisk, exportBelief, } from './factory';