From e77f037d626ccd8c58de900c3c7392e45349342c Mon Sep 17 00:00:00 2001 From: Daniel Rosel Date: Sat, 28 Mar 2026 11:56:37 +0100 Subject: [PATCH] initial progress --- paper/src/chapters/03-methodology.tex | 2 +- paper/src/chapters/mdp_agent.pdf | Bin 11308 -> 11236 bytes paper/src/chapters/mdp_human.pdf | Bin 12049 -> 11953 bytes scripts/nx_paper.sh | 21 ++++ sim/rl/behavior_loader/models.py | 163 ++++++++++++++++++++++---- 5 files changed, 163 insertions(+), 23 deletions(-) diff --git a/paper/src/chapters/03-methodology.tex b/paper/src/chapters/03-methodology.tex index 8c58717..799486e 100644 --- a/paper/src/chapters/03-methodology.tex +++ b/paper/src/chapters/03-methodology.tex @@ -23,7 +23,7 @@ where: The platform does not directly observe the true underlying demand function $d(p)$. Instead, it observes a behavioral proxy $\hat{q}_t$, which is a composite signal derived from the mixture of actor types. We define the demand proxy for product $i$ at epoch $t$ as a weighted aggregation of events: \begin{equation} \label{eq:qhat} -\hat{q}_{t,i} = \sum_{s \in \mathcal{S}_t} \sum_{k=1}^{L_s} \omega(a_{s,k}) \cdot \mathds{1}[i_{s,k} = i] +\hat{q}_{t,i} = \sum_{s \in \mathcal{S}_t} \sum_{k=1}^{L_s} \omega(a_{s,k}) \cdot \mathbf{1}[i_{s,k} = i] \end{equation} where $\omega: \mathcal{A} \to \mathbb{R}_+$ assigns weights to actions based on their signal strength regarding willingness to pay. diff --git a/paper/src/chapters/mdp_agent.pdf b/paper/src/chapters/mdp_agent.pdf index 6845eb5e38a36c814ccf729d04281671097dd95c..aeab1b7ff171d39eb33df300f16001377afec8b7 100644 GIT binary patch delta 9869 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 USXd(e+cY;9G7XJ{k|gr~0L^FmbN~PV delta 9894 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 diff --git a/paper/src/chapters/mdp_human.pdf b/paper/src/chapters/mdp_human.pdf index 69bc8d3cde21065fc132b2dbbab5b534201752f5..b753b4ea8fce0f6dfcb47961aafd33ed07beeed4 100644 GIT binary patch delta 10531 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 RK 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 str: + ports = ("e", "ne", "n", "nw", "w", "sw", "s", "se") + normalized = (angle_rad + (2 * np.pi)) % (2 * np.pi) + step = np.pi / 4 + idx = int(np.round(normalized / step)) % len(ports) + return ports[idx] + + +def _edge_ports( + src: str, + dst: str, + positions: Dict[str, Tuple[float, float]], + has_reverse: bool, +) -> Tuple[str, str]: + src_x, src_y = positions[src] + dst_x, dst_y = positions[dst] + angle = float(np.arctan2(dst_y - src_y, dst_x - src_x)) + + if has_reverse: + bend = np.pi / 10 + angle += bend if src < dst else -bend + + tail_port = _compass_from_angle(angle) + head_port = _compass_from_angle(angle + np.pi) + return tail_port, head_port + + +def _edge_style(prob: float) -> Dict[str, str]: + if prob >= 0.75: + edge_color = "#111827" + elif prob >= 0.50: + edge_color = "#374151" + elif prob >= 0.25: + edge_color = "#6b7280" + else: + edge_color = "#9ca3af" + return { + "color": edge_color, + "fontcolor": "#111827", + "fontsize": "10", + "penwidth": f"{0.9 + 3.6 * prob:.2f}", + "arrowsize": f"{0.55 + 0.55 * prob:.2f}", + } + + +def _format_node_label(evt: str) -> str: + max_line_len = 16 + tokens = evt.split("_") + if len(tokens) == 1: + return evt + + lines: List[str] = [] + curr = "" + for token in tokens: + piece = token if not curr else f"_{token}" + if curr and len(curr) + len(piece) > max_line_len: + lines.append(curr) + curr = token + else: + curr = f"{curr}{piece}" if curr else token + if curr: + lines.append(curr) + return "\n".join(lines) + + +def _compute_flow_positions( + events: List[str], + layout_radius: float, ) -> Dict[str, Tuple[float, float]]: + """Balanced grid layout for paper-friendly diagrams.""" if not events: return {} - step = (2 * np.pi) / len(events) - return { - evt: ( - float(radius * np.cos(idx * step)), - float(radius * np.sin(idx * step)), - ) - for idx, evt in enumerate(events) - } + + num_events = len(events) + cols = int(np.ceil(np.sqrt(num_events))) + rows = int(np.ceil(num_events / cols)) + x_step = max(layout_radius * 1.10, 3.6) + y_step = max(layout_radius * 0.95, 3.2) + + positions: Dict[str, Tuple[float, float]] = {} + for idx, evt in enumerate(events): + row = idx // cols + col = idx % cols + x = (col - (cols - 1) / 2.0) * x_step + y = ((rows - 1) / 2.0 - row) * y_step + positions[evt] = (float(x), float(y)) + + return positions def visualize_mdp( @@ -232,35 +307,79 @@ def visualize_mdp( view: bool = False, export_dot: bool = False, event_order: Optional[List[str]] = None, - layout_radius: float = 6.0, - node_diameter: float = 2.4, + layout_radius: float = 10.0, + node_diameter: float = 1.8, + label_threshold: float = 0.08, ): if not model.mdp: raise ValueError("build MDP first") evt_trans = aggregate_event_transitions(model.mdp) ordered_events = _resolve_event_order(evt_trans, event_order=event_order) - positions = _fixed_circle_positions(ordered_events, radius=layout_radius) + positions = _compute_flow_positions(ordered_events, layout_radius=layout_radius) g = graphviz.Digraph(format=fmt, engine="neato") - g.attr(overlap="false", splines="true", outputorder="edgesfirst") + g.attr( + overlap="false", + splines="true", + outputorder="edgesfirst", + pad="0.5", + sep="+9", + esep="+4", + bgcolor="white", + dpi="180", + ) g.attr( "node", shape="circle", + fixedsize="true", width=f"{node_diameter:.2f}", height=f"{node_diameter:.2f}", - fixedsize="true", - fontsize="10", + fontsize="11", + fontname="Helvetica", + style="filled", + fillcolor="white", + color="#374151", + fontcolor="#111827", + penwidth="1.8", + peripheries="1", + ) + g.attr( + "edge", + fontname="Helvetica", ) for evt in ordered_events: - x_pos, y_pos = positions[evt] - g.node(evt, pos=f"{x_pos:.3f},{y_pos:.3f}!", pin="true") + x, y = positions[evt] + g.node(evt, label=_format_node_label(evt), pos=f"{x:.2f},{y:.2f}!", pin="true") - for src, dsts in evt_trans.items(): - for dst, prob in dsts.items(): - if prob > threshold: - g.edge(src, dst, label=f"{prob:.2f}") + edges = [ + (src, dst, prob) + for src, dsts in evt_trans.items() + for dst, prob in dsts.items() + if prob > threshold + ] + edge_set = {(src, dst) for src, dst, _ in edges} + + for src, dst, prob in sorted(edges, key=lambda row: row[2]): + edge_attrs: Dict[str, str] = _edge_style(prob) + + if src == dst: + # pick a loop port away from the main flow + sx, sy = positions[src] + loop_port = "n" if sy <= 0 else "s" + edge_attrs.update({"tailport": loop_port, "headport": loop_port}) + else: + has_reverse = (dst, src) in edge_set + tail_port, head_port = _edge_ports(src, dst, positions, has_reverse) + edge_attrs.update({"tailport": tail_port, "headport": head_port}) + if has_reverse: + edge_attrs["constraint"] = "false" + + if prob >= label_threshold or src == dst: + edge_attrs["label"] = f" {prob:.2f} " + + g.edge(src, dst, **edge_attrs) g.render(output, view=view, cleanup=True) print(f"Saved MDP graph to {output}.{fmt}")