montana/Русский/Экономика/банк_времени/код/test_halving.py

250 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
test_halving.py — Unit tests для halving.py
Montana Protocol
Тестирование механизма халвинга эмиссии
"""
import unittest
from halving import halving_coefficient
class TestHalving(unittest.TestCase):
"""Тесты для механизма халвинга Montana"""
# ═══════════════════════════════════════════════════════════════════════
# BASIC HALVING
# ═══════════════════════════════════════════════════════════════════════
def test_halving_tau4_0(self):
"""τ₄ = 0: коэффициент 1.0 (первые 4 года)"""
self.assertEqual(halving_coefficient(0), 1.0)
def test_halving_tau4_1(self):
"""τ₄ = 1: коэффициент 0.5 (4-8 лет)"""
self.assertEqual(halving_coefficient(1), 0.5)
def test_halving_tau4_2(self):
"""τ₄ = 2: коэффициент 0.25 (8-12 лет)"""
self.assertEqual(halving_coefficient(2), 0.25)
def test_halving_tau4_3(self):
"""τ₄ = 3: коэффициент 0.125 (12-16 лет)"""
self.assertEqual(halving_coefficient(3), 0.125)
def test_halving_tau4_4(self):
"""τ₄ = 4: коэффициент 0.0625 (16-20 лет)"""
self.assertEqual(halving_coefficient(4), 0.0625)
# ═══════════════════════════════════════════════════════════════════════
# EXTENDED TIMELINE
# ═══════════════════════════════════════════════════════════════════════
def test_halving_tau4_10(self):
"""τ₄ = 10: коэффициент ~0.0009765625 (40-44 года)"""
expected = 1.0 / (2 ** 10)
self.assertEqual(halving_coefficient(10), expected)
self.assertAlmostEqual(halving_coefficient(10), 0.0009765625, places=10)
def test_halving_tau4_20(self):
"""τ₄ = 20: очень малый коэффициент (80-84 года)"""
expected = 1.0 / (2 ** 20)
self.assertEqual(halving_coefficient(20), expected)
self.assertAlmostEqual(halving_coefficient(20), 9.5367431640625e-07, places=15)
def test_halving_tau4_50(self):
"""τ₄ = 50: экстремально малый коэффициент (200-204 года)"""
expected = 1.0 / (2 ** 50)
self.assertEqual(halving_coefficient(50), expected)
# ═══════════════════════════════════════════════════════════════════════
# EMISSION CALCULATION
# ═══════════════════════════════════════════════════════════════════════
def test_emission_calculation_tau4_0(self):
"""Эмиссия для 100 участников, 600 сек каждый, τ₄ = 0"""
participants = 100
seconds_per_participant = 600
total_seconds = participants * seconds_per_participant
coef = halving_coefficient(0)
emission = total_seconds * coef
self.assertEqual(emission, 60_000) # 100 × 600 × 1.0
def test_emission_calculation_tau4_1(self):
"""Эмиссия для 100 участников, 600 сек каждый, τ₄ = 1"""
participants = 100
seconds_per_participant = 600
total_seconds = participants * seconds_per_participant
coef = halving_coefficient(1)
emission = total_seconds * coef
self.assertEqual(emission, 30_000) # 100 × 600 × 0.5
def test_emission_calculation_tau4_2(self):
"""Эмиссия для 100 участников, 600 сек каждый, τ₄ = 2"""
participants = 100
seconds_per_participant = 600
total_seconds = participants * seconds_per_participant
coef = halving_coefficient(2)
emission = total_seconds * coef
self.assertEqual(emission, 15_000) # 100 × 600 × 0.25
# ═══════════════════════════════════════════════════════════════════════
# COMPARISON WITH BITCOIN
# ═══════════════════════════════════════════════════════════════════════
def test_bitcoin_like_progression(self):
"""Проверка что прогрессия халвинга как у Bitcoin"""
# Bitcoin: 50 → 25 → 12.5 → 6.25 → 3.125
# Montana: 1.0 → 0.5 → 0.25 → 0.125 → 0.0625
btc_rewards = [50, 25, 12.5, 6.25, 3.125]
montana_coefs = [halving_coefficient(i) for i in range(5)]
# Нормализуем Bitcoin к Montana (делим на 50)
btc_normalized = [r / 50 for r in btc_rewards]
for btc_norm, montana in zip(btc_normalized, montana_coefs):
self.assertAlmostEqual(btc_norm, montana, places=10)
# ═══════════════════════════════════════════════════════════════════════
# PROPERTIES
# ═══════════════════════════════════════════════════════════════════════
def test_halving_monotonic_decrease(self):
"""Коэффициент монотонно убывает"""
coefficients = [halving_coefficient(i) for i in range(10)]
for i in range(len(coefficients) - 1):
self.assertGreater(coefficients[i], coefficients[i + 1])
def test_halving_never_zero(self):
"""Коэффициент никогда не равен нулю"""
for tau4 in range(100):
coef = halving_coefficient(tau4)
self.assertGreater(coef, 0)
def test_halving_never_negative(self):
"""Коэффициент никогда не отрицательный"""
for tau4 in range(100):
coef = halving_coefficient(tau4)
self.assertGreaterEqual(coef, 0)
def test_halving_approaches_zero(self):
"""Коэффициент стремится к нулю при больших τ₄"""
coef_100 = halving_coefficient(100)
self.assertLess(coef_100, 1e-30) # Очень близко к нулю
def test_halving_exact_division_by_two(self):
"""Каждый следующий коэффициент ровно в 2 раза меньше"""
for tau4 in range(10):
coef_current = halving_coefficient(tau4)
coef_next = halving_coefficient(tau4 + 1)
self.assertAlmostEqual(coef_current / 2, coef_next, places=15)
# ═══════════════════════════════════════════════════════════════════════
# PRACTICAL SCENARIOS
# ═══════════════════════════════════════════════════════════════════════
def test_single_user_emission(self):
"""Один пользователь, 600 секунд присутствия"""
seconds = 600
# τ₄ = 0
emission_0 = seconds * halving_coefficient(0)
self.assertEqual(emission_0, 600)
# τ₄ = 1
emission_1 = seconds * halving_coefficient(1)
self.assertEqual(emission_1, 300)
# τ₄ = 2
emission_2 = seconds * halving_coefficient(2)
self.assertEqual(emission_2, 150)
def test_ten_users_emission(self):
"""10 пользователей, 600 секунд каждый"""
total_seconds = 10 * 600 # 6000
# τ₄ = 0
emission_0 = total_seconds * halving_coefficient(0)
self.assertEqual(emission_0, 6_000)
# τ₄ = 1
emission_1 = total_seconds * halving_coefficient(1)
self.assertEqual(emission_1, 3_000)
def test_thousand_users_emission(self):
"""1000 пользователей, 600 секунд каждый"""
total_seconds = 1000 * 600 # 600,000
# τ₄ = 0
emission_0 = total_seconds * halving_coefficient(0)
self.assertEqual(emission_0, 600_000)
# τ₄ = 1
emission_1 = total_seconds * halving_coefficient(1)
self.assertEqual(emission_1, 300_000)
# ═══════════════════════════════════════════════════════════════════════
# EDGE CASES
# ═══════════════════════════════════════════════════════════════════════
def test_halving_float_precision(self):
"""Проверка точности float для больших tau4"""
# Для очень больших tau4 может возникнуть underflow
coef_1000 = halving_coefficient(1000)
# Должно быть очень близко к нулю, но не точно ноль из-за float precision
self.assertGreaterEqual(coef_1000, 0)
# Может быть 0.0 из-за underflow — это ожидаемо для tau4 > ~1000
if coef_1000 > 0:
self.assertLess(coef_1000, 1e-300)
def test_halving_formula_consistency(self):
"""Проверка что формула 1/(2^n) работает корректно"""
for tau4 in range(20):
coef = halving_coefficient(tau4)
expected = 1.0 / (2 ** tau4)
self.assertEqual(coef, expected)
# ═══════════════════════════════════════════════════════════════════════
# FUTURE PROJECTIONS
# ═══════════════════════════════════════════════════════════════════════
def test_100_years_projection(self):
"""Проекция на 100 лет (25 халвингов)"""
# 100 лет ÷ 4 года = 25 халвингов
tau4_100_years = 25
coef = halving_coefficient(tau4_100_years)
expected = 1.0 / (2 ** 25)
self.assertEqual(coef, expected)
self.assertAlmostEqual(coef, 2.9802322387695312e-08, places=15)
def test_200_years_projection(self):
"""Проекция на 200 лет (50 халвингов)"""
tau4_200_years = 50
coef = halving_coefficient(tau4_200_years)
expected = 1.0 / (2 ** 50)
self.assertEqual(coef, expected)
# ═══════════════════════════════════════════════════════════════════════════
# RUN TESTS
# ═══════════════════════════════════════════════════════════════════════════
if __name__ == '__main__':
# Запускаем с verbose output
unittest.main(verbosity=2)