Skip to main content

Negative Weight Mapping - a non-parametric reinforcement learning framework using persistent potential fields

Project description

NWM — Negative Weight Mapping

A non-parametric reinforcement learning framework built on persistent potential fields.

PyPI Python License: MIT Code style: ruff Typed: mypy strict

NWM turns an agent's past experience into a potential force field over the observation space. Instead of training a neural network by gradient descent, it remembers where things went well or badly and acts by following forces:

  • Attractive forces pull the agent toward actions that succeeded before.
  • Repulsive forces push it away from actions that led to failure.

The result is a transparent, reproducible, dependency-light agent (NumPy + Gymnasium) that starts behaving sensibly from very few episodes.

What's new in 2.0src/ layout, reproducible seeding, an incremental query cache, strict typing, an extended benchmark suite vs. Random / tabular Q-learning / DQN, and an accompanying LaTeX paper. See the CHANGELOG.

Key ideas

Mechanism What it does
Potential field Maps states to per-action attractive/repulsive forces.
Persistent memory Experiences merge into bounded centroids with progressive stiffness.
Dynamic Smart Lock Protects high-confidence memories from being overwritten.
Fear & Greed Rejects dangerous actions before maximizing reward.
Adaptive exploration Collapses exploration once performance is high.

Installation

pip install nwm-rl

From source (with development and benchmark extras):

git clone https://github.com/CastermustOfficial/NWM.git
cd NWM
pip install -e ".[dev,benchmark]"

Extras: plots (matplotlib), baselines (torch, for the DQN baseline), benchmark (both + pandas), dev (ruff, mypy, pytest, pre-commit).

Quick start

import gymnasium as gym
from nwm import NWM

env = gym.make("CartPole-v1")
agent = NWM(
    state_dim=env.observation_space.shape[0],
    num_actions=env.action_space.n,
    seed=0,  # reproducible: no global RNG state touched
)

for episode in range(200):
    state, _ = env.reset(seed=episode)
    done = False
    while not done:
        action = agent.select_action(state)
        next_state, reward, terminated, truncated, _ = env.step(action)
        done = terminated or truncated
        agent.step(state, action, reward, next_state, done)
        state = next_state
    print(f"Episode {episode + 1}: best={agent.best_reward:.0f}")

env.close()

More examples live in examples/: quickstart.py, cartpole_training.py (with plotting/demo), and custom_environment.py.

API overview

from nwm import NWM, NWMConfig, set_global_seed

set_global_seed(42)  # seeds Python / NumPy / torch for the whole experiment

config = NWMConfig(
    max_centroids=500,      # memory capacity
    warmup_episodes=50,     # pure-exploration episodes before learning
    exploration_rate=1.0,   # initial epsilon
    exploration_decay=0.99,
    min_exploration=0.05,
    merge_threshold=0.3,    # distance below which experiences merge
    distance_cutoff=2.5,    # max influence radius
    seed=42,
)

agent = NWM(state_dim=4, num_actions=2, config=config)
action = agent.select_action(state, training=True)
agent.step(state, action, reward, next_state, done)
stats = agent.get_stats()
agent.save("agent.pkl")
agent = NWM.load("agent.pkl")   # restores the RNG stream too

Benchmarks

A reproducible harness compares NWM against Random, tabular Q-learning, and DQN across a difficulty gradient of Gymnasium tasks (CartPole, Acrobot, MountainCar), over 5 seeds with a fixed greedy-evaluation protocol.

python -m benchmarks.run_benchmark --quick            # fast smoke run
python -m benchmarks.run_benchmark --seeds 0 1 2 3 4  # full protocol

Outputs land in results/: per-run JSON, an aggregated summary.csv, a Markdown table, and learning-curve / comparison plots. The accompanying paper in paper/ is built from exactly these numbers.

Final greedy evaluation (mean ± std over 5 seeds; higher is better — Acrobot and MountainCar returns are negative). Best per environment in bold:

Environment Random TabularQ DQN NWM
CartPole-v1 25.1 ± 3.2 98.4 ± 20.2 100.8 ± 30.3 159.8 ± 94.0
Acrobot-v1 −499.9 ± 0.3 −423.1 ± 53.5 −165.8 ± 111.3 −307.9 ± 157.7
MountainCar-v0 −200.0 ± 0.0 −200.0 ± 0.0 −174.6 ± 31.2 −200.0 ± 0.0

Takeaways. NWM is the strongest method on dense, low-dimensional CartPole; it learns on Acrobot but trails DQN; and on sparse-reward MountainCar every non-bootstrapping method (NWM, tabular Q, Random) stays at the floor — a transparent illustration of where instance-based potential fields help and where value bootstrapping is needed. See paper/ for the full analysis.

Paper

The method is formalized and evaluated in a short paper under paper/. Build it with cd paper && latexmk -pdf nwm.tex (see paper/README.md). Tables and figures are regenerated from the benchmark via python paper/make_paper_assets.py.

Project structure

NWM/
├── src/nwm/            # library (installed package)
│   ├── agents/         # NWMAgent
│   ├── core/           # centroid + potential field
│   ├── utils/          # configuration
│   └── seeding.py      # reproducibility helpers
├── benchmarks/         # reproducible benchmark suite + baselines
├── examples/           # runnable usage examples
├── paper/              # LaTeX paper + asset generation
├── tests/              # pytest suite (unit + integration)
└── results/            # benchmark outputs (generated)

Development

pip install -e ".[dev,benchmark]"
pre-commit install
ruff check . && ruff format --check .   # lint + format
mypy                                    # strict static typing
pytest --cov=nwm                        # tests + coverage

See CONTRIBUTING.md for the full workflow.

Citation

@software{nwm2026,
  title   = {NWM: Negative Weight Mapping — A Non-Parametric Potential-Field
             Framework for Reinforcement Learning},
  author  = {CastermustOfficial},
  year    = {2026},
  url     = {https://github.com/CastermustOfficial/NWM},
  version = {2.0.0}
}

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nwm_rl-2.0.0.tar.gz (26.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nwm_rl-2.0.0-py3-none-any.whl (20.1 kB view details)

Uploaded Python 3

File details

Details for the file nwm_rl-2.0.0.tar.gz.

File metadata

  • Download URL: nwm_rl-2.0.0.tar.gz
  • Upload date:
  • Size: 26.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for nwm_rl-2.0.0.tar.gz
Algorithm Hash digest
SHA256 2729d668452a7c4ef8edc829eb140d4026136edafb349b0c252b0c8cc4a776e1
MD5 d469723a2b5ac4a00756931c052997e8
BLAKE2b-256 0a533b744da8650236df409b010681329354208c2cfa1778f833b24a33a6e48d

See more details on using hashes here.

File details

Details for the file nwm_rl-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: nwm_rl-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 20.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for nwm_rl-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8bab65c1d3228848dae82f1c6a181df22af8144cbfb2225db8f6ab3ff842cbd8
MD5 9f124f6bd26cd3b1351151142b6f1154
BLAKE2b-256 8999e370420bce5aedabd2ed3ca4bfbb99f4464d715e26bf4e58cee9d8815991

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page