[{"data":1,"prerenderedAt":516},["ShallowReactive",2],{"dev-\u002Fdeveloper\u002Fguides\u002Fdiet":3},{"id":4,"title":5,"body":6,"description":499,"extension":500,"faq":501,"meta":511,"navigation":89,"noindex":89,"path":512,"seo":513,"stem":514,"__hash__":515},"content\u002Fdeveloper\u002Fguides\u002Fdiet.md","Solve the diet problem in Python",{"type":7,"value":8,"toc":493},"minimark",[9,13,26,31,34,38,41,417,422,426,440,443,447,473,484,489],[10,11,5],"h1",{"id":12},"solve-the-diet-problem-in-python",[14,15,16,17,21,22,25],"p",{},"The ",[18,19,20],"strong",{},"diet problem"," — choose how much of each food to buy so a set of nutrient\nrequirements is met at minimum cost — is the problem that motivated early linear\nprogramming (Stigler, 1945) and still the cleanest way to learn LP. With\n",[18,23,24],{},"quicopt"," it is a few lines in Python.",[27,28,30],"h2",{"id":29},"the-naive-approach","The naive approach",[14,32,33],{},"The tempting shortcut is to greedily pick the cheapest food per nutrient, or to\ntry combinations by hand. Because each food contributes to several nutrients at\nonce, that misses the cheapest balanced mix. The problem is linear — solve it\nexactly.",[27,35,37],{"id":36},"model-it-as-an-lp","Model it as an LP",[14,39,40],{},"A continuous variable per food is the quantity to buy. One constraint per\nnutrient enforces its minimum, and the objective minimizes total cost:",[42,43,49],"pre",{"className":44,"code":45,"filename":46,"language":47,"meta":48,"style":48},"language-python shiki shiki-themes github-dark","from ortools.math_opt.python import mathopt\nfrom quicopt import Client\n\n# Choose food quantities meeting nutrient minimums at minimum cost.\ncost    = [2.0, 3.5, 1.5, 4.0]\nprotein = [4.0, 6.0, 3.0, 8.0]\niron    = [2.0, 1.0, 4.0, 3.0]\nN = len(cost)\n\nmodel = mathopt.Model(name=\"diet\")\nx = [model.add_variable(lb=0.0, name=f\"food_{i}\") for i in range(N)]\nmodel.add_linear_constraint(sum(protein[i] * x[i] for i in range(N)) >= 20.0)\nmodel.add_linear_constraint(sum(iron[i] * x[i] for i in range(N)) >= 10.0)\nmodel.minimize(sum(cost[i] * x[i] for i in range(N)))\n\nclient = Client(\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\")\nprint(client.solve(model).display)\n","diet.py","python","",[50,51,52,71,84,91,98,133,162,189,203,208,232,293,330,361,387,392,408],"code",{"__ignoreMap":48},[53,54,57,61,65,68],"span",{"class":55,"line":56},"line",1,[53,58,60],{"class":59},"snl16","from",[53,62,64],{"class":63},"s95oV"," ortools.math_opt.python ",[53,66,67],{"class":59},"import",[53,69,70],{"class":63}," mathopt\n",[53,72,74,76,79,81],{"class":55,"line":73},2,[53,75,60],{"class":59},[53,77,78],{"class":63}," quicopt ",[53,80,67],{"class":59},[53,82,83],{"class":63}," Client\n",[53,85,87],{"class":55,"line":86},3,[53,88,90],{"emptyLinePlaceholder":89},true,"\n",[53,92,94],{"class":55,"line":93},4,[53,95,97],{"class":96},"sAwPA","# Choose food quantities meeting nutrient minimums at minimum cost.\n",[53,99,101,104,107,110,114,117,120,122,125,127,130],{"class":55,"line":100},5,[53,102,103],{"class":63},"cost    ",[53,105,106],{"class":59},"=",[53,108,109],{"class":63}," [",[53,111,113],{"class":112},"sDLfK","2.0",[53,115,116],{"class":63},", ",[53,118,119],{"class":112},"3.5",[53,121,116],{"class":63},[53,123,124],{"class":112},"1.5",[53,126,116],{"class":63},[53,128,129],{"class":112},"4.0",[53,131,132],{"class":63},"]\n",[53,134,136,139,141,143,145,147,150,152,155,157,160],{"class":55,"line":135},6,[53,137,138],{"class":63},"protein ",[53,140,106],{"class":59},[53,142,109],{"class":63},[53,144,129],{"class":112},[53,146,116],{"class":63},[53,148,149],{"class":112},"6.0",[53,151,116],{"class":63},[53,153,154],{"class":112},"3.0",[53,156,116],{"class":63},[53,158,159],{"class":112},"8.0",[53,161,132],{"class":63},[53,163,165,168,170,172,174,176,179,181,183,185,187],{"class":55,"line":164},7,[53,166,167],{"class":63},"iron    ",[53,169,106],{"class":59},[53,171,109],{"class":63},[53,173,113],{"class":112},[53,175,116],{"class":63},[53,177,178],{"class":112},"1.0",[53,180,116],{"class":63},[53,182,129],{"class":112},[53,184,116],{"class":63},[53,186,154],{"class":112},[53,188,132],{"class":63},[53,190,192,195,197,200],{"class":55,"line":191},8,[53,193,194],{"class":63},"N ",[53,196,106],{"class":59},[53,198,199],{"class":112}," len",[53,201,202],{"class":63},"(cost)\n",[53,204,206],{"class":55,"line":205},9,[53,207,90],{"emptyLinePlaceholder":89},[53,209,211,214,216,219,223,225,229],{"class":55,"line":210},10,[53,212,213],{"class":63},"model ",[53,215,106],{"class":59},[53,217,218],{"class":63}," mathopt.Model(",[53,220,222],{"class":221},"s9osk","name",[53,224,106],{"class":59},[53,226,228],{"class":227},"sU2Wk","\"diet\"",[53,230,231],{"class":63},")\n",[53,233,235,238,240,243,246,248,251,253,255,257,260,263,266,269,272,275,278,281,284,287,290],{"class":55,"line":234},11,[53,236,237],{"class":63},"x ",[53,239,106],{"class":59},[53,241,242],{"class":63}," [model.add_variable(",[53,244,245],{"class":221},"lb",[53,247,106],{"class":59},[53,249,250],{"class":112},"0.0",[53,252,116],{"class":63},[53,254,222],{"class":221},[53,256,106],{"class":59},[53,258,259],{"class":59},"f",[53,261,262],{"class":227},"\"food_",[53,264,265],{"class":112},"{",[53,267,268],{"class":63},"i",[53,270,271],{"class":112},"}",[53,273,274],{"class":227},"\"",[53,276,277],{"class":63},") ",[53,279,280],{"class":59},"for",[53,282,283],{"class":63}," i ",[53,285,286],{"class":59},"in",[53,288,289],{"class":112}," range",[53,291,292],{"class":63},"(N)]\n",[53,294,296,299,302,305,308,311,313,315,317,319,322,325,328],{"class":55,"line":295},12,[53,297,298],{"class":63},"model.add_linear_constraint(",[53,300,301],{"class":112},"sum",[53,303,304],{"class":63},"(protein[i] ",[53,306,307],{"class":59},"*",[53,309,310],{"class":63}," x[i] ",[53,312,280],{"class":59},[53,314,283],{"class":63},[53,316,286],{"class":59},[53,318,289],{"class":112},[53,320,321],{"class":63},"(N)) ",[53,323,324],{"class":59},">=",[53,326,327],{"class":112}," 20.0",[53,329,231],{"class":63},[53,331,333,335,337,340,342,344,346,348,350,352,354,356,359],{"class":55,"line":332},13,[53,334,298],{"class":63},[53,336,301],{"class":112},[53,338,339],{"class":63},"(iron[i] ",[53,341,307],{"class":59},[53,343,310],{"class":63},[53,345,280],{"class":59},[53,347,283],{"class":63},[53,349,286],{"class":59},[53,351,289],{"class":112},[53,353,321],{"class":63},[53,355,324],{"class":59},[53,357,358],{"class":112}," 10.0",[53,360,231],{"class":63},[53,362,364,367,369,372,374,376,378,380,382,384],{"class":55,"line":363},14,[53,365,366],{"class":63},"model.minimize(",[53,368,301],{"class":112},[53,370,371],{"class":63},"(cost[i] ",[53,373,307],{"class":59},[53,375,310],{"class":63},[53,377,280],{"class":59},[53,379,283],{"class":63},[53,381,286],{"class":59},[53,383,289],{"class":112},[53,385,386],{"class":63},"(N)))\n",[53,388,390],{"class":55,"line":389},15,[53,391,90],{"emptyLinePlaceholder":89},[53,393,395,398,400,403,406],{"class":55,"line":394},16,[53,396,397],{"class":63},"client ",[53,399,106],{"class":59},[53,401,402],{"class":63}," Client(",[53,404,405],{"class":227},"\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\"",[53,407,231],{"class":63},[53,409,411,414],{"class":55,"line":410},17,[53,412,413],{"class":112},"print",[53,415,416],{"class":63},"(client.solve(model).display)\n",[418,419],"term-result",{":rows":420,"cmd":421},"[\"├── status:     optimal\",\"├── feasible:   true\",\"├── objective:  10.0\",\"├── x:          food_0=5, food_1=0, food_2=0, food_3=0  (4 variables)\",\"└── solve_time: 0.0023 s\"]","$ python diet.py",[27,423,425],{"id":424},"what-you-get","What you get",[14,427,428,431,432,435,436,439],{},[50,429,430],{},"status: optimal"," means the plan is ",[18,433,434],{},"proven"," cheapest — cost ",[50,437,438],{},"10.0",", meeting\nboth the protein (≥20) and iron (≥10) minimums, in a couple of milliseconds.",[14,441,442],{},"The same model scales to hundreds of foods and dozens of nutrients — you change\nthe data, not the method. (An illustrative optimization example, not nutritional\nadvice.)",[27,444,446],{"id":445},"next","Next",[448,449,450,459,466],"ul",{},[451,452,453,454],"li",{},"The problem class behind this: ",[455,456,458],"a",{"href":457},"\u002Fproblems\u002Flp","Linear programming (LP)",[451,460,461,462],{},"A runnable model for every supported class: ",[455,463,465],{"href":464},"\u002Fdeveloper\u002Fexamples","Examples",[451,467,468,469],{},"Set up the client and solve your first model: ",[455,470,472],{"href":471},"\u002Fdeveloper\u002Fgetting-started","Getting started",[14,474,475,478,479,483],{},[18,476,477],{},"Reference:"," G. J. Stigler, ",[480,481,482],"em",{},"The Cost of Subsistence",", Journal of Farm\nEconomics, 1945.",[485,486],"contact-cta",{"sub":487,"title":488},"Tell us what you're optimizing. We'll help you model it and point you at the right approach.","A bigger nutrition model — or a different problem?",[490,491,492],"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 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":48,"searchDepth":73,"depth":73,"links":494},[495,496,497,498],{"id":29,"depth":73,"text":30},{"id":36,"depth":73,"text":37},{"id":424,"depth":73,"text":425},{"id":445,"depth":73,"text":446},"Choose food quantities that meet nutrient requirements at minimum cost in Python — the classic diet problem modeled as a linear program (LP) and solved with quicopt in a few lines.","md",[502,505,508],{"q":503,"a":504},"Why not just pick the cheapest food that covers each nutrient?","Foods contribute to several nutrients at once, so a greedy pick over- or under-shoots and costs more. The LP balances all nutrients simultaneously at minimum cost.",{"q":506,"a":507},"Can I add upper bounds or variety constraints?","Yes — maximum servings, calorie caps, or 'at least k foods' are extra linear constraints on the same model.",{"q":509,"a":510},"Is quicopt free to use?","Yes — pip install quicopt and your first call sets up a free key, no license.",{},"\u002Fdeveloper\u002Fguides\u002Fdiet",{"title":5,"description":499},"developer\u002Fguides\u002Fdiet","Mnw_09Bj0vIWirtJmVIginLR73u5LkM5W8y9pGNCNP4",1784110685996]