[{"data":1,"prerenderedAt":453},["ShallowReactive",2],{"dev-\u002Fdeveloper\u002Fguides\u002Fmax-cut":3},{"id":4,"title":5,"body":6,"description":434,"extension":435,"faq":436,"meta":446,"navigation":447,"noindex":448,"path":449,"seo":450,"stem":451,"__hash__":452},"content\u002Fdeveloper\u002Fguides\u002Fmax-cut.md","Solve the max-cut problem in Python",{"type":7,"value":8,"toc":428},"minimark",[9,13,29,34,37,41,61,332,337,341,368,382,386,409,419,424],[10,11,5],"h1",{"id":12},"solve-the-max-cut-problem-in-python",[14,15,16,20,21,24,25,28],"p",{},[17,18,19],"strong",{},"Max-cut"," asks you to split a graph's vertices into two sides so that as many\nedges as possible cross between them. It is NP-hard, and it is the canonical\n",[17,22,23],{},"QUBO \u002F Ising"," problem — the one quantum annealers are built for. With\n",[17,26,27],{},"quicopt"," you solve that same formulation classically, in a few lines of\nPython on an ordinary machine.",[30,31,33],"h2",{"id":32},"the-naive-approach","The naive approach",[14,35,36],{},"The usual answers are a greedy or random assignment (fast, but no guarantee on\nquality), or a QAOA tutorial that needs quantum hardware or a simulator. Max-cut\nis a binary quadratic problem — so hand it to a solver built for exactly that.",[30,38,40],{"id":39},"model-it-as-a-qubo","Model it as a QUBO",[14,42,43,44,48,49,52,53,56,57,60],{},"A binary variable ",[45,46,47],"code",{},"x[i]"," puts vertex ",[45,50,51],{},"i"," on side 0 or 1. An edge ",[45,54,55],{},"(i, j)"," is cut\nexactly when its endpoints differ, which ",[45,58,59],{},"x[i] + x[j] - 2·x[i]·x[j]"," captures.\nMaximize the number of cut edges — a quadratic objective over binaries, no\nconstraints:",[62,63,69],"pre",{"className":64,"code":65,"filename":66,"language":67,"meta":68,"style":68},"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),(1,3),(2,3),(2,4),(3,4)]\nN = 5\nmodel = mathopt.Model(name=\"maxcut\")\nx = [model.add_binary_variable(name=f\"x{i}\") for i in range(N)]\n# each edge contributes 1 to the cut iff its endpoints are on different sides:\nmodel.maximize(sum(x[i] + x[j] - 2 * x[i] * x[j] for (i, j) in edges))\nprint(Client(\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\").solve(model).display)\n","maxcut.py","python","",[45,70,71,90,103,180,191,215,265,272,317],{"__ignoreMap":68},[72,73,76,80,84,87],"span",{"class":74,"line":75},"line",1,[72,77,79],{"class":78},"snl16","from",[72,81,83],{"class":82},"s95oV"," ortools.math_opt.python ",[72,85,86],{"class":78},"import",[72,88,89],{"class":82}," mathopt\n",[72,91,93,95,98,100],{"class":74,"line":92},2,[72,94,79],{"class":78},[72,96,97],{"class":82}," quicopt ",[72,99,86],{"class":78},[72,101,102],{"class":82}," Client\n",[72,104,106,109,112,115,119,122,125,128,130,132,135,137,139,141,143,145,147,149,152,154,156,158,160,162,164,166,169,171,173,175,177],{"class":74,"line":105},3,[72,107,108],{"class":82},"edges ",[72,110,111],{"class":78},"=",[72,113,114],{"class":82}," [(",[72,116,118],{"class":117},"sDLfK","0",[72,120,121],{"class":82},",",[72,123,124],{"class":117},"1",[72,126,127],{"class":82},"),(",[72,129,118],{"class":117},[72,131,121],{"class":82},[72,133,134],{"class":117},"2",[72,136,127],{"class":82},[72,138,124],{"class":117},[72,140,121],{"class":82},[72,142,134],{"class":117},[72,144,127],{"class":82},[72,146,124],{"class":117},[72,148,121],{"class":82},[72,150,151],{"class":117},"3",[72,153,127],{"class":82},[72,155,134],{"class":117},[72,157,121],{"class":82},[72,159,151],{"class":117},[72,161,127],{"class":82},[72,163,134],{"class":117},[72,165,121],{"class":82},[72,167,168],{"class":117},"4",[72,170,127],{"class":82},[72,172,151],{"class":117},[72,174,121],{"class":82},[72,176,168],{"class":117},[72,178,179],{"class":82},")]\n",[72,181,183,186,188],{"class":74,"line":182},4,[72,184,185],{"class":82},"N ",[72,187,111],{"class":78},[72,189,190],{"class":117}," 5\n",[72,192,194,197,199,202,206,208,212],{"class":74,"line":193},5,[72,195,196],{"class":82},"model ",[72,198,111],{"class":78},[72,200,201],{"class":82}," mathopt.Model(",[72,203,205],{"class":204},"s9osk","name",[72,207,111],{"class":78},[72,209,211],{"class":210},"sU2Wk","\"maxcut\"",[72,213,214],{"class":82},")\n",[72,216,218,221,223,226,228,230,233,236,239,241,244,247,250,253,256,259,262],{"class":74,"line":217},6,[72,219,220],{"class":82},"x ",[72,222,111],{"class":78},[72,224,225],{"class":82}," [model.add_binary_variable(",[72,227,205],{"class":204},[72,229,111],{"class":78},[72,231,232],{"class":78},"f",[72,234,235],{"class":210},"\"x",[72,237,238],{"class":117},"{",[72,240,51],{"class":82},[72,242,243],{"class":117},"}",[72,245,246],{"class":210},"\"",[72,248,249],{"class":82},") ",[72,251,252],{"class":78},"for",[72,254,255],{"class":82}," i ",[72,257,258],{"class":78},"in",[72,260,261],{"class":117}," range",[72,263,264],{"class":82},"(N)]\n",[72,266,268],{"class":74,"line":267},7,[72,269,271],{"class":270},"sAwPA","# each edge contributes 1 to the cut iff its endpoints are on different sides:\n",[72,273,275,278,281,284,287,290,293,296,299,302,305,307,309,312,314],{"class":74,"line":274},8,[72,276,277],{"class":82},"model.maximize(",[72,279,280],{"class":117},"sum",[72,282,283],{"class":82},"(x[i] ",[72,285,286],{"class":78},"+",[72,288,289],{"class":82}," x[j] ",[72,291,292],{"class":78},"-",[72,294,295],{"class":117}," 2",[72,297,298],{"class":78}," *",[72,300,301],{"class":82}," x[i] ",[72,303,304],{"class":78},"*",[72,306,289],{"class":82},[72,308,252],{"class":78},[72,310,311],{"class":82}," (i, j) ",[72,313,258],{"class":78},[72,315,316],{"class":82}," edges))\n",[72,318,320,323,326,329],{"class":74,"line":319},9,[72,321,322],{"class":117},"print",[72,324,325],{"class":82},"(Client(",[72,327,328],{"class":210},"\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\"",[72,330,331],{"class":82},").solve(model).display)\n",[333,334],"term-result",{":rows":335,"cmd":336},"[\"├── shots\",\"│   ├── 1 · Heuristic 1   0   0.0s\",\"│   ├── 2 · Heuristic 2   5   0.0s  ◀ best\",\"│   └── 3 · Heuristic 2   5   0.0s\",\"├── status:     heuristic\",\"├── feasible:   n\u002Fa\",\"├── objective:  5.0\",\"├── x:          x0=0, x1=1, x2=1, x3=0, x4=1  (5 variables)\",\"└── solve_time: 0.003 s\"]","$ python maxcut.py",[30,338,340],{"id":339},"what-you-get","What you get",[14,342,343,344,347,348,351,352,355,356,359,360,363,364,367],{},"quicopt runs several heuristic shots and returns the best: a cut of ",[45,345,346],{},"5",", putting\nvertices ",[45,349,350],{},"{1, 2, 4}"," on one side and ",[45,353,354],{},"{0, 3}"," on the other. For this graph that\nis the maximum — brute force over all 2⁵ assignments confirms it. Because a QUBO\nhas no constraints to satisfy, the status is ",[45,357,358],{},"heuristic"," and ",[45,361,362],{},"feasible"," is ",[45,365,366],{},"n\u002Fa",".",[14,369,370,371,375,376,381],{},"The point is that the ",[372,373,374],"em",{},"same"," model scales: on the large public Gset graphs\nquicopt reaches within a fraction of a percent of the best-known cuts in seconds\n— see the ",[377,378,380],"a",{"href":379},"\u002Fbenchmarks\u002Fgset","Gset benchmark"," — without a GPU or a quantum device.",[30,383,385],{"id":384},"next","Next",[387,388,389,396,402],"ul",{},[390,391,392,393],"li",{},"The problem class behind this: ",[377,394,23],{"href":395},"\u002Fproblems\u002Fqubo",[390,397,398,399],{},"Measured results at scale: ",[377,400,401],{"href":379},"Max-cut benchmark (Gset)",[390,403,404,405],{},"Set up the client and solve your first model: ",[377,406,408],{"href":407},"\u002Fdeveloper\u002Fgetting-started","Getting started",[14,410,411,414,415,418],{},[17,412,413],{},"Reference:"," M. X. Goemans and D. P. Williamson, ",[372,416,417],{},"Improved Approximation\nAlgorithms for Maximum Cut and Satisfiability Problems Using Semidefinite\nProgramming",", Journal of the ACM, 1995.",[420,421],"contact-cta",{"sub":422,"title":423},"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?",[425,426,427],"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":68,"searchDepth":92,"depth":92,"links":429},[430,431,432,433],{"id":32,"depth":92,"text":33},{"id":39,"depth":92,"text":40},{"id":339,"depth":92,"text":340},{"id":384,"depth":92,"text":385},"Partition a graph's vertices into two sets to maximize the weight of edges between them in Python — max-cut as a QUBO, solved with quicopt on ordinary hardware instead of a quantum computer or a hand-rolled heuristic.","md",[437,440,443],{"q":438,"a":439},"Isn't max-cut a quantum-computing problem?","Max-cut is the flagship QUBO\u002FIsing problem that quantum annealers and QAOA target. quicopt solves the exact same formulation classically, on a normal CPU — a classical alternative to a quantum computer, no hardware required.",{"q":441,"a":442},"Is the returned cut optimal?","Max-cut is NP-hard, so quicopt returns a heuristic solution (status: heuristic). For the small graph here it finds a cut of 5 — the maximum, confirmed by brute force. On large graphs it targets best-known quality; see the Gset benchmark.",{"q":444,"a":445},"Is quicopt free to use?","Yes — pip install quicopt and your first call sets up a free key, no license.",{},true,false,"\u002Fdeveloper\u002Fguides\u002Fmax-cut",{"title":5,"description":434},"developer\u002Fguides\u002Fmax-cut","eEDlslPM-CzrED66OAcZGnJOEUHnNAgGx70vP4Cu1SE",1784110685996]