MarkTechPost

Meta AI open-source Rebalancer : un solveur d'affectation en C++ qui traite environ 40 millions de problèmes de placement par jour

Meta a rendu open source Rebalancer, la bibliothèque C++ et Python qu'elle utilise depuis plus de 9 ans pour placer des shards, des serveurs et le trafic. Elle traite environ 40 millions de problèmes d'affectation par…

Meta a rendu open source Rebalancer, une bibliothèque C++ avec une interface Python pour résoudre des problèmes d'affectation. Elle décide quels objets vont dans quels conteneurs sous des contraintes et des objectifs. Selon le post d'Engineering at Meta, Rebalancer gère l'allocation de ressources chez Meta depuis plus de 9 ans. La version est publiée sous Apache 2.0 avec une documentation, un paquet PyPI et une interface de débogage appelée Rebalancer Explorer.

Est-elle déployable ? Oui. pip install rebalancer installe la v1.0.4 pour Python 3.12+, avec des paquets préconstruits pour Linux x86-64 et macOS 14+ ARM64. Des paquets .deb, .rpm et Homebrew existent également. PyPI classe toujours le projet comme Alpha.

Quel problème Rebalancer résout-il ?

Les problèmes d'affectation apparaissent partout dans la pile de Meta. Les racks vont dans les datacenters, les serveurs vont aux services, les tâches vont aux serveurs, et le trafic des utilisateurs va aux datacenters. Meta cite 2 obstacles : l'utilisabilité et la scalabilité. Les ingénieurs peinent à transformer des politiques en formules précises, et de nombreux problèmes sont NP-difficiles et trop grands pour les solveurs commerciaux.

La réponse de Rebalancer est de séparer la spécification d'un problème de sa résolution. La conception est détaillée dans l' article d'OSDI 2024, Optimizing Resource Allocation in Hyperscale Datacenters.

Fonctionnement de la couche de spécification

Le langage de spécification comporte 3 couches :

  • Constructs de modélisation : les dimensions (attributs tels que le CPU ou le stockage), les partitions (groupes d'objets), les scopes (groupes de conteneurs) et l'utilisation.
  • API d'expressions : agréger l'utilisation avec SUM ou MAX, ou la transformer avec des opérations telles que SQUARE.
  • API de spécification : des dizaines d'objectifs et de contraintes prédéfinis, listés dans la docs.

L'exemple de Meta modélise les tâches comme des objets, les serveurs comme des conteneurs et les racks comme un scope. Un CapacitySpec limite le CPU et le stockage par serveur. Un GroupCountSpec garantit 1 type de tâche par rack. Un BalanceSpec équilibre l’utilisation de chaque serveur selon les deux dimensions.

Un graphe d’expressions, deux solveurs

Rebalancer compile la spécification en un graphe d’expressions acyclique dirigé. Les nœuds feuilles contiennent des valeurs d’utilisation ; les nœuds d’agrégation et de transformation se situent au-dessus d’eux. Les utilisateurs fournissent une affectation initiale et une condition d’arrêt. Les contraintes déjà violées par l’affectation initiale deviennent des objectifs prioritaires.

Solveur optimal: le graphe est traduit en un programme en nombres entiers mixtes pour FICO Xpress, Gurobi ou HiGHS. L’agrégation des variables et la rupture de symétrie réduisent les modèles. La taille du modèle dans le pire des cas reste O(objets × bins). Les plus gros problèmes de Meta sont trop grands pour tout solveur MIP.

Recherche locale: ce solveur travaille directement sur le graphe d’expressions. Il explore les déplacements d’objets vers d’autres bins, avec un voisinage dans le pire des cas de O(objets + bins). Il applique ensuite le meilleur candidat qui ne viole aucune contrainte. L’évaluation est parallélisée, atteignant des millions d’évaluations par seconde, et l’espace de recherche est élagué.

Meta utilise la recherche locale pour presque tous les grands problèmes et le MIP pour les problèmes de petite et moyenne taille, en prototypant souvent d’abord avec le MIP.

Chiffres de production chez Meta

  • Environ 40 millions de problèmes d’affectation résolus par jour, avec plus de 30 formulations uniques.
  • Temps de résolution P99 de 12 secondes sur 265k objets et 3.2k bins.
  • Les problèmes dépassant 1 million d’objets et 5k bins durent en moyenne 171 secondes, sur plus de 3.4k exécutions.

Meilleurs cas d’usage pour Rebalancer

  1. Placement de shards, de tâches ou de conteneurs sur un cluster: attribuer du travail aux serveurs sous des limites de CPU et de mémoire tout en répartissant les réplicas entre les racks. Chez Meta, Shard Manager et RAS suivent ce schéma.
  2. Équilibrage du trafic et des charges de travail entre les régions: router le trafic des utilisateurs ou les jobs vers des datacenters, en arbitrant entre la latence et la charge. Taiji fait cela pour le trafic en périphérie, et Meta équilibre l’entraînement ML par priorité.
  3. Affectation opérationnelle en dehors de l'infrastructure: associer les tickets d'assistance à des ingénieurs, les réunions à des salles ou les bureaux à des personnes sous des règles de capacité. Meta a fait les 3.

Déboguer avec Rebalancer Explorer

Les modeleurs de Meta passaient la majeure partie de leur temps à déboguer le comportement du solveur. Rebalancer Explorer est une interface web Dockerisée conçue pour cela. Elle montre les contraintes de liaison, les effets de relaxation, et pourquoi un objet a atterri dans un bac.

Explication interactive

Run local search</button> <button class="b" id="mtpStep">Step once</button> <button class="b" id="mtpShuf">Random bad start</button> <button class="b" id="mtpReset">Reset</button> </div> <div class="stats"> <div class="st"><div class="k">Step</div><div class="v" id="mtpS">0</div></div> <div class="st"><div class="k">Moves evaluated</div><div class="v" id="mtpE">0</div></div> <div class="st"><div class="k">Capacity overflow</div><div class="v" id="mtpV">0</div></div> <div class="st"><div class="k">Balance objective</div><div class="v" id="mtpO">0</div></div> </div> <div class="racks" id="mtpRacks"></div> <div class="spark"><div class="k">Objective over steps (lower is better, ideal = 324)</div> <svg id="mtpSpark" viewBox="0 0 800 70" width="100%" height="70" preserveAspectRatio="none"></svg> </div> <div class="log" id="mtpLog">Server S1 starts 4 CPU over capacity. Press Run.</div> </div> <!-- PANE 2 --> <div class="pane" id="mtpP1"> <p class="note">Rebalancer compile les spécifications en un <b>graphe d'expressions acyclique orienté</b>. Les feuilles contiennent l'utilisation de chaque serveur ; les nœuds SQUARE, SUM et MAX se trouvent au-dessus d'elles. Lorsqu'une tâche se déplace, seules les feuilles qu'elle touche et leurs ancêtres ont besoin de nouvelles valeurs. Le graphe utilise le même état en direct que l'onglet 1.</p> <div class="btns"> <button class="b pri" id="mtpGMove">Move a random task</button> <button class="b" id="mtpGBest">Apply best local-search move</button> </div> <div class="gwrap"><svg id="mtpGraph" viewBox="0 0 820 300" width="100%"></svg></div> <div class="log" id="mtpGLog">Press a button to move a task.</div> </div> <!-- PANE 3 --> <div class="pane" id="mtpP2"> <p class="note">Le modèle MIP nécessite environ une variable binaire par objet par bac, il croît donc en <b>O(objects × bins)</b>. Un voisinage de recherche locale croît en <b>O(objects + bins)</b>. Faites glisser les curseurs ou chargez les tailles publiées par Meta.</p> <div class="btns"> <button class="b" data-o="500" data-bn="20">Small: 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>Objects <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>Bins <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 binary variables, worst case <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">Local-search neighborhood, worst case <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">Les barres utilisent une échelle logarithmique. Les tranches de taille dans le verdict sont illustratives ; la règle énoncée par Meta est la recherche locale pour presque tous les gros problèmes et le MIP pour ceux de petite à moyenne taille.</p> </div> <!-- PANE 4 --> <div class="pane" id="mtpP3"> <p class="note">Chiffres de production publiés par Meta pour Rebalancer (Engineering at Meta, 21 sep 2026).</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">problèmes d'affectation résolus par jour</div></div> <div class="card"><div class="n"><span data-c="30">0</span><em>+</em></div><div class="d">formulations de problèmes uniques</div></div> <div class="card"><div class="n"><span data-c="12">0</span><em>s</em></div><div class="d">temps de résolution P99 sur 265k objets et 3.2k bins</div></div> <div class="card"><div class="n"><span data-c="171">0</span><em>s</em></div><div class="d">temps de résolution moyen pour 1M+ objets et 5k bins</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">exécutions à cette échelle de 1M+ objets</div></div> <div class="card"><div class="n"><span data-c="9">0</span><em>+ yrs</em></div><div class="d">utilisé dans Meta avant l'open-source</div></div> </div> <div class="pills"> <span class="pill">Shard Manager : shards → serveurs</span> <span class="pill">RAS : serveurs → services</span> <span class="pill">Taiji : trafic edge → datacenters</span> <span class="pill">Groupement de fonctions serverless</span> <span class="pill">Équilibrage de l'entraînement ML</span> <span class="pill">Réunions → salles</span> </div> </div> <div class="ft"> <span>Sources : <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> · Les onglets 1 à 3 sont des simulations simplifiées</span> <span class="brand">Réalisé par 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">'+'Rack '+(r?'B':'A')+' (scope)'+'</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='Optimum local : aucun déplacement ni échange n''améliore le score ('+evals+' évaluations).';render();return false;} var old=asg;asg=r.best.a;step++;hist.push(score(asg)[1]); var moved=r.best.ids;logEl.textContent='Étape '+step+' : '+r.best.txt+' ('+r.n+' candidats examinés)'; 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=' Lancer la recherche locale';} document.getElementById('mtpRun').onclick=function(){if(timer){stop();return;}this.textContent='❚❚ Pause';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(),'Le serveur S1 démarre avec 4 CPU en surcapacité. Appuyez sur Exécuter.');}; 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,'Nouveau départ aléatoire. Appuyez sur Exécuter.');}; /* graphe des expressions */ 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">objectif 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?' (violé)':' (ok)')+'</text>'; h+='<text x="410" y="292" fill="#93A3BF" font-size="11" text-anchor="middle">Feuilles : utilisation par serveur · nœuds recalculés lors de ce mouvement : '+(any?(live.length*2+2):0)+' sur 10</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='Déplacé t'+(i+1)+' S'+(old[i]+1)+' → S'+(s+1)+'. Seuls '+(d.length*2+2)+' des 10 nœuds ont eu besoin de nouvelles valeurs.';}; document.getElementById('mtpGBest').onclick=function(){stop();var r=bestMove();evals+=r.n;if(!r.best){gLog.textContent='Optimum local atteint. Essayez d\'abord un mouvement aléatoire.';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='Meilleur parmi '+r.n+' candidats : '+r.best.txt+'. Recalcul de '+(d.length*2+2)+' des 10 nœuds.';}; /* solver picker */ 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>Un solveur optimal (MIP) est un bon point de départ.</b> Petit modèle : confiez-le à HiGHS, Gurobi ou FICO Xpress et obtenez une affectation prouvablement optimale.';v.style.borderColor='#2BD99F';} else if(m<=1e8){t='<b>Prototypez avec MIP, puis passez à la recherche locale.</b> Meta indique que c\'est un chemin courant : trouvez une solide base de référence avec le solveur optimal, puis migrez.';v.style.borderColor='#4C9BFF';} else{t='<b>Recherche locale.</b> Le MIP nécessiterait ≈ '+fmt(m)+' variables binaires dans le au pire cas, tandis que chaque voisinage de recherche locale reste proche de '+fmt(l)+'. Meta exécute presque tous les gros problèmes de cette façon.';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();};}); /* statistiques */ 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);}); } /* onglets */ 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>">

Rebalancer de Meta face aux alternatives open source les plus proches

CaractéristiqueRebalancer de MetaGoogle OR-ToolsTimefold Solver (Community)
LicenceApache 2.0Apache 2.0Apache 2.0 (L'édition Enterprise est commerciale)
Langage principalC++C++Java
APIC++, PythonC++, Python, Java, C#Java, Kotlin
ObjectifAffectation générique (objets vers bacs)Suite large : wrappers CP-SAT, LP, MIP, routage, empilement, affectationPlanification : routage, établissement de plannings, ordonnancement, affectation de tâches
Recherche localeOui, parallèle, sur graphe d'expressionsOui, dans le solveur de routage (recherche locale guidée, recuit simulé, tabou)Oui, moteur central (tabou, recuit simulé, late acceptance)
Backends MIPFICO Xpress, Gurobi, HiGHSWrappers pour solveurs MIP commerciaux et open sourceNon utilisé
Débogage de l'interface utilisateurExplorateur de rééquilibrage (Docker)Non répertorié dans le READMEBenchmarker ; analyse de score dans les éditions commerciales
Installationpip install rebalancerpip install ortoolsMaven, JDK 21+

OR-Tools couvre davantage de classes de problèmes, et Timefold cible l’ordonnancement et le routage sur JVM. L’avantage de Rebalancer est une seule spécification d’affectation qui fonctionne à la fois avec la recherche locale et le MIP.

Points clés

  • Rebalancer modélise n’importe quel problème d’affectation sous forme d’objets, de bacs, de contraintes et d’objectifs.
  • Les spécifications sont compilées en un graphe d’expressions résolu par recherche locale ou par un solveur MIP.
  • Les backends MIP incluent FICO Xpress, Gurobi et le HiGHS open source.
  • Meta exécute environ 40M de problèmes par jour ; le P99 est de 12s sur 265k objets et 3.2k bacs.
  • Apache 2.0, API C++ et Python, installable depuis PyPI dès aujourd’hui.


Découvrez le Paper, GitHub Repo et Technical details. Tout le crédit revient au chercheur de ce projet. Aussi, n’hésitez pas à nous suivre sur Twitter et n’oubliez pas de rejoindre notre 150k+ML SubReddit et de vous abonner à notre Newsletter. Attendez ! êtes-vous sur telegram ? vous pouvez désormais également nous rejoindre sur telegram.

[Sponsorisé] Le web est l’API unique qui manque à la plupart des agents. Les bases de données, les calendriers et les dépôts ont des API. Le web ouvert, principalement pas. Le serveur MCP TinyFish offre à tout client MCP quatre outils : TinySearch, TinyFetch (pages complètes en markdown, JavaScript inclus), TinyBrowser pour les connexions et les formulaires, et TinyAgent pour les tâches multi-étapes. Search et Fetch sont gratuits.

L’article Meta AI Open-Sources Rebalancer : un solveur d’affectation en C++ qui exécute environ 40 millions de problèmes de placement par jour est apparu en premier sur MarkTechPost.

Source originale

MarkTechPost

À propos du contenu

La publication originale et les droits appartiennent à la source.

Traduction automatique · Consultez l’original