graph LR A["gain buckets\nkeyed by gain"] --> B["pick highest-gain\nfree move"] B --> C{"negative gain ?"} C -->|"yes"| D["take snapshot\n(journal of moves)"] C -->|"no"| E["apply move"] D --> E E --> F["LOCK v\n(at most once per pass)"] F --> G["update neighbour gains"] G --> H{"more moves ?"} H -->|"yes"| B H -->|"no"| I["rollback to\nbest prefix"] I --> J["next pass"] style A fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style D fill:#fff9c4,stroke:#f57f17,stroke-width:3px style F fill:#fadbd8,stroke:#c0392b,stroke-width:3px style I fill:#d1c4e9,stroke:#6a1b9a,stroke-width:3px style J fill:#d5f5e3,stroke:#2e7d32,stroke-width:3px
graph LR A["select max-gain move"] --> B{"positive gain ?"} B -->|"no"| C["STOP\n(local optimum)"] B -->|"yes"| D["check balance"] D --> E["apply move\n(no lock, no snapshot)"] E --> A style A fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style C fill:#d5f5e3,stroke:#2e7d32,stroke-width:3px style E fill:#e8f5e9,stroke:#43a047,stroke-width:3px
graph TD PB["PartMgrBase\n(Template Method)"] PB --> OP["_optimize_1pass()\nthe overridable hook"] OP --> FM["FMPartMgr\nbuckets + lock + rollback"] OP --> NN["NNPartMgr\ngreedy, no lock"] PB --> GM["GainMgr\n(Strategy)"] PB --> CM["ConstrMgr\n(Strategy)"] GM --> GC["GainCalc"] style PB fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style OP fill:#fff9c4,stroke:#f57f17,stroke-width:3px style FM fill:#d1c4e9,stroke:#6a1b9a,stroke-width:3px style NN fill:#d5f5e3,stroke:#2e7d32,stroke-width:3px style GM fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style CM fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style GC fill:#e3f2fd,stroke:#1565c0,stroke-width:3px
graph TD R["refiner"] --> FM["FM\nbuckets + lock"] R --> NN["NN\ngreedy"] S["scale"] --> FL["flat\n(single level)"] S --> ML["multilevel"] K["k"] --> BI["bi (k = 2)"] K --> KW["k-way (k = 3)"] style R fill:#fff9c4,stroke:#f57f17,stroke-width:3px style S fill:#fff9c4,stroke:#f57f17,stroke-width:3px style K fill:#fff9c4,stroke:#f57f17,stroke-width:3px style FM fill:#d1c4e9,stroke:#6a1b9a,stroke-width:3px style NN fill:#d5f5e3,stroke:#2e7d32,stroke-width:3px style ML fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style FL fill:#e3f2fd,stroke:#1565c0,stroke-width:3px
graph TD Q{"what matters most ?"} -->|"best cut"| A["FM + ML π"] Q -->|"speed"| B["NN flat β‘"] Q -->|"speed AND decent cut"| C["NN + ML π―"] Q -->|"robust default"| D["FM + ML β "] style Q fill:#fff9c4,stroke:#f57f17,stroke-width:3px style A fill:#d1c4e9,stroke:#6a1b9a,stroke-width:3px style B fill:#d5f5e3,stroke:#2e7d32,stroke-width:3px style C fill:#e8f5e9,stroke:#43a047,stroke-width:3px style D fill:#e3f2fd,stroke:#1565c0,stroke-width:3px