loanbook#

LoanBook relationship for tracking loans between borrowers and lenders.

This module implements the LoanBook relationship, a many-to-many connection between Borrower (firms) and Lender (banks) roles. It uses COO (Coordinate List) sparse format to efficiently store active loan contracts.

Design Philosophy#

The LoanBook uses a sparse edge-list representation rather than a dense (n_firms × n_banks) matrix. This design choice provides:

  1. Memory efficiency: O(active_loans) instead of O(n_firms × n_banks)

  2. Cache-friendly: Sequential access patterns for vectorized operations

  3. Dynamic growth: Amortized O(1) append via doubling strategy

  4. Fast aggregation: Vectorized sums using np.bincount and np.add.at

COO Format Structure#

The LoanBook stores five parallel arrays:

  • source_ids (borrower IDs)

  • target_ids (lender IDs)

  • principal (loan amounts)

  • rate (interest rates)

  • interest (cached: rate × principal)

  • debt (cached: principal × (1 + rate))

Only the first size entries in each array are valid. The remaining entries up to capacity are pre-allocated but unused.

Examples

Create empty LoanBook:

>>> from bamengine.relationships import LoanBook
>>> loans = LoanBook()
>>> loans.size
0
>>> loans.capacity
128

Append loans:

>>> import numpy as np
>>> loans.append_loans_for_lender(
...     lender_idx=0,
...     borrower_indices=np.array([1, 2, 3]),
...     amount=np.array([100.0, 150.0, 200.0]),
...     rate=np.array([0.02, 0.03, 0.02]),
... )
>>> loans.size
3

Aggregate debt by borrower:

>>> debt_per_borrower = loans.debt_per_borrower(n_borrowers=10)
>>> debt_per_borrower.shape
(10,)

Purge loans from bankrupt firms:

>>> bankrupt_firms = np.array([1, 5, 7])
>>> removed = loans.purge_borrowers(bankrupt_firms)
>>> removed
1

See also

Relationship

Base class with query methods

Borrower

Source role (firms)

Lender

Target role (banks)

Classes#

LoanBook

Sparse edge-list ledger for managing active loan contracts.