[{"data":1,"prerenderedAt":440},["ShallowReactive",2],{"dev-\u002Fdeveloper\u002Fguides\u002Fmaximum-independent-set":3},{"id":4,"title":5,"body":6,"description":419,"extension":420,"faq":421,"meta":434,"navigation":435,"noindex":435,"path":436,"seo":437,"stem":438,"__hash__":439},"content\u002Fdeveloper\u002Fguides\u002Fmaximum-independent-set.md","Solve the maximum independent set problem in Python",{"type":7,"value":8,"toc":413},"minimark",[9,13,35,40,48,52,63,332,337,341,358,367,371,394,404,409],[10,11,5],"h1",{"id":12},"solve-the-maximum-independent-set-problem-in-python",[14,15,16,17,21,22,26,27,30,31,34],"p",{},"A ",[18,19,20],"strong",{},"maximum independent set"," is the largest possible set of vertices in a graph\nwith no edge between any two of them — the model behind conflict-free scheduling,\nchannel assignment, and de-duplication. It is NP-hard, and the default answer\nonline — a greedy pass — returns a ",[23,24,25],"em",{},"maximal"," set, not the ",[23,28,29],{},"maximum"," one.\nWith ",[18,32,33],{},"quicopt"," you get the proven maximum in a few lines of Python.",[36,37,39],"h2",{"id":38},"the-naive-approach","The naive approach",[14,41,42,43,47],{},"A greedy pass grows a set until nothing else fits — a\nlocally-stuck answer that is usually smaller than the true maximum. Enumerating\nall subsets to find the largest is ",[44,45,46],"code",{},"O(2^n)",". Model it instead.",[36,49,51],{"id":50},"model-it-as-a-milp","Model it as a MILP",[14,53,54,55,58,59,62],{},"A binary variable ",[44,56,57],{},"x[i]"," selects vertex ",[44,60,61],{},"i",". For every edge, at most one endpoint\nmay be chosen. Maximize the number of selected vertices:",[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\nedges = [(0,1),(0,2),(1,2),(2,3),(3,4),(3,5),(4,5)]\nN = 6\nmodel = mathopt.Model(name=\"mis\")\nx = [model.add_binary_variable(name=f\"x{i}\") for i in range(N)]\nfor (i, j) in edges:                      # no two adjacent vertices both chosen\n    model.add_linear_constraint(x[i] + x[j] \u003C= 1)\nmodel.maximize(sum(x))\nprint(Client(\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\").solve(model).display)\n","max_independent_set.py","python","",[44,72,73,92,105,183,194,218,268,285,305,317],{"__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,130,132,134,137,139,141,143,145,147,149,151,154,156,158,160,163,165,167,169,172,174,176,178,180],{"class":76,"line":107},3,[74,109,110],{"class":84},"edges ",[74,112,113],{"class":80},"=",[74,115,116],{"class":84}," [(",[74,118,120],{"class":119},"sDLfK","0",[74,122,123],{"class":84},",",[74,125,126],{"class":119},"1",[74,128,129],{"class":84},"),(",[74,131,120],{"class":119},[74,133,123],{"class":84},[74,135,136],{"class":119},"2",[74,138,129],{"class":84},[74,140,126],{"class":119},[74,142,123],{"class":84},[74,144,136],{"class":119},[74,146,129],{"class":84},[74,148,136],{"class":119},[74,150,123],{"class":84},[74,152,153],{"class":119},"3",[74,155,129],{"class":84},[74,157,153],{"class":119},[74,159,123],{"class":84},[74,161,162],{"class":119},"4",[74,164,129],{"class":84},[74,166,153],{"class":119},[74,168,123],{"class":84},[74,170,171],{"class":119},"5",[74,173,129],{"class":84},[74,175,162],{"class":119},[74,177,123],{"class":84},[74,179,171],{"class":119},[74,181,182],{"class":84},")]\n",[74,184,186,189,191],{"class":76,"line":185},4,[74,187,188],{"class":84},"N ",[74,190,113],{"class":80},[74,192,193],{"class":119}," 6\n",[74,195,197,200,202,205,209,211,215],{"class":76,"line":196},5,[74,198,199],{"class":84},"model ",[74,201,113],{"class":80},[74,203,204],{"class":84}," mathopt.Model(",[74,206,208],{"class":207},"s9osk","name",[74,210,113],{"class":80},[74,212,214],{"class":213},"sU2Wk","\"mis\"",[74,216,217],{"class":84},")\n",[74,219,221,224,226,229,231,233,236,239,242,244,247,250,253,256,259,262,265],{"class":76,"line":220},6,[74,222,223],{"class":84},"x ",[74,225,113],{"class":80},[74,227,228],{"class":84}," [model.add_binary_variable(",[74,230,208],{"class":207},[74,232,113],{"class":80},[74,234,235],{"class":80},"f",[74,237,238],{"class":213},"\"x",[74,240,241],{"class":119},"{",[74,243,61],{"class":84},[74,245,246],{"class":119},"}",[74,248,249],{"class":213},"\"",[74,251,252],{"class":84},") ",[74,254,255],{"class":80},"for",[74,257,258],{"class":84}," i ",[74,260,261],{"class":80},"in",[74,263,264],{"class":119}," range",[74,266,267],{"class":84},"(N)]\n",[74,269,271,273,276,278,281],{"class":76,"line":270},7,[74,272,255],{"class":80},[74,274,275],{"class":84}," (i, j) ",[74,277,261],{"class":80},[74,279,280],{"class":84}," edges:                      ",[74,282,284],{"class":283},"sAwPA","# no two adjacent vertices both chosen\n",[74,286,288,291,294,297,300,303],{"class":76,"line":287},8,[74,289,290],{"class":84},"    model.add_linear_constraint(x[i] ",[74,292,293],{"class":80},"+",[74,295,296],{"class":84}," x[j] ",[74,298,299],{"class":80},"\u003C=",[74,301,302],{"class":119}," 1",[74,304,217],{"class":84},[74,306,308,311,314],{"class":76,"line":307},9,[74,309,310],{"class":84},"model.maximize(",[74,312,313],{"class":119},"sum",[74,315,316],{"class":84},"(x))\n",[74,318,320,323,326,329],{"class":76,"line":319},10,[74,321,322],{"class":119},"print",[74,324,325],{"class":84},"(Client(",[74,327,328],{"class":213},"\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\"",[74,330,331],{"class":84},").solve(model).display)\n",[333,334],"term-result",{":rows":335,"cmd":336},"[\"├── status:     optimal\",\"├── feasible:   true\",\"├── objective:  2.0\",\"├── x:          x0=0, x1=1, x2=0, x3=1, x4=0, x5=0  (6 variables)\",\"└── solve_time: 0.0171 s\"]","$ python max_independent_set.py",[36,338,340],{"id":339},"what-you-get","What you get",[14,342,343,346,347,350,351,353,354,357],{},[44,344,345],{},"status: optimal"," means the solver ",[18,348,349],{},"proved"," no larger independent set exists —\nsize ",[44,352,136],{}," (vertices ",[44,355,356],{},"{1, 3}","). The graph is two triangles joined by an edge, so at\nmost one vertex per triangle can be chosen; the solver finds that bound and\nproves it, rather than getting stuck like a greedy pass.",[14,359,360,361,366],{},"The same model scales to large graphs — see how quicopt does on the public QOBLIB\nindependent-set instances in the ",[362,363,365],"a",{"href":364},"\u002Fbenchmarks\u002Fmis","MIS benchmark",".",[36,368,370],{"id":369},"next","Next",[372,373,374,382,387],"ul",{},[375,376,377,378],"li",{},"The problem class behind this: ",[362,379,381],{"href":380},"\u002Fproblems\u002Fmilp","Mixed-integer linear (MILP)",[375,383,384,385],{},"The QUBO\u002FIsing view + measured results: ",[362,386,365],{"href":364},[375,388,389,390],{},"Set up the client and solve your first model: ",[362,391,393],{"href":392},"\u002Fdeveloper\u002Fgetting-started","Getting started",[14,395,396,399,400,403],{},[18,397,398],{},"Reference:"," R. M. Karp, ",[23,401,402],{},"Reducibility Among Combinatorial Problems",", in\nComplexity of Computer Computations, 1972.",[405,406],"contact-cta",{"sub":407,"title":408},"Tell us what you're optimizing. We'll help you model it and point you at the right approach.","A bigger graph — or a different problem?",[410,411,412],"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 .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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":414},[415,416,417,418],{"id":38,"depth":94,"text":39},{"id":50,"depth":94,"text":51},{"id":339,"depth":94,"text":340},{"id":369,"depth":94,"text":370},"Find the largest set of vertices with no edge between any two in Python — maximum independent set modeled as a MILP and solved to proven optimality with quicopt, instead of a greedy approximation that only finds a maximal set.","md",[422,425,428,431],{"q":423,"a":424},"Isn't a greedy maximal independent set enough?","That returns a maximal set — one you can't extend — which is usually not the maximum (globally largest). This MILP returns the provably largest set.",{"q":426,"a":427},"What's the difference between maximal and maximum?","Maximal = locally stuck (no vertex can be added). Maximum = globally largest. Greedy methods give maximal; the solver gives maximum.",{"q":429,"a":430},"Is this related to max-cut and QUBO?","Yes — independent set has an equivalent QUBO\u002FIsing form and is a standard quantum-inspired benchmark. Here we use the clean MILP formulation, which proves optimality.",{"q":432,"a":433},"Is quicopt free to use?","Yes — pip install quicopt and your first call sets up a free key, no license.",{},true,"\u002Fdeveloper\u002Fguides\u002Fmaximum-independent-set",{"title":5,"description":419},"developer\u002Fguides\u002Fmaximum-independent-set","yvmi1Z7utJn-NJ0nDDDrYqRhuYeWaZaCMEanFppcJPA",1784110685996]