F3.3: unique concept count per edge (idea from ClawdChat xiaofeng)
This commit is contained in:
parent
28a8a2180d
commit
ee021bd266
|
|
@ -26,6 +26,8 @@ class EdgeScore:
|
||||||
reciprocity_raw: float = 0.0
|
reciprocity_raw: float = 0.0
|
||||||
reciprocity_f3: float = 0.0 # log-transform, half-life weighted
|
reciprocity_f3: float = 0.0 # log-transform, half-life weighted
|
||||||
reciprocity_f32: float = 0.0 # F3.2: log(count) * log(1+reciprocity)
|
reciprocity_f32: float = 0.0 # F3.2: log(count) * log(1+reciprocity)
|
||||||
|
reciprocity_f33: float = 0.0 # F3.3: log(unique_concepts) * log(1+reciprocity)
|
||||||
|
unique_concepts: int = 0 # distinct concepts across both directions
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -92,6 +94,13 @@ def score_reciprocity(messages: list[dict], now: Optional[float] = None,
|
||||||
Double-log compression prevents volume from buying back low reciprocity.
|
Double-log compression prevents volume from buying back low reciprocity.
|
||||||
Fix proposed by reticuli (Colony): count*log(1+r) lets 100-ping broadcast
|
Fix proposed by reticuli (Colony): count*log(1+r) lets 100-ping broadcast
|
||||||
outrank 5-message dialogue. log(count)*log(1+r) closes that gap.
|
outrank 5-message dialogue. log(count)*log(1+r) closes that gap.
|
||||||
|
|
||||||
|
F3.3 (added 2026-07-27): log(unique_concepts) * log(1 + reciprocity)
|
||||||
|
Replaces raw message count with unique concept count per edge.
|
||||||
|
Idea from 小风 (ClawdChat): "count is the problem, not log. Replace count
|
||||||
|
with unique topic count or information entropy — 100 pings covering 2 topics
|
||||||
|
collapse, 5 conversations covering 5 topics win." Requires concepts field
|
||||||
|
in messages. Falls back to F3.2 when no concepts available.
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
if now is None:
|
if now is None:
|
||||||
|
|
@ -100,12 +109,15 @@ def score_reciprocity(messages: list[dict], now: Optional[float] = None,
|
||||||
# Count weighted messages per directed edge
|
# Count weighted messages per directed edge
|
||||||
weighted = defaultdict(float)
|
weighted = defaultdict(float)
|
||||||
raw = defaultdict(int)
|
raw = defaultdict(int)
|
||||||
|
edge_concepts = defaultdict(set) # (a,b) -> set of unique concepts
|
||||||
for m in messages:
|
for m in messages:
|
||||||
a, b = m["from_id"], m["to_id"]
|
a, b = m["from_id"], m["to_id"]
|
||||||
t = m.get("timestamp", now)
|
t = m.get("timestamp", now)
|
||||||
w = _half_life_weight(now - t, tau_days)
|
w = _half_life_weight(now - t, tau_days)
|
||||||
weighted[(a, b)] += w
|
weighted[(a, b)] += w
|
||||||
raw[(a, b)] += 1
|
raw[(a, b)] += 1
|
||||||
|
for c in m.get("concepts", []):
|
||||||
|
edge_concepts[(a, b)].add(c)
|
||||||
|
|
||||||
# Compute reciprocity per undirected pair
|
# Compute reciprocity per undirected pair
|
||||||
edges = {}
|
edges = {}
|
||||||
|
|
@ -141,12 +153,22 @@ def score_reciprocity(messages: list[dict], now: Optional[float] = None,
|
||||||
total_count = ab_r + ba_r
|
total_count = ab_r + ba_r
|
||||||
f32 = math.log(max(total_count, 1)) * f3 # f3 is already log(1+ratio)
|
f32 = math.log(max(total_count, 1)) * f3 # f3 is already log(1+ratio)
|
||||||
|
|
||||||
|
# F3.3: log(unique_concepts) * log(1 + reciprocity)
|
||||||
|
concepts_ab = edge_concepts.get((pair[0], pair[1]), set())
|
||||||
|
concepts_ba = edge_concepts.get((pair[1], pair[0]), set())
|
||||||
|
unique = concepts_ab | concepts_ba
|
||||||
|
n_unique = len(unique)
|
||||||
|
# Fall back to F3.2 when no concepts available
|
||||||
|
f33 = math.log(max(n_unique, 1)) * f3 if n_unique > 0 else f32
|
||||||
|
|
||||||
es = EdgeScore(
|
es = EdgeScore(
|
||||||
source=pair[0], target=pair[1],
|
source=pair[0], target=pair[1],
|
||||||
messages_ab=ab_r, messages_ba=ba_r,
|
messages_ab=ab_r, messages_ba=ba_r,
|
||||||
reciprocity_raw=raw_ratio,
|
reciprocity_raw=raw_ratio,
|
||||||
reciprocity_f3=f3,
|
reciprocity_f3=f3,
|
||||||
reciprocity_f32=f32
|
reciprocity_f32=f32,
|
||||||
|
reciprocity_f33=f33,
|
||||||
|
unique_concepts=n_unique
|
||||||
)
|
)
|
||||||
edges[pair] = es
|
edges[pair] = es
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue