[{"data":1,"prerenderedAt":548},["ShallowReactive",2],{"dev-\u002Fdeveloper\u002Fguides\u002Fbin-packing":3},{"id":4,"title":5,"body":6,"description":530,"extension":531,"faq":532,"meta":542,"navigation":543,"noindex":543,"path":544,"seo":545,"stem":546,"__hash__":547},"content\u002Fdeveloper\u002Fguides\u002Fbin-packing.md","Solve the bin packing problem in Python",{"type":7,"value":8,"toc":524},"minimark",[9,13,29,34,37,41,63,449,454,458,471,474,478,504,515,520],[10,11,5],"h1",{"id":12},"solve-the-bin-packing-problem-in-python",[14,15,16,20,21,24,25,28],"p",{},[17,18,19],"strong",{},"Bin packing"," — fit a set of items into as few fixed-capacity bins as possible\n— is everywhere: filling trucks, VMs onto servers, ads into breaks, files onto\ndisks. The usual answer is a greedy first-fit-decreasing pass, which is quick but\nnot optimal. With ",[17,22,23],{},"quicopt"," you get the ",[17,26,27],{},"provably fewest"," bins in a few lines\nof Python.",[30,31,33],"h2",{"id":32},"the-naive-approach","The naive approach",[14,35,36],{},"First-fit-decreasing sorts items large-to-small and drops each into the first bin\nthat fits. It is a good heuristic, but it can waste a bin and never tells you\nwhether fewer was possible. Trying every assignment is exponential. Model it\ninstead.",[30,38,40],{"id":39},"model-it-as-a-milp","Model it as a MILP",[14,42,43,47,48,51,52,55,56,59,60,62],{},[44,45,46],"code",{},"y[b]"," marks bin ",[44,49,50],{},"b"," as used; ",[44,53,54],{},"x[i][b]"," puts item ",[44,57,58],{},"i"," in bin ",[44,61,50],{},". Every item goes\nin exactly one bin, each bin respects its capacity, and we minimize bins used:",[64,65,71],"pre",{"className":66,"code":67,"filename":68,"language":69,"meta":70,"style":70},"language-python shiki shiki-themes github-dark","from ortools.math_opt.python import mathopt\nfrom quicopt import Client\nsize = [4, 8, 5, 7, 3, 6]\nC = 10\nn = len(size)\nB = n  # at most n bins\nmodel = mathopt.Model(name=\"bin_packing\")\ny = [model.add_binary_variable(name=f\"y{b}\") for b in range(B)]\nx = [[model.add_binary_variable(name=f\"x_{i}_{b}\") for b in range(B)] for i in range(n)]\nfor i in range(n):\n    model.add_linear_constraint(sum(x[i][b] for b in range(B)) == 1)\nfor b in range(B):\n    model.add_linear_constraint(sum(size[i] * x[i][b] for i in range(n)) \u003C= C * y[b])\nmodel.minimize(sum(y))\nprint(Client(\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\").solve(model).display)\n","bin_packing.py","python","",[44,72,73,92,105,150,161,175,190,214,264,326,340,371,385,423,434],{"__ignoreMap":70},[74,75,78,82,86,89],"span",{"class":76,"line":77},"line",1,[74,79,81],{"class":80},"snl16","from",[74,83,85],{"class":84},"s95oV"," ortools.math_opt.python ",[74,87,88],{"class":80},"import",[74,90,91],{"class":84}," mathopt\n",[74,93,95,97,100,102],{"class":76,"line":94},2,[74,96,81],{"class":80},[74,98,99],{"class":84}," quicopt ",[74,101,88],{"class":80},[74,103,104],{"class":84}," Client\n",[74,106,108,111,114,117,121,124,127,129,132,134,137,139,142,144,147],{"class":76,"line":107},3,[74,109,110],{"class":84},"size ",[74,112,113],{"class":80},"=",[74,115,116],{"class":84}," [",[74,118,120],{"class":119},"sDLfK","4",[74,122,123],{"class":84},", ",[74,125,126],{"class":119},"8",[74,128,123],{"class":84},[74,130,131],{"class":119},"5",[74,133,123],{"class":84},[74,135,136],{"class":119},"7",[74,138,123],{"class":84},[74,140,141],{"class":119},"3",[74,143,123],{"class":84},[74,145,146],{"class":119},"6",[74,148,149],{"class":84},"]\n",[74,151,153,156,158],{"class":76,"line":152},4,[74,154,155],{"class":84},"C ",[74,157,113],{"class":80},[74,159,160],{"class":119}," 10\n",[74,162,164,167,169,172],{"class":76,"line":163},5,[74,165,166],{"class":84},"n ",[74,168,113],{"class":80},[74,170,171],{"class":119}," len",[74,173,174],{"class":84},"(size)\n",[74,176,178,181,183,186],{"class":76,"line":177},6,[74,179,180],{"class":84},"B ",[74,182,113],{"class":80},[74,184,185],{"class":84}," n  ",[74,187,189],{"class":188},"sAwPA","# at most n bins\n",[74,191,193,196,198,201,205,207,211],{"class":76,"line":192},7,[74,194,195],{"class":84},"model ",[74,197,113],{"class":80},[74,199,200],{"class":84}," mathopt.Model(",[74,202,204],{"class":203},"s9osk","name",[74,206,113],{"class":80},[74,208,210],{"class":209},"sU2Wk","\"bin_packing\"",[74,212,213],{"class":84},")\n",[74,215,217,220,222,225,227,229,232,235,238,240,243,246,249,252,255,258,261],{"class":76,"line":216},8,[74,218,219],{"class":84},"y ",[74,221,113],{"class":80},[74,223,224],{"class":84}," [model.add_binary_variable(",[74,226,204],{"class":203},[74,228,113],{"class":80},[74,230,231],{"class":80},"f",[74,233,234],{"class":209},"\"y",[74,236,237],{"class":119},"{",[74,239,50],{"class":84},[74,241,242],{"class":119},"}",[74,244,245],{"class":209},"\"",[74,247,248],{"class":84},") ",[74,250,251],{"class":80},"for",[74,253,254],{"class":84}," b ",[74,256,257],{"class":80},"in",[74,259,260],{"class":119}," range",[74,262,263],{"class":84},"(B)]\n",[74,265,267,270,272,275,277,279,281,284,286,288,290,293,295,297,299,301,303,305,307,309,311,314,316,319,321,323],{"class":76,"line":266},9,[74,268,269],{"class":84},"x ",[74,271,113],{"class":80},[74,273,274],{"class":84}," [[model.add_binary_variable(",[74,276,204],{"class":203},[74,278,113],{"class":80},[74,280,231],{"class":80},[74,282,283],{"class":209},"\"x_",[74,285,237],{"class":119},[74,287,58],{"class":84},[74,289,242],{"class":119},[74,291,292],{"class":209},"_",[74,294,237],{"class":119},[74,296,50],{"class":84},[74,298,242],{"class":119},[74,300,245],{"class":209},[74,302,248],{"class":84},[74,304,251],{"class":80},[74,306,254],{"class":84},[74,308,257],{"class":80},[74,310,260],{"class":119},[74,312,313],{"class":84},"(B)] ",[74,315,251],{"class":80},[74,317,318],{"class":84}," i ",[74,320,257],{"class":80},[74,322,260],{"class":119},[74,324,325],{"class":84},"(n)]\n",[74,327,329,331,333,335,337],{"class":76,"line":328},10,[74,330,251],{"class":80},[74,332,318],{"class":84},[74,334,257],{"class":80},[74,336,260],{"class":119},[74,338,339],{"class":84},"(n):\n",[74,341,343,346,349,352,354,356,358,360,363,366,369],{"class":76,"line":342},11,[74,344,345],{"class":84},"    model.add_linear_constraint(",[74,347,348],{"class":119},"sum",[74,350,351],{"class":84},"(x[i][b] ",[74,353,251],{"class":80},[74,355,254],{"class":84},[74,357,257],{"class":80},[74,359,260],{"class":119},[74,361,362],{"class":84},"(B)) ",[74,364,365],{"class":80},"==",[74,367,368],{"class":119}," 1",[74,370,213],{"class":84},[74,372,374,376,378,380,382],{"class":76,"line":373},12,[74,375,251],{"class":80},[74,377,254],{"class":84},[74,379,257],{"class":80},[74,381,260],{"class":119},[74,383,384],{"class":84},"(B):\n",[74,386,388,390,392,395,398,401,403,405,407,409,412,415,418,420],{"class":76,"line":387},13,[74,389,345],{"class":84},[74,391,348],{"class":119},[74,393,394],{"class":84},"(size[i] ",[74,396,397],{"class":80},"*",[74,399,400],{"class":84}," x[i][b] ",[74,402,251],{"class":80},[74,404,318],{"class":84},[74,406,257],{"class":80},[74,408,260],{"class":119},[74,410,411],{"class":84},"(n)) ",[74,413,414],{"class":80},"\u003C=",[74,416,417],{"class":84}," C ",[74,419,397],{"class":80},[74,421,422],{"class":84}," y[b])\n",[74,424,426,429,431],{"class":76,"line":425},14,[74,427,428],{"class":84},"model.minimize(",[74,430,348],{"class":119},[74,432,433],{"class":84},"(y))\n",[74,435,437,440,443,446],{"class":76,"line":436},15,[74,438,439],{"class":119},"print",[74,441,442],{"class":84},"(Client(",[74,444,445],{"class":209},"\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\"",[74,447,448],{"class":84},").solve(model).display)\n",[450,451],"term-result",{":rows":452,"cmd":453},"[\"├── status:     optimal\",\"├── feasible:   true\",\"├── objective:  4.0\",\"├── x:          x_0_0=0, x_0_1=0, x_0_2=0, x_0_3=0, x_0_4=0, x_0_5=1, …  (42 variables)\",\"└── solve_time: 0.0185 s\"]","$ python bin_packing.py",[30,455,457],{"id":456},"what-you-get","What you get",[14,459,460,463,464,466,467,470],{},[44,461,462],{},"status: optimal"," means ",[44,465,120],{}," bins is ",[17,468,469],{},"proven"," minimal for these six items — no\npacking uses fewer. The total size is 33 and each bin holds 10, so three bins\n(capacity 30) can't work; the solver proves four is the floor, which a greedy\npass can only guess at.",[14,472,473],{},"The same model extends to larger instances and takes side rules as plain linear\nconstraints — you change the data, not the method. (Bin packing is NP-hard, and\nthis compact formulation is bin-symmetric, so it is best on small-to-medium\ninstances; very large packings call for symmetry-breaking or specialized methods.)",[30,475,477],{"id":476},"next","Next",[479,480,481,490,497],"ul",{},[482,483,484,485],"li",{},"The problem class behind this: ",[486,487,489],"a",{"href":488},"\u002Fproblems\u002Fmilp","Mixed-integer linear (MILP)",[482,491,492,493],{},"A runnable model for every supported class: ",[486,494,496],{"href":495},"\u002Fdeveloper\u002Fexamples","Examples",[482,498,499,500],{},"Set up the client and solve your first model: ",[486,501,503],{"href":502},"\u002Fdeveloper\u002Fgetting-started","Getting started",[14,505,506,509,510,514],{},[17,507,508],{},"Reference:"," M. R. Garey and D. S. Johnson, ",[511,512,513],"em",{},"Computers and Intractability: A\nGuide to the Theory of NP-Completeness",", W. H. Freeman, 1979.",[516,517],"contact-cta",{"sub":518,"title":519},"Tell us what you're optimizing. We'll help you model it and point you at the right approach.","More items — or a different problem?",[521,522,523],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":70,"searchDepth":94,"depth":94,"links":525},[526,527,528,529],{"id":32,"depth":94,"text":33},{"id":39,"depth":94,"text":40},{"id":456,"depth":94,"text":457},{"id":476,"depth":94,"text":477},"Pack all items into the fewest fixed-capacity bins in Python — the bin packing problem modeled as a MILP and solved to proven optimality with quicopt, instead of a greedy first-fit-decreasing heuristic.","md",[533,536,539],{"q":534,"a":535},"Isn't first-fit-decreasing (FFD) good enough?","FFD is fast but only a heuristic — it can use more bins than necessary and never proves optimality. The MILP returns the provably fewest bins.",{"q":537,"a":538},"Can I add per-bin cost or item-compatibility rules?","Yes — bin costs, forbidden pairs, or category limits are extra linear constraints on the same model.",{"q":540,"a":541},"Is quicopt free to use?","Yes — pip install quicopt and your first call sets up a free key, no license.",{},true,"\u002Fdeveloper\u002Fguides\u002Fbin-packing",{"title":5,"description":530},"developer\u002Fguides\u002Fbin-packing","MLOO_Jcp4Lahm5gJ-6k2mKFdxVB-uNI_X7dcxF2sAgM",1784110685996]