54 lines
No EOL
1.5 KiB
Python
54 lines
No EOL
1.5 KiB
Python
"""Pluggable investor and voter strategies for PolyCode v0.1."""
|
|
from __future__ import annotations
|
|
|
|
import random
|
|
from dataclasses import dataclass
|
|
from typing import Protocol
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Proposal:
|
|
id: int
|
|
effort: float
|
|
value: float
|
|
|
|
|
|
class InvestorStrategy(Protocol):
|
|
def allocate(
|
|
self, proposal: Proposal, funded: float, available: float, rng: random.Random
|
|
) -> float: ...
|
|
|
|
|
|
class VoterStrategy(Protocol):
|
|
def approve(self, proposal: Proposal, funded: float, rng: random.Random) -> bool: ...
|
|
|
|
|
|
class ThresholdInvestor:
|
|
"""Invest when projected value covers effort."""
|
|
|
|
def allocate(
|
|
self, proposal: Proposal, funded: float, available: float, rng: random.Random
|
|
) -> float:
|
|
if proposal.value < proposal.effort or available <= 0:
|
|
return 0.0
|
|
need = max(0.0, proposal.effort - funded)
|
|
return min(available, need)
|
|
|
|
|
|
class RandomInvestor:
|
|
def allocate(
|
|
self, proposal: Proposal, funded: float, available: float, rng: random.Random
|
|
) -> float:
|
|
if available <= 0:
|
|
return 0.0
|
|
return rng.uniform(0, min(available, max(0.0, proposal.effort - funded)))
|
|
|
|
|
|
class ValueVoter:
|
|
def approve(self, proposal: Proposal, funded: float, rng: random.Random) -> bool:
|
|
return funded >= proposal.effort and proposal.value >= proposal.effort
|
|
|
|
|
|
class LenientVoter:
|
|
def approve(self, proposal: Proposal, funded: float, rng: random.Random) -> bool:
|
|
return funded >= proposal.effort * 0.8 |