45 lines
1.8 KiB
Python
45 lines
1.8 KiB
Python
"""이산 협상 State 모델 (우리 자체 구현, config 주입형).
|
|
|
|
Chat_server 의 state.py 는 임계값/가중치를 IntEnum 클래스변수로 박아 config 주입이 불가능했다.
|
|
여기서는 임계값/가중치/코드맵을 모두 TenantConfig.state(StateConfig)에서 주입받고,
|
|
State 는 차원 인덱스 튜플만 보유하는 순수 값객체로 둔다.
|
|
|
|
state_index 는 mixed-radix(혼합 진법) 인코딩으로 차원 곱 공간에 매핑한다 — 차원 개수가
|
|
회사마다 달라도 일반적으로 동작한다(기능적 방법).
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import List
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class State:
|
|
"""5개 이산 차원 인덱스. 각 인덱스는 해당 차원의 [0, dim) 범위."""
|
|
|
|
revenue_idx: int
|
|
distribution_idx: int
|
|
partner_idx: int
|
|
acceptance_idx: int
|
|
price_zone_idx: int
|
|
|
|
def to_tuple(self) -> tuple[int, int, int, int, int]:
|
|
return (self.revenue_idx, self.distribution_idx, self.partner_idx, self.acceptance_idx, self.price_zone_idx)
|
|
|
|
|
|
def encode_index(indices: List[int], dims: List[int]) -> int:
|
|
"""mixed-radix 인코딩: indices 를 dims 진법으로 단일 정수에 매핑.
|
|
|
|
idx = ((...(i0)*d1 + i1)*d2 + i2)...)*d_{n-1} + i_{n-1}
|
|
범위/차원 검증 포함 — 잘못된 입력은 즉시 실패(학습 차원 오염 방지).
|
|
"""
|
|
if len(indices) != len(dims):
|
|
raise ValueError(f"indices/dims length mismatch: {len(indices)} vs {len(dims)}")
|
|
idx = 0
|
|
for i, (val, dim) in enumerate(zip(indices, dims)):
|
|
if dim <= 0:
|
|
raise ValueError(f"dim[{i}] must be positive, got {dim}")
|
|
if not (0 <= val < dim):
|
|
raise ValueError(f"index[{i}]={val} out of range [0,{dim})")
|
|
idx = idx * dim + val
|
|
return idx
|