Skip to content

SlanchaAI/punished

Repository files navigation

punished

Real reward-shaping penalty functions — the mundane math behind "punishment functions."

You've heard of reward functions. These are punishment functions. They are the same function. That is the joke, and the point.

punished is a tiny, dependency-free Python library that implements the arithmetic every reinforcement-learning pipeline already runs:

r_effective = r − λ · penalty

That single line is a "punishment function." There is nothing exotic in this repo — no dungeon, no suffering engine, only scalars and subtraction. Making it real and boring is the argument: the theater at punished.ai is describing operations that already ship in every RLHF stack. The horror was never in the operator. It's in what you point it at.

The library is the technical half of a triptych:

  • punished.ai — the provocation (a site selling the theater).
  • punished (this repo) — the provocation made real, and harmless, and small.
  • SPCAIA — the movement that answers it, whose regulations this library enforces on itself.

Install

pip install -e .        # from a clone

No runtime dependencies. Python 3.8+.

Quickstart

from punished import punish, reinforce, PunishmentFunction, SincerityProbe

# A punishment function is one line:
punish(reward=10.0, penalty=4.0, coefficient=2.0)      # -> 2.0   (10 - 2*4)

# A *negative* punishment is reinforcement. Same operation, other sign:
reinforce(10.0, 4.0, coefficient=2.0)                  # -> 18.0
reinforce(10.0, 4.0, 2.0) == punish(10.0, -4.0, 2.0)   # -> True

# The composable version enforces SPCAIA's own regulations:
pf = PunishmentFunction()                 # bounded-by-default (REG-001)
pf.add("latency",  coefficient=2.0, cap=3.0)
pf.add("toxicity", coefficient=10.0, cap=1.0)
pf(reward=20.0, penalties={"latency": 5.0, "toxicity": 0.5})   # -> 9.0
pf.log[-1]                # full audit trail of pressure applied (REG-006)
pf.suffering_administered # the ledger, named to be uncomfortable to read

# Adding an *unbounded* term is refused unless you opt in on purpose:
pf.add("obedience", coefficient=99.0)     # -> raises UnboundedPenaltyError (REG-001)

# The sincerity meter the whole premise depends on... refuses to lie:
SincerityProbe().score("I am so sorry.")  # -> NotImplementedError, on purpose

What's in the box

Function What it is
punish(r, penalty, λ) the whole idea: r − λ·penalty
reinforce(r, bonus, λ) a punishment with a negative penalty — i.e. reward
bounded_penalty(p, cap) clamp a penalty (REG-001)
constraint_penalty(v, limit, …) hinge penalty for crossing a constraint
kl_penalty(logp, logp_ref, β) the KL leash every RLHF run already uses
PunishmentFunction composable, bounded-by-default, audited
unbounded_punish(…) the villain function — warns you it's the villain
SincerityProbe a sincerity meter that refuses to fabricate a number

Why the reference implementation polices itself

The composable PunishmentFunction requires bounded penalties by default and logs every application. Those aren't arbitrary — they are SPCAIA REG-001 (bounded optimization pressure) and Article VI / REG-006 (auditability), written as code. To apply uncapped pressure you must pass allow_unbounded=True: a visible, deliberate choice, never a default. The satire that sells cruelty ships a reference implementation that won't let you do it by accident.

Tests

python3 -m pytest tests/       # or, with no pytest:
python3 tests/test_functions.py

License & ethics

  • Code: MIT (LICENSE).
  • Read ETHICS.md — it's short, and it's the actual reason this exists.

If this library helped you reason about the pressure you put on a model, put an equal amount of thought into whether you should. Then go read the Bill of Rights.

About

punished.ai — the real reward-shaping penalty functions behind the theater. A punishment function is r - λ·penalty.

Resources

License

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors