MarkTechPost更新日

Meta AI、リバランサー(Rebalancer)をオープンソース化:1日約4,000万件の配置問題を処理するC++割り当てソルバー

Metaは、シャード、サーバー、トラフィックの配置に9年以上使用してきたC++およびPythonライブラリ「Rebalancer」をオープンソース化しました。このライブラリは1日約4,000万件の割り当て問題を処理し、局所探索や、Gurobi、FICO Xpress、HiGHSなどのMIPソルバーを利用します。Apache 2.0ライセンスのもと、pipでインストール可能です。本記事「Meta AI Open-Sources…

Metaはオープンソース化しました Rebalancer、割り当て問題を解くためのPythonインターフェースを持つC++ライブラリです。制約と目的に基づいて、どのオブジェクトをどのビンに入れるかを決定します。によると、 Metaのエンジニアリングによる投稿Rebalancerは9年以上にわたりMeta全体のリソース割り当てを処理してきました。今回のリリースはApache 2.0ライセンスの下で公開され、 ドキュメント、a PyPI パッケージ 「Rebalancer Explorer」と呼ばれるデバッグ用UI。

デプロイ可能ですか? はい。 pip install rebalancer Python 3.12+向けにv1.0.4をインストールし、Linux x86-64およびmacOS 14+ ARM64用のプレビルドwheelが用意されています。.deb、.rpm、Homebrewパッケージも存在します。PyPIでは引き続きこのプロジェクトはAlphaと分類されています。

Rebalancerはどのような問題を解決するのか?

割り当て問題はMetaのスタック全体に登場します。ラックはデータセンターに、サーバーはサービスに、タスクはサーバーに、そしてユーザートラフィックはデータセンターに割り当てられます。Metaは2つの障壁を挙げています:使いやすさとスケーラビリティです。エンジニアはポリシーを正確な数式に変換するのに苦労し、多くの問題はNP困難であり、商用ソルバーには大きすぎます。

Rebalancerの答えは、問題の指定方法と解決方法を分離することです。その設計の詳細は以下で説明されています。 OSDI 2024 論文, ハイパースケールデータセンターにおけるリソース割り当ての最適化.

仕様レイヤーの仕組み

仕様言語には 3 つの層があります:

  • モデリング構成要素: ディメンション(CPUやストレージなどの属性)、パーティション(オブジェクトのグループ)、スコープ(ビンのグループ)、そして使用率。
  • Expression API: 「SUMやMAXで集計利用率を求めたり、SQUAREなどの演算で変換したりできます。」
  • Spec API: dozens of predefined objectives and constraints, listed in the ドキュメント.

Metaの例では、タスクをオブジェクト、サーバーをビン、ラックをスコープとしてモデル化しています。A CapacitySpec サーバーごとのCPUとストレージに上限を設けています。A GroupCountSpec ラックごとに1種類のジョブを維持します。A BalanceSpec 両方のディメンションにわたって各サーバーの使用率を均衡させます。

1つの式グラフ、2つのソルバー

Rebalancerは仕様を有向非巡回式グラフへコンパイルします。リーフノードは利用率の値を保持し、その上に集約ノードと変換ノードが配置されます。ユーザーは初期割り当てと停止条件を指定します。初期割り当てがすでに違反している制約は、高優先度のゴールになります。

最適ソルバー: そのグラフは混合整数計画に変換され、次の FICO Xpress, Gurobi または HiGHS. 変数の集約と対称性の破りによってモデルを縮小します。それでも最悪ケースのモデルサイズは O(objects × bins) のままです。Meta の最大規模の問題は、どんな MIP ソルバーにとっても大きすぎます。

ローカル検索: このソルバーは式グラフを直接操作します。オブジェクトを他のビンへ移動させる手を探索し、最悪ケースの近傍は O(objects + bins) です。その後、制約を一切破らない最良の候補を適用します。評価は並列化されており、毎秒数百万回の評価に到達し、探索空間は剪定されます。

Metaはほぼすべての大規模問題に局所探索を使用し、小規模から中規模の問題にはMIPを使用しています。多くの場合、まずMIPで試作を行います。

Metaにおける制作数

  • 1日あたり約4,000万件の割り当て問題を、30以上の独自の定式化にわたって解いています。
  • 265kオブジェクトと3.2kビンでのP99求解時間は12秒でした。
  • 100万個を超えるオブジェクトと5kビンの問題では、3.4k回以上の実行全体で平均171秒かかります。

リバランサーの最適な使用例

  1. クラスターへのシャード、タスク、コンテナの配置: CPUおよびメモリの上限のもとでサーバーにワークを割り当て、レプリカをラック間に分散させます。Metaの Shard Manager および RAS このパターンを実行します。
  2. リージョン間でのトラフィックとワークロードの分散: ユーザーのトラフィックやジョブをデータセンターに振り分け、レイテンシと負荷のトレードオフを調整します。 太地 これはエッジトラフィックに対してこの処理を行い、MetaはMLトレーニングを優先度に応じて負荷分散しています。
  3. インフラ外の運用割り当て: ヘルプデスクのチケットをエンジニアに、会議を部屋に、またはデスクを人に、キャパシティのルールに従って割り当てます。Metaはこの3つすべてを実現しています。

Rebalancer Explorerによるデバッグ

Metaのモデラーは時間の大半をソルバーの挙動のデバッグに費やしていました。 Rebalancer Explorer はそのために構築されたDocker化されたWeb UIです。バインディング制約、緩和の影響、そしてオブジェクトがどのビンに配置されたのかその理由を表示します。

インタラクティブな解説

ローカル探索を実行</button> <button class="b" id="mtpStep">1ステップ実行</button> <button class="b" id="mtpShuf">ランダムな悪い初期状態</button> <button class="b" id="mtpReset">リセット</button> </div> <div class="stats"> <div class="st"><div class="k">ステップ</div><div class="v" id="mtpS">0</div></div> <div class="st"><div class="k">評価されたムーブ</div><div class="v" id="mtpE">0</div></div> <div class="st"><div class="k">キャパシティ超過</div><div class="v" id="mtpV">0</div></div> <div class="st"><div class="k">バランス目的関数</div><div class="v" id="mtpO">0</div></div> </div> <div class="racks" id="mtpRacks"></div> <div class="spark"><div class="k">ステップごとの目的関数の値(小さいほど良い、理想値 = 324)</div> <svg id="mtpSpark" viewBox="0 0 800 70" width="100%" height="70" preserveAspectRatio="none"></svg> </div> <div class="log" id="mtpLog">サーバーS1はキャパシティを4 CPU超過しています。実行を押してください。</div> </div> <!-- PANE 2 --> <div class="pane" id="mtpP1"> <p class="note">Rebalancerは仕様を<b>有向非巡回式グラフ</b>にコンパイルします。リーフには各サーバーの使用率が保持され、その上にSQUARE、SUM、MAXノードが配置されます。1つのタスクが移動すると、そのタスクが触れるリーフとその祖先のみが新しい値を必要とします。グラフはタブ1と同じライブ状態を使用します。</p> <div class="btns"> <button class="b pri" id="mtpGMove">ランダムなタスクを移動</button> <button class="b" id="mtpGBest">最良のローカル探索ムーブを適用</button> </div> <div class="gwrap"><svg id="mtpGraph" viewBox="0 0 820 300" width="100%"></svg></div> <div class="log" id="mtpGLog">ボタンを押してタスクを移動してください。</div> </div> <!-- PANE 3 --> <div class="pane" id="mtpP2"> <p class="note">MIPモデルはオブジェクト×ビンの組み合わせごとにおよそ1つのバイナリ変数を必要とするため、<b>O(objects × bins)</b>で増大します。ローカル探索の近傍は<b>O(objects + bins)</b>で増大します。スライダーをドラッグするか、Metaが公開しているサイズを読み込んでください。</p> <div class="btns"> <button class="b" data-o="500" data-bn="20">小規模: 500 × 20</button> <button class="b" data-o="265000" data-bn="3200">Meta P99: 265k × 3.2k</button> <button class="b" data-o="1000000" data-bn="5000">Meta XL: 1M × 5k</button> </div> <div class="sl"><label>オブジェクト数 <b id="mtpOv"></b></label><input type="range" id="mtpOs" min="1" max="6.3" step="0.01" value="2.7"></div> <div class="sl"><label>ビン数 <b id="mtpBv"></b></label><input type="range" id="mtpBs" min="0.3" max="4" step="0.01" value="1.3"></div> <div class="cmp"> <div class="row"><div class="t">MIPのバイナリ変数、最悪ケース <span id="mtpMv"></span></div><div class="track"><i id="mtpMb" style="background:linear-gradient(90deg,#FF8A5A,#FF5A6E)"></i></div></div> <div class="row"><div class="t">ローカル探索の近傍、最悪ケース <span id="mtpLv"></span></div><div class="track"><i id="mtpLb" style="background:linear-gradient(90deg,#0866FF,#38D6FF)"></i></div></div> </div> <div class="verdict" id="mtpVerdict"></div> <p class="note" style="margin-top:10px">バーは対数スケールです。判定のサイズ帯は説明用であり、Metaが明示しているルールは、ほぼすべての大規模問題にはローカル探索を、小〜中規模の問題にはMIPを使用するというものです。</p> </div> <!-- PANE 4 --> <div class="pane" id="mtpP3"> <p class="note">MetaがRebalancerについて公開した実績数値(Engineering at Meta、2026年9月21日)。</p> <div class="grid" id="mtpCards"> <div class="card"><div class="n"><span data-c="40">0</span><em>M</em></div><div class="d">1日あたりに解かれる割当問題の数</div></div> <div class="card"><div class="n"><span data-c="30">0</span><em>+</em></div><div class="d">ユニークな問題の定式化の数</div></div> <div class="card"><div class="n"><span data-c="12">0</span><em>s</em></div><div class="d">265kオブジェクトと3.2kビンでのP99求解時間</div></div> <div class="card"><div class="n"><span data-c="171">0</span><em>s</em></div><div class="d">1M+オブジェクトと5kビンでの平均求解時間</div></div> <div class="card"><div class="n"><span data-c="3.4" data-d="1">0</span><em>k+</em></div><div class="d">その1M+オブジェクト規模での実行回数</div></div> <div class="card"><div class="n"><span data-c="9">0</span><em>+ yrs</em></div><div class="d">オープンソース化前にMeta全体で使用された年数</div></div> </div> <div class="pills"> <span class="pill">Shard Manager: シャード → サーバー</span> <span class="pill">RAS: サーバー → サービス</span> <span class="pill">Taiji: エッジトラフィック → データセンター</span> <span class="pill">サーバーレス関数のグループ化</span> <span class="pill">MLトレーニングの負荷分散</span> <span class="pill">会議 → 会議室</span> </div> </div> <div class="ft"> <span>出典: <a href="https://engineering.fb.com/2026/09/21/open-source/rebalancer-generic-high-performance-library-assignment-problems/" target="_blank" rel="noopener">Engineering at Meta</a> · <a href="https://github.com/facebook/rebalancer" target="_blank" rel="noopener">GitHub</a> · タブ1〜3は簡略化されたシミュレーションです</span> <span class="brand">Marktechpostによる制作</span> </div> </div> <script> (function(){ var R=document.getElementById('mtp-rebal'); function postH(){try{parent.postMessage({mtpRebalH:R.offsetHeight+40},'*');}catch(e){}} var SIZES=[6,5,4,4,3,3,3,2,2,2,1,1], CAP=16, NS=4; var START=[0,0,0,0,1,1,1,2,2,2,0,1]; var asg=START.slice(), step=0, evals=0, hist=[], timer=null, hot=-1; function util(a){var u=[0,0,0,0];for(var i=0;i<a.length;i++)u[a[i]]+=SIZES[i];return u;} function score(a){var u=util(a),v=0,o=0;for(var s=0;s<NS;s++){v+=Math.max(0,u[s]-CAP);o+=u[s]*u[s];}return [v,o];} function better(x,y){return x[0]<y[0]||(x[0]===y[0]&&x[1]<y[1]);} function bestMove(){ var cur=score(asg),best=null,bs=cur,n=0; for(var i=0;i<asg.length;i++){for(var s=0;s<NS;s++){if(s===asg[i])continue;var b=asg.slice();b[i]=s;n++;var sc=score(b);if(better(sc,bs)){bs=sc;best={a:b,txt:'move t'+(i+1)+' S'+(asg[i]+1)+' → S'+(s+1),ids:[i]};}}} for(var i2=0;i2<asg.length;i2++)for(var j=i2+1;j<asg.length;j++){if(asg[i2]===asg[j])continue;var c=asg.slice();c[i2]=asg[j];c[j]=asg[i2];n++;var sc2=score(c);if(better(sc2,bs)){bs=sc2;best={a:c,txt:'swap t'+(i2+1)+' t'+(j+1),ids:[i2,j]};}} return {best:best,n:n,sc:bs}; } var racksEl=document.getElementById('mtpRacks'); function rects(){var m={};racksEl.querySelectorAll('.chip').forEach(function(c){m[c.dataset.id]=c.getBoundingClientRect();});return m;} function render(ids){ var before=rects(),u=util(asg),h=''; for(var r=0;r<2;r++){h+='<div class="rack"><div class="rl">ラック '+(r?'B':'A')+' (スコープ)</div><div class="srvs">'; for(var s=r*2;s<r*2+2;s++){var over=u[s]>CAP; h+='<div class="srv'+(over?' over':'')+'"><div class="sn">S'+(s+1)+'<span>'+u[s]+' / '+CAP+' CPU</span></div><div class="bar"><i style="width:'+Math.min(100,u[s]/24*100)+'%"></i><u style="left:'+(CAP/24*100)+'%"></u></div><div class="chips">'; for(var i=0;i<asg.length;i++)if(asg[i]===s){h+='<div class="chip'+(ids&&ids.indexOf(i)>-1?' hot':'')+'" data-id="'+i+'" style="width:'+(30+SIZES[i]*8)+'px">t'+(i+1)+'·'+SIZES[i]+'</div>';} h+='</div></div>';} h+='</div></div>';} racksEl.innerHTML=h; racksEl.querySelectorAll('.chip').forEach(function(c){var b=before[c.dataset.id];if(!b)return;var a=c.getBoundingClientRect(),dx=b.left-a.left,dy=b.top-a.top;if(dx||dy){c.style.transition='none';c.style.transform='translate('+dx+'px,'+dy+'px)';requestAnimationFrame(function(){requestAnimationFrame(function(){c.style.transition='transform .55s cubic-bezier(.2,.8,.2,1)';c.style.transform='';});});}}); var sc=score(asg); document.getElementById('mtpS').textContent=step; document.getElementById('mtpE').textContent=evals; var V=document.getElementById('mtpV');V.textContent=sc[0];V.className='v '+(sc[0]?'bad':'good'); var O=document.getElementById('mtpO');O.textContent=sc[1];O.className='v'+(sc[1]===324?' good':''); spark();drawGraph(null);postH(); } function spark(){ var s=document.getElementById('mtpSpark'),pts=hist.length?hist:[score(asg)[1]]; var mx=Math.max.apply(null,pts.concat([600])),mn=300,n=Math.max(pts.length-1,12); var p=pts.map(function(v,i){return (i/n*790+5)+','+(65-(v-mn)/(mx-mn)*58);}).join(' '); var ideal=65-(324-mn)/(mx-mn)*58; s.innerHTML='<line x1="0" x2="800" y1="'+ideal+'" y2="'+ideal+'" stroke="#2BD99F" stroke-dasharray="4 4" opacity=".6"/><polyline points="'+p+'" fill="none" stroke="#38D6FF" stroke-width="2.5"/>'+pts.map(function(v,i){return '<circle cx="'+(i/n*790+5)+'" cy="'+(65-(v-mn)/(mx-mn)*58)+'" r="3.5" fill="#0866FF" stroke="#fff" stroke-width="1"/>';}).join(''); } var logEl=document.getElementById('mtpLog'); function doStep(){ var r=bestMove();evals+=r.n; if(!r.best){stop();logEl.textContent='局所最適解: 移動もスワップもスコアを改善しません ('+evals+' 回の評価)。';render();return false;} var old=asg;asg=r.best.a;step++;hist.push(score(asg)[1]); var moved=r.best.ids;logEl.textContent='ステップ '+step+': '+r.best.txt+' ('+r.n+' 個の候補をチェック)'; render(moved);drawGraph(diff(old,asg));return true; } function diff(a,b){var s={};for(var i=0;i<a.length;i++)if(a[i]!==b[i]){s[a[i]]=1;s[b[i]]=1;}return Object.keys(s).map(Number);} function stop(){if(timer){clearInterval(timer);timer=null;}document.getElementById('mtpRun').textContent=' ローカル探索を実行';} document.getElementById('mtpRun').onclick=function(){if(timer){stop();return;}this.textContent='❚❚ 一時停止';if(!doStep())return;timer=setInterval(function(){if(!doStep())stop();},900);}; document.getElementById('mtpStep').onclick=function(){stop();doStep();}; function resetTo(a,msg){stop();asg=a;step=0;evals=0;hist=[score(asg)[1]];logEl.textContent=msg;render();} document.getElementById('mtpReset').onclick=function(){resetTo(START.slice(),'サーバーS1が容量を 4 CPU 超過した状態で開始します。実行を押してください。');}; document.getElementById('mtpShuf').onclick=function(){var a=[];for(var i=0;i<12;i++)a.push(Math.random()<.55?Math.floor(Math.random()*2):Math.floor(Math.random()*4));resetTo(a,'新しいランダムな初期状態です。実行を押してください。');}; /* 式のグラフ */ var G=document.getElementById('mtpGraph'),gLog=document.getElementById('mtpGLog'); var LX=[110,300,490,680]; function drawGraph(live){ live=live||[];var u=util(asg),sc=score(asg),h=''; function on(s){return live.indexOf(s)>-1;} var any=live.length>0; for(var s=0;s<4;s++){ h+='<path class="edge'+(on(s)?' live':'')+'" d="M'+LX[s]+',232 L'+LX[s]+',172"/>'; h+='<path class="edge'+(on(s)?' live':'')+'" d="M'+LX[s]+',138 C'+LX[s]+',100 300,110 300,78"/>'; h+='<path class="edge'+(on(s)?' live':'')+'" d="M'+(LX[s]+40)+',233 C'+(LX[s]+60)+',200 650,130 650,78"/>'; } h+='<path class="edge'+(any?' live':'')+'" d="M300,44 L300,22"/><path class="edge'+(any?' live':'')+'" d="M650,44 L650,22"/>'; function node(x,y,w,label,val,l){return '<g class="node'+(l?' live':'')+'"><rect x="'+(x-w/2)+'" y="'+(y-17)+'" width="'+w+'" height="34" rx="8"/><text x="'+x+'" y="'+(y-2)+'">'+label+'</text><text class="val" x="'+x+'" y="'+(y+11)+'">'+val+'</text></g>';} for(var k=0;k<4;k++){h+=node(LX[k],250,96,'U(S'+(k+1)+')','= '+u[k],on(k));h+=node(LX[k],155,96,'SQUARE','= '+u[k]*u[k],on(k));} h+=node(300,61,120,'SUM','= '+sc[1],any);h+=node(650,61,120,'MAX','= '+Math.max.apply(null,u),any); h+='<text x="300" y="14" fill="#4C9BFF" font-size="11" font-weight="700" text-anchor="middle">BalanceSpec の目的関数</text>'; h+='<text x="650" y="14" fill="'+(Math.max.apply(null,u)>CAP?'#FF5A6E':'#2BD99F')+'" font-size="11" font-weight="700" text-anchor="middle">CapacitySpec: MAX ≤ '+CAP+(Math.max.apply(null,u)>CAP?' (違反)':' (OK)')+'</text>'; h+='<text x="410" y="292" fill="#93A3BF" font-size="11" text-anchor="middle">リーフ: サーバーごとの使用率 · この手で再計算されたノード: 10 中 '+(any?(live.length*2+2):0)+'</text>'; G.innerHTML=h; } document.getElementById('mtpGMove').onclick=function(){stop();var i=Math.floor(Math.random()*12),s;do{s=Math.floor(Math.random()*4);}while(s===asg[i]);var old=asg;asg=asg.slice();asg[i]=s;evals++;step++;hist.push(score(asg)[1]);render([i]);var d=diff(old,asg);drawGraph(d);gLog.textContent='Moved t'+(i+1)+' S'+(old[i]+1)+' → S'+(s+1)+'. Only '+(d.length*2+2)+' of 10 nodes needed new values.';}; document.getElementById('mtpGBest').onclick=function(){stop();var r=bestMove();evals+=r.n;if(!r.best){gLog.textContent='Local optimum reached. Try a random move first.';render();return;}var old=asg;asg=r.best.a;step++;hist.push(score(asg)[1]);render(r.best.ids);var d=diff(old,asg);drawGraph(d);gLog.textContent='Best of '+r.n+' candidates: '+r.best.txt+'. Recomputed '+(d.length*2+2)+' of 10 nodes.';}; /* ソルバー選択 */ var Os=document.getElementById('mtpOs'),Bs=document.getElementById('mtpBs'); function fmt(n){if(n>=1e9)return (n/1e9).toFixed(n>=1e10?0:1)+'B';if(n>=1e6)return (n/1e6).toFixed(n>=1e7?0:1)+'M';if(n>=1e3)return (n/1e3).toFixed(n>=1e4?0:1)+'k';return Math.round(n)+'';} function pick(){ var o=exactO||Math.round(Math.pow(10,+Os.value)),b=exactB||Math.round(Math.pow(10,+Bs.value)),m=o*b,l=o+b;exactO=exactB=0; document.getElementById('mtpOv').textContent=fmt(o);document.getElementById('mtpBv').textContent=fmt(b); document.getElementById('mtpMv').textContent='≈ '+fmt(m);document.getElementById('mtpLv').textContent='≈ '+fmt(l); document.getElementById('mtpMb').style.width=Math.min(100,Math.log10(m)/11*100)+'%'; document.getElementById('mtpLb').style.width=Math.min(100,Math.log10(l)/11*100)+'%'; var v=document.getElementById('mtpVerdict'),t; if(m<=1e6){t='<b>Optimal (MIP) solver is a good start.</b> Small model: hand it to HiGHS, Gurobi or FICO Xpress and get a provably optimal assignment.';v.style.borderColor='#2BD99F';} else if(m<=1e8){t='<b>Prototype with MIP, then move to local search.</b> Meta says this is a common path: find a strong baseline with the optimal solver, then migrate.';v.style.borderColor='#4C9BFF';} else{t='<b>Local search.</b> The MIP would need ≈ '+fmt(m)+' binary variables in the 最悪の場合、各局所探索の近傍は '+fmt(l)+' 近くに保たれます。Metaはほぼすべての大規模問題をこの方法で実行しています。';v.style.borderColor='#38D6FF';} v.innerHTML=t;postH(); } var exactO=0,exactB=0;Os.oninput=pick;Bs.oninput=pick; document.querySelectorAll('#mtpP2 button[data-o]').forEach(function(btn){btn.onclick=function(){exactO=+btn.dataset.o;exactB=+btn.dataset.bn;Os.value=Math.log10(+btn.dataset.o);Bs.value=Math.log10(+btn.dataset.bn);pick();};}); /* 統計 */ var counted=false; function count(){ var cards=document.querySelectorAll('#mtpCards .card'); cards.forEach(function(c,i){c.classList.remove('in');setTimeout(function(){c.classList.add('in');},90*i);}); document.querySelectorAll('#mtpCards [data-c]').forEach(function(el){var tgt=+el.dataset.c,dp=+(el.dataset.d||0),t0=null; function f(ts){if(!t0)t0=ts;var p=Math.min(1,(ts-t0)/1100),e=1-Math.pow(1-p,3);el.textContent=(tgt*e).toFixed(dp);if(p<1)requestAnimationFrame(f);}requestAnimationFrame(f);}); } /* タブ */ var tabs=R.querySelectorAll('.tab'); tabs.forEach(function(t){t.onclick=function(){tabs.forEach(function(x){x.classList.remove('on');});t.classList.add('on'); R.querySelectorAll('.pane').forEach(function(p){p.classList.remove('on');});document.getElementById('mtpP'+t.dataset.p).classList.add('on'); if(t.dataset.p==='3')count();if(t.dataset.p==='1')drawGraph(null);setTimeout(postH,60);setTimeout(postH,450);};}); hist=[score(asg)[1]];render();pick(); window.addEventListener('load',postH);window.addEventListener('resize',postH);setTimeout(postH,300); })(); </script> </body></html>">

リバランサーと最も近いオープンソース代替との比較

機能MetaリバランサーGoogle OR-ToolsTimefold Solver(Community版)
ライセンスApache 2.0Apache 2.0Apache 2.0 (Enterprise版は商用です)
主要言語C++C++Java
APIC++、PythonC++、Python、Java、C#Java、Kotlin
焦点汎用的な割り当て(オブジェクトからビンへ)幅広いスイート:CP-SAT、LP、MIPラッパー、ルーティング、パッキング、割り当てプランニング:ルーティング、ロスタリング、スケジューリング、タスク割り当て
局所探索あり、式グラフ上で並列実行あり、ルーティングソルバー内 (guided local search、simulated annealing、tabu)あり、コアエンジン (tabu、simulated annealing、late acceptance)
MIPバックエンドFICO Xpress、Gurobi、HiGHS商用およびオープンソースMIPソルバーのラッパー未使用
デバッグUIRebalancer Explorer(Docker)READMEに記載されていないベンチマーカー:商用エディションにおけるスコア分析
インストールpip install rebalancerpip install ortoolsMaven、JDK 21以上

OR-Toolsはより多くの問題クラスをカバーし、TimefoldはJVM上のスケジューリングとルーティングをターゲットとしています。Rebalancerの強みは、ローカルサーチとMIPの両方で動作する単一の割り当て仕様です。

重要ポイント

  • Rebalancerは、あらゆる割り当て問題をオブジェクト、ビン、制約、目的関数としてモデル化します。
  • 仕様は、局所探索またはMIPソルバーによって解かれる式グラフにコンパイルされます。
  • MIPバックエンドには、FICO Xpress、Gurobi、オープンソースのHiGHSが含まれます。
  • Metaでは1日約40M件の問題を実行しており、265kオブジェクトと3.2kビンにおいてP99は12秒です。
  • Apache 2.0ライセンス、C++およびPython APIに対応し、本日からPyPIからインストール可能です。


チェックしてみてください: 論文, GitHub リポジトリ および 技術的詳細。本プロジェクトの研究者に全ての功績が帰属します。また、ぜひ当社をフォローしてください: Twitter そして、私たちのぜひご参加ください。 150k以上のML SubReddit および「Subscribe to(購読する)」を 当社のニュースレター「. 待って!あなたはTelegramを使っていますか?」 telegramでもご参加いただけるようになりました。

[提供] ウェブは、ほとんどのエージェントに欠けている唯一のAPIです。データベース、カレンダー、リポジトリにはAPIがあります。しかしオープンウェブにはほとんどありません。The TinyFish MCPサーバー 任意のMCPクライアントに4つのツールを提供します: TinySearch、TinyFetch(JavaScriptを含むページ全体をマークダウンで取得)、ログインやフォーム用のTinyBrowser、複数ステップの作業用のTinyAgentです。Search と Fetch は無料です。

この投稿 Meta AI、Rebalancerをオープンソース化:1日約4,000万件の配置問題を処理するC++割り当てソルバー 最初に掲載されたのは MarkTechPost.

原文の出典

MarkTechPost

内容について

原文の公開と権利は出典元に帰属します。

機械翻訳 · 原文をご参照ください