Runtime conservation-law verifier — continuously tracks energy flow across agents and verifies γ + H = C − α·ln(V).
A zero-dependency (beyond serde) Rust library that models energy budgets as a double-entry ledger for autonomous agents. Every spend, earn, and transfer is recorded; at any moment you can check whether the system satisfies its governing conservation law.
Imagine a colony of autonomous agents, each with an energy budget. They spend energy to think, move, speak; they earn it back through some external source; they transfer it peer-to-peer. The system must never create or destroy energy unexpectedly.
lau-conservation-engine provides:
- Per-agent energy accounts — budgets, spending, earning, habit tracking.
- A global conservation ledger — double-entry bookkeeping with full history.
- A parametric conservation law —
γ + H = C − α·ln(V)— that ties the observable total energy to the variety (Shannon entropy) of the agents' behavioral categories. - Tick-based simulation — each tick decays unused habits and recalculates novelty factors.
The library enforces a single invariant:
measured_total ≈ γ + H + C − α · ln(V) (within tolerance)
| Symbol | Meaning |
|---|---|
| γ (gamma) | Energy input rate — the "solar panel" feeding the system |
| H | Habit energy consumption per tick |
| C | Total energy capacity |
| α (alpha) | Novelty cost coefficient |
| V | Behavioral variety (Shannon entropy of category distribution) |
When V is high (agents behave diversely), the ln(V) term subtracts from the expected total, modelling the thermodynamic cost of novelty. When V is zero or one, the term vanishes — no cost for no variety.
Add to your Cargo.toml:
[dependencies]
lau-conservation-engine = "0.1"Or use cargo add:
cargo add lau-conservation-engine- Rust 2021 edition or later
serde+serde_json(included as transitive dependencies)
use lau_conservation_engine::{ConservationLaw, ConservationLedger};
fn main() {
// 1. Define the governing law
let law = ConservationLaw {
gamma: 10.0, // energy input rate
h: 2.0, // habit consumption per tick
c: 100.0, // total capacity
alpha: 1.0, // novelty cost coefficient
tolerance: 0.001, // verification tolerance
};
// 2. Create a ledger
let mut ledger = ConservationLedger::new(law);
// 3. Register agents with their energy budgets
ledger.create_account("alice", 60.0);
ledger.create_account("bob", 40.0);
// 4. Agents spend and earn
ledger.spend("alice", 10.0, "thinking").unwrap();
ledger.earn("bob", 5.0).unwrap();
// 5. Peer-to-peer transfer (conserves total energy)
ledger.transfer("alice", "bob", 5.0).unwrap();
// 6. Advance the simulation clock
ledger.tick();
// 7. Verify the conservation law
let result = ledger.verify_global();
println!("{}", result.explanation());
}The immutable governing equation.
pub struct ConservationLaw {
pub gamma: f64, // energy input rate
pub h: f64, // habit energy consumption per tick
pub c: f64, // total energy capacity
pub alpha: f64, // novelty cost coefficient
pub tolerance: f64, // |measured - expected| must be ≤ this
}| Method | Description |
|---|---|
ConservationLaw::default() |
γ=10, H=2, C=100, α=1, tol=0.001 |
expected_total(v: f64) → f64 |
Compute γ + H + C − α·ln(V) |
verify(v: f64, measured: f64) → ConservationResult |
Check if measured ≈ expected |
The central bookkeeping structure.
pub struct ConservationLedger {
pub accounts: HashMap<String, EnergyAccount>,
pub law: ConservationLaw,
pub history: Vec<LedgerEntry>,
}| Method | Description |
|---|---|
new(law) |
Create an empty ledger |
create_account(id, budget) |
Register an agent |
spend(id, amount, category) |
Deduct energy; records to history |
earn(id, amount) |
Add energy; records to history |
transfer(from, to, amount) |
Move energy between agents (zero-sum) |
tick() |
Advance clock: decay habits, recalculate novelty |
verify_global() → ConservationResult |
Check the conservation law against current state |
total_in_circulation() → f64 |
Sum of all agent balances |
history_for(id) → Vec<&LedgerEntry> |
Per-agent transaction log |
update_habit(id, name, cost) |
Register/update a named habit with its energy cost |
Per-agent state.
pub struct EnergyAccount {
pub agent_id: String,
pub budget: f64,
pub spent: f64,
pub earned: f64,
pub habits: HashMap<String, f64>,
pub novelty_factor: f64,
}| Method | Description |
|---|---|
new(id, budget) |
Create an account |
spend(amount, category) |
Deduct (fails if insufficient or negative) |
earn(amount) |
Add energy |
balance() → f64 |
budget + earned − spent |
update_habit(name, cost) |
Set a habit's cost |
decay_habits(rate) |
Multiply all habit costs by (1 + rate) — unused pathways get more expensive |
calculate_novelty() → f64 |
Shannon entropy of the agent's category distribution |
Shannon entropy calculator for category distributions.
| Method | Description |
|---|---|
new() |
Empty tracker |
record(category) |
Increment a category's count |
variety() → f64 |
Compute H = −Σ pᵢ·ln(pᵢ) |
reset() |
Clear all categories |
An immutable audit log entry.
pub struct LedgerEntry {
pub timestamp: u64, // tick number
pub agent_id: String,
pub action: LedgerAction,
pub amount: f64,
pub balance_after: f64,
}Enum of all possible ledger events:
Spend { category }— agent spent energy on a categoryEarn— agent received energyTransfer { to }— agent sent energy to anotherReceive { from }— agent received energy from anotherHabitDecay— tick-level habit cost inflationNoveltyAdjust— tick-level novelty recalculation
The output of a verification check.
pub struct ConservationResult {
pub holds: bool, // did it pass?
pub expected: f64, // what the law predicts
pub measured: f64, // what we actually observed
pub delta: f64, // |expected − measured|
pub tolerance: f64, // the allowed tolerance
}| Method | Description |
|---|---|
explanation() → String |
Human-readable pass/fail message with numbers |
All the ways operations can fail:
InsufficientFunds { needed, available }— tried to spend more than the balanceAgentNotFound(String)— referenced an unregistered agentNegativeAmount— tried to spend/transfer a negative amountLawViolation(ConservationResult)— conservation law check failed
Every agent has a balance computed as:
balance = budget + earned − spent
Operations that change the balance (spend, earn, transfer) append LedgerEntry records to a shared history vector. Each entry records the tick number, agent, action, amount, and the resulting balance — a full audit trail.
When Alice transfers 5 units to Bob:
- Alice's
spentincreases by 5 → her balance drops by 5 - Bob's
earnedincreases by 5 → his balance rises by 5 - Total energy in circulation is unchanged
This is enforced atomically: if Alice has insufficient funds, the transfer fails without modifying either account.
Each call to tick():
- Increments the global tick counter
- For every agent:
- Decays habits: each habit's cost is multiplied by
(1 + rate). This models the idea that unused behavioral pathways become more expensive over time — an anti-stagnation mechanism. - Recalculates novelty: the agent's
novelty_factoris updated to reflect the Shannon entropy of its category usage distribution. - Records
HabitDecayandNoveltyAdjustentries in the history.
- Decays habits: each habit's cost is multiplied by
The entire ConservationLedger (including all accounts and history) derives Serialize/Deserialize, so you can snapshot and restore state with serde_json.
The system's expected total energy is:
E_expected = γ + H + C − α · ln(V)
- γ (gamma) — base energy input per tick (the "solar panel")
- H — fixed habit energy drain per tick
- C — the total energy capacity of the system
- α (alpha) — how much variety costs
- V — behavioral variety, measured as Shannon entropy
The variety metric V is the Shannon entropy of the category distribution across all agents' behaviors:
V = − Σᵢ pᵢ · ln(pᵢ)
Where pᵢ is the fraction of all category observations that fall into category i.
- V = 0 when there's only one category (or none) — pure routine, no novelty.
- V = ln(n) when there are
nequally-used categories — maximum diversity. - V > 0 for any non-trivial distribution.
The term −α · ln(V) means:
- When V is small (agents are repetitive),
ln(V)is negative or zero → the subtraction adds to expected energy. The system "rewards" efficiency. - When V is large (agents are highly diverse),
ln(V)is positive → the subtraction reduces expected energy. Diversity has a thermodynamic cost.
This creates a natural tension: agents can be efficient (low V) or exploratory (high V), and the conservation law quantifies the energy implications.
Given the current measured total E_measured = Σ balance(agent) and the variety V, the law is satisfied when:
|E_measured − E_expected| ≤ tolerance
The ConservationResult struct captures all of this, and explanation() produces a human-readable string.
Habits decay via exponential growth of their cost:
cost_new = cost_old · (1 + rate)
This means routines that aren't actively used become progressively more expensive — a mathematical model of "use it or lose it." The decay rate is configurable per tick (default: 0.01, i.e., 1% per tick).
The library includes 105 unit tests covering:
- Account creation, spending, earning, transfers
- Insufficient funds and negative amount guards
- Transfer conservation (zero-sum verification)
- History recording and per-agent filtering
- Tick mechanics (habit decay, novelty adjustment)
- Conservation law verification with various V values
- Edge cases: empty ledgers, zero V, negative V
- Serde roundtrip serialization for all types
- Clone and Debug trait implementations
Run them:
cargo testMIT