[{"data":1,"prerenderedAt":989},["ShallowReactive",2],{"dev-\u002Fdeveloper\u002Fdocs\u002Fapi":3},{"id":4,"title":5,"body":6,"description":980,"extension":981,"faq":982,"meta":983,"navigation":190,"noindex":984,"path":985,"seo":986,"stem":987,"__hash__":988},"content\u002Fdeveloper\u002Fdocs\u002Fapi.md","API reference — the Quicopt clients",{"type":7,"value":8,"toc":968},"minimark",[9,14,18,144,152,157,232,297,304,311,483,501,505,519,527,558,565,569,659,666,672,747,792,809,816,819,879,939,952,956,959,964],[10,11,13],"h1",{"id":12},"api-reference","API reference",[15,16,17],"p",{},"Each client has its own full reference, generated from its source. This page\nsays where to find it and describes what all of them share: the result you get\nback, how to read it, and what an error looks like.",[19,20,21,40],"table",{},[22,23,24],"thead",{},[25,26,27,31,34,37],"tr",{},[28,29,30],"th",{},"Language",[28,32,33],{},"Package",[28,35,36],{},"Reference",[28,38,39],{},"Source",[41,42,43,72,96,120],"tbody",{},[25,44,45,49,56,65],{},[46,47,48],"td",{},"Python",[46,50,51,55],{},[52,53,54],"code",{},"quicopt"," on PyPI",[46,57,58],{},[59,60,64],"a",{"href":61,"rel":62},"https:\u002F\u002Fquicopt.github.io\u002Fquicopt-python\u002F",[63],"nofollow","MkDocs ↗",[46,66,67],{},[59,68,71],{"href":69,"rel":70},"https:\u002F\u002Fgithub.com\u002FQuicopt\u002Fquicopt-python",[63],"quicopt-python ↗",[25,73,74,77,82,89],{},[46,75,76],{},"Julia",[46,78,79],{},[52,80,81],{},"QuicoptClient",[46,83,84],{},[59,85,88],{"href":86,"rel":87},"https:\u002F\u002Fquicopt.github.io\u002FQuicoptClient.jl\u002F",[63],"Documenter ↗",[46,90,91],{},[59,92,95],{"href":93,"rel":94},"https:\u002F\u002Fgithub.com\u002FQuicopt\u002FQuicoptClient.jl",[63],"QuicoptClient.jl ↗",[25,97,98,101,106,113],{},[46,99,100],{},"R",[46,102,103,105],{},[52,104,54],{}," on r-universe",[46,107,108],{},[59,109,112],{"href":110,"rel":111},"https:\u002F\u002Fquicopt.github.io\u002Fquicopt-r\u002F",[63],"pkgdown ↗",[46,114,115],{},[59,116,119],{"href":117,"rel":118},"https:\u002F\u002Fgithub.com\u002FQuicopt\u002Fquicopt-r",[63],"quicopt-r ↗",[25,121,122,125,130,137],{},[46,123,124],{},"Ruby",[46,126,127,129],{},[52,128,54],{}," gem",[46,131,132],{},[59,133,136],{"href":134,"rel":135},"https:\u002F\u002Fquicopt.github.io\u002Fquicopt-ruby\u002F",[63],"YARD ↗",[46,138,139],{},[59,140,143],{"href":141,"rel":142},"https:\u002F\u002Fgithub.com\u002FQuicopt\u002Fquicopt-ruby",[63],"quicopt-ruby ↗",[15,145,146,147,151],{},"All four are open source under Apache 2.0. Installation: ",[59,148,150],{"href":149},"\u002Fdeveloper\u002Fdocs\u002Fclients","Client libraries",".",[153,154,156],"h2",{"id":155},"python-at-a-glance","Python at a glance",[158,159,164],"pre",{"className":160,"code":161,"language":162,"meta":163,"style":163},"language-python shiki shiki-themes github-dark","from quicopt import Client\n\nclient = Client()                 # key from QUICOPT_API_KEY\nresult = client.solve(model)      # a MathOpt or Pyomo model\nprint(result.display)\n","python","",[52,165,166,185,192,208,222],{"__ignoreMap":163},[167,168,171,175,179,182],"span",{"class":169,"line":170},"line",1,[167,172,174],{"class":173},"snl16","from",[167,176,178],{"class":177},"s95oV"," quicopt ",[167,180,181],{"class":173},"import",[167,183,184],{"class":177}," Client\n",[167,186,188],{"class":169,"line":187},2,[167,189,191],{"emptyLinePlaceholder":190},true,"\n",[167,193,195,198,201,204],{"class":169,"line":194},3,[167,196,197],{"class":177},"client ",[167,199,200],{"class":173},"=",[167,202,203],{"class":177}," Client()                 ",[167,205,207],{"class":206},"sAwPA","# key from QUICOPT_API_KEY\n",[167,209,211,214,216,219],{"class":169,"line":210},4,[167,212,213],{"class":177},"result ",[167,215,200],{"class":173},[167,217,218],{"class":177}," client.solve(model)      ",[167,220,221],{"class":206},"# a MathOpt or Pyomo model\n",[167,223,225,229],{"class":169,"line":224},5,[167,226,228],{"class":227},"sDLfK","print",[167,230,231],{"class":177},"(result.display)\n",[233,234,235,266,285],"ul",{},[236,237,238,244,245,248,249,253,254,257,258,261,262,265],"li",{},[239,240,241],"strong",{},[52,242,243],{},"Client()"," — reads your key from ",[52,246,247],{},"QUICOPT_API_KEY","\n(",[59,250,252],{"href":251},"\u002Fdeveloper\u002Fdocs\u002Fkeys","API keys","). To pass a key in code, name it:\n",[52,255,256],{},"Client(api_key=\"…\")",". The first positional argument is the service address,\nso ",[52,259,260],{},"Client(\"…\")"," would not set your key. ",[52,263,264],{},"timeout=60.0"," is the per-request\ntimeout in seconds.",[236,267,268,273,274,280,281,284],{},[239,269,270],{},[52,271,272],{},"client.solve(model, *, gzip=False)"," — sends the model and returns a\n",[59,275,277],{"href":276},"#the-result-object",[52,278,279],{},"Result",". ",[52,282,283],{},"gzip=True"," compresses the request body, which\nhelps with large models.",[236,286,287,292,293,151],{},[239,288,289],{},[52,290,291],{},"client.submit(model)"," — the same without waiting; see\n",[59,294,296],{"href":295},"#async-jobs-clientsubmit","async jobs",[15,298,299,300,151],{},"The full Python reference, every argument included, is in the\n",[59,301,303],{"href":61,"rel":302},[63],"MkDocs documentation ↗",[153,305,307,308,310],{"id":306},"the-result-object","The ",[52,309,279],{}," object",[19,312,313,326],{},[22,314,315],{},[25,316,317,320,323],{},[28,318,319],{},"Field",[28,321,322],{},"Type",[28,324,325],{},"Meaning",[41,327,328,364,386,405,420,450,464],{},[25,329,330,335,340],{},[46,331,332],{},[52,333,334],{},"status",[46,336,337],{},[52,338,339],{},"str",[46,341,342,345,346,345,349,345,352,345,355,345,358,345,361],{},[52,343,344],{},"optimal"," · ",[52,347,348],{},"feasible",[52,350,351],{},"heuristic",[52,353,354],{},"time_limit",[52,356,357],{},"iteration_limit",[52,359,360],{},"infeasible",[52,362,363],{},"unbounded",[25,365,366,371,380],{},[46,367,368],{},[52,369,370],{},"objective",[46,372,373,376,377],{},[52,374,375],{},"float"," or ",[52,378,379],{},"None",[46,381,382,383,385],{},"objective value; ",[52,384,379],{}," when there is no solution",[25,387,388,392,399],{},[46,389,390],{},[52,391,348],{},[46,393,394,376,397],{},[52,395,396],{},"bool",[52,398,379],{},[46,400,401,402,404],{},"whether the returned solution satisfies all constraints; ",[52,403,379],{}," where that's undefined (e.g. an unconstrained heuristic)",[25,406,407,412,417],{},[46,408,409],{},[52,410,411],{},"solution",[46,413,414],{},[52,415,416],{},"dict[str, float]",[46,418,419],{},"variable name → value; empty for infeasible\u002Funbounded",[25,421,422,427,433],{},[46,423,424],{},[52,425,426],{},"model_class",[46,428,429,376,431],{},[52,430,339],{},[52,432,379],{},[46,434,435,436,439,440,439,443,439,446,449],{},"how the service classified the model (",[52,437,438],{},"lp",", ",[52,441,442],{},"qp",[52,444,445],{},"milp",[52,447,448],{},"qubo",", …)",[25,451,452,457,461],{},[46,453,454],{},[52,455,456],{},"solve_time_seconds",[46,458,459],{},[52,460,375],{},[46,462,463],{},"solve wall time",[25,465,466,471,475],{},[46,467,468],{},[52,469,470],{},"display",[46,472,473],{},[52,474,339],{},[46,476,477,478,482],{},"the framed console report — print it and you get the result view from the examples, ",[59,479,481],{"href":480},"#the-shots-block","shots block"," included",[15,484,485,486,489,490,492,493,496,497,500],{},"With the ",[239,487,488],{},"MathOpt"," front-end, ",[52,491,411],{}," keys are your variable names from the\nmodel — name your variables and you can read the result without bookkeeping.\nThe ",[239,494,495],{},"Pyomo"," front-end currently returns generic ",[52,498,499],{},"x1, x2, …"," keys.",[153,502,504],{"id":503},"the-shots-block","The shots block",[15,506,507,510,511,514,515,518],{},[52,508,509],{},"result.display"," opens with a ",[52,512,513],{},"shots"," block. The service takes several shots at\nyour model, and the block is one row per shot: the value it reached, how long it\ntook, and ",[52,516,517],{},"◀ best"," on the one that won.",[158,520,525],{"className":521,"code":523,"language":524,"meta":163},[522],"language-text","├── shots\n│   ├── 1 · primal-dual · global   42    0.0s  ◀ best\n│   ├── 2 · primal-dual · global   42   0.01s\n│   └── 3 · primal                 32   0.01s\n","text",[52,526,523],{"__ignoreMap":163},[15,528,529,530,533,534,539,540,545,546,551,552,557],{},"Each row is labelled ",[52,531,532],{},"method · certificate",". A ",[239,535,536],{},[52,537,538],{},"primal"," shot only ever\nholds a solution; a ",[239,541,542],{},[52,543,544],{},"primal-dual"," shot also maintains a bound on what the\nbest solution could be, which is what puts it in a position to certify. The\ncertificate is what the shot ended up proving: ",[239,547,548],{},[52,549,550],{},"global"," for a proven\noptimum, ",[239,553,554],{},[52,555,556],{},"local"," for a point proven optimal in its own neighbourhood, and no\ncertificate at all where it proved neither — a good value, not a guarantee.",[15,559,560,561,564],{},"Read the block when you want to know how much weight the answer carries;\n",[52,562,563],{},"result.status"," is the one-word summary of it. How many rows you get depends on\nthe model, so don't count on a fixed number.",[153,566,568],{"id":567},"status-semantics","Status semantics",[233,570,571,587,600,607,617,626,652],{},[236,572,573,577,578,580,581,583,584,151],{},[239,574,575],{},[52,576,344],{}," — the value is certified, and the shots block shows how far the\nproof reaches: ",[52,579,550],{},", or ",[52,582,556],{}," on a non-convex model where local\noptimality is what can be proven. ",[52,585,586],{},"feasible: True",[236,588,589,593,594,596,597,599],{},[239,590,591],{},[52,592,351],{}," — the best value found across the shots, with nothing in the\nblock certifying it (typical for QUBO); ",[52,595,348],{}," is ",[52,598,379],{}," when there are no\nconstraints to check.",[236,601,602,606],{},[239,603,604],{},[52,605,348],{}," — the solution satisfies every constraint, but no shot proved\nit optimal.",[236,608,609,613,614,616],{},[239,610,611],{},[52,612,354],{}," — the solve ran out of time and returns the best point found;\ncheck ",[52,615,348],{}," before you use it.",[236,618,619,623,624,151],{},[239,620,621],{},[52,622,357],{}," — the solver stopped at its iteration cap and returns\nthe best point found (can happen on hard NLPs); treat it like ",[52,625,351],{},[236,627,628,632,633,635,636,439,638,640,641,644,645,647,648,151],{},[239,629,630],{},[52,631,360],{}," — no assignment satisfies the constraints; ",[52,634,370],{}," is\n",[52,637,379],{},[52,639,411],{}," is empty. This is a ",[239,642,643],{},"regular status, not an error"," —\ncheck ",[52,646,563],{}," rather than catching exceptions. There's a\n",[59,649,651],{"href":650},"\u002Fdeveloper\u002Fexamples\u002Fby-class#handling-an-infeasible-model","worked example",[236,653,654,658],{},[239,655,656],{},[52,657,363],{}," — the objective can be improved without limit; also a regular\nstatus.",[153,660,662,663],{"id":661},"errors-quicopterror","Errors: ",[52,664,665],{},"QuicoptError",[15,667,668,669,671],{},"Anything the service declines raises ",[52,670,665],{}," with three useful fields:",[158,673,675],{"className":160,"code":674,"language":162,"meta":163,"style":163},"from quicopt import Client, QuicoptError\n\ntry:\n    result = client.solve(model)\nexcept QuicoptError as e:\n    print(e.reason)     # stable code, e.g. \"unsupported_model\" or \"invalid_key\"\n    print(e.display)    # the service's readable message\n",[52,676,677,688,692,700,710,724,736],{"__ignoreMap":163},[167,678,679,681,683,685],{"class":169,"line":170},[167,680,174],{"class":173},[167,682,178],{"class":177},[167,684,181],{"class":173},[167,686,687],{"class":177}," Client, QuicoptError\n",[167,689,690],{"class":169,"line":187},[167,691,191],{"emptyLinePlaceholder":190},[167,693,694,697],{"class":169,"line":194},[167,695,696],{"class":173},"try",[167,698,699],{"class":177},":\n",[167,701,702,705,707],{"class":169,"line":210},[167,703,704],{"class":177},"    result ",[167,706,200],{"class":173},[167,708,709],{"class":177}," client.solve(model)\n",[167,711,712,715,718,721],{"class":169,"line":224},[167,713,714],{"class":173},"except",[167,716,717],{"class":177}," QuicoptError ",[167,719,720],{"class":173},"as",[167,722,723],{"class":177}," e:\n",[167,725,727,730,733],{"class":169,"line":726},6,[167,728,729],{"class":227},"    print",[167,731,732],{"class":177},"(e.reason)     ",[167,734,735],{"class":206},"# stable code, e.g. \"unsupported_model\" or \"invalid_key\"\n",[167,737,739,741,744],{"class":169,"line":738},7,[167,740,729],{"class":227},[167,742,743],{"class":177},"(e.display)    ",[167,745,746],{"class":206},"# the service's readable message\n",[19,748,749,757],{},[22,750,751],{},[25,752,753,755],{},[28,754,319],{},[28,756,325],{},[41,758,759,773,782],{},[25,760,761,766],{},[46,762,763],{},[52,764,765],{},"reason",[46,767,768,769,772],{},"a stable snake_case code, e.g. ",[52,770,771],{},"unsupported_model"," for a problem class that isn't solved yet",[25,774,775,779],{},[46,776,777],{},[52,778,470],{},[46,780,781],{},"the framed, human-readable message",[25,783,784,789],{},[46,785,786],{},[52,787,788],{},"status_code",[46,790,791],{},"the HTTP status behind it",[15,793,794,795,797,798,800,801,805,806,808],{},"Remember: ",[52,796,360],{}," and ",[52,799,363],{}," are ",[802,803,804],"em",{},"results",", not errors — you get a\nnormal ",[52,807,279],{}," for those.",[153,810,812,813],{"id":811},"async-jobs-clientsubmit","Async jobs: ",[52,814,815],{},"client.submit()",[15,817,818],{},"For a long solve, don't block — submit the model and poll a job handle:",[158,820,822],{"className":160,"code":821,"language":162,"meta":163,"style":163},"job = client.submit(model)      # returns immediately\n\njob.status()                    # {\"status\": \"queued\" | \"running\" | \"done\" | \"failed\", ...}\nresult = job.result()           # polls until done, returns the same Result as solve()\nprint(job.log())                # the solver log so far\njob.delete()                    # remove the job and its stored result\n",[52,823,824,837,841,849,861,871],{"__ignoreMap":163},[167,825,826,829,831,834],{"class":169,"line":170},[167,827,828],{"class":177},"job ",[167,830,200],{"class":173},[167,832,833],{"class":177}," client.submit(model)      ",[167,835,836],{"class":206},"# returns immediately\n",[167,838,839],{"class":169,"line":187},[167,840,191],{"emptyLinePlaceholder":190},[167,842,843,846],{"class":169,"line":194},[167,844,845],{"class":177},"job.status()                    ",[167,847,848],{"class":206},"# {\"status\": \"queued\" | \"running\" | \"done\" | \"failed\", ...}\n",[167,850,851,853,855,858],{"class":169,"line":210},[167,852,213],{"class":177},[167,854,200],{"class":173},[167,856,857],{"class":177}," job.result()           ",[167,859,860],{"class":206},"# polls until done, returns the same Result as solve()\n",[167,862,863,865,868],{"class":169,"line":224},[167,864,228],{"class":227},[167,866,867],{"class":177},"(job.log())                ",[167,869,870],{"class":206},"# the solver log so far\n",[167,872,873,876],{"class":169,"line":726},[167,874,875],{"class":177},"job.delete()                    ",[167,877,878],{"class":206},"# remove the job and its stored result\n",[19,880,881,890],{},[22,882,883],{},[25,884,885,888],{},[28,886,887],{},"Method",[28,889,325],{},[41,891,892,902,919,929],{},[25,893,894,899],{},[46,895,896],{},[52,897,898],{},"job.status()",[46,900,901],{},"the job's state and a tail of its log",[25,903,904,909],{},[46,905,906],{},[52,907,908],{},"job.result(wait=True, timeout=None, poll=0.5)",[46,910,911,912,914,915,918],{},"the finished ",[52,913,279],{},"; it waits up to 120 s by default (longer if the job has a time limit) and then raises; with ",[52,916,917],{},"wait=False"," it fetches once and raises if the job isn't done yet",[25,920,921,926],{},[46,922,923],{},[52,924,925],{},"job.log()",[46,927,928],{},"the job's full plain-text log",[25,930,931,936],{},[46,932,933],{},[52,934,935],{},"job.delete()",[46,937,938],{},"delete the job and its stored result on the server",[15,940,941,944,945,948,949,151],{},[52,942,943],{},"submit()"," takes the same models and the same ",[52,946,947],{},"gzip"," option as ",[52,950,951],{},"solve()",[153,953,955],{"id":954},"questions","Questions",[15,957,958],{},"Something unclear in a client, or a model that does not behave as expected?\nTell us:",[960,961],"contact-cta",{"sub":962,"title":963},"Whether something's unclear or you want to try Quicopt on your real models — tell us what you're optimizing.","Questions? Talk to us.",[965,966,967],"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 .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}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":163,"searchDepth":187,"depth":187,"links":969},[970,971,973,974,975,977,979],{"id":155,"depth":187,"text":156},{"id":306,"depth":187,"text":972},"The Result object",{"id":503,"depth":187,"text":504},{"id":567,"depth":187,"text":568},{"id":661,"depth":187,"text":976},"Errors: QuicoptError",{"id":811,"depth":187,"text":978},"Async jobs: client.submit()",{"id":954,"depth":187,"text":955},"The Quicopt clients for Python, Julia, R and Ruby with links to their full reference, and what every client returns — the Result fields, the shots block, statuses, errors and async jobs.","md",null,{},false,"\u002Fdeveloper\u002Fdocs\u002Fapi",{"title":5,"description":980},"developer\u002Fdocs\u002Fapi","M5A0tab0FXLtEmzOSubYdcMWH7IJbnELPR14qtWadvo",1794337679391]