[{"data":1,"prerenderedAt":616},["ShallowReactive",2],{"dev-\u002Fdeveloper\u002Fexamples\u002Ftransportation":3},{"id":4,"title":5,"body":6,"description":598,"extension":599,"faq":600,"meta":610,"navigation":110,"noindex":611,"path":612,"seo":613,"stem":614,"__hash__":615},"content\u002Fdeveloper\u002Fexamples\u002Ftransportation.md","Solve the transportation problem in Python",{"type":7,"value":8,"toc":592},"minimark",[9,13,30,35,43,47,63,523,528,532,546,549,553,578,588],[10,11,5],"h1",{"id":12},"solve-the-transportation-problem-in-python",[14,15,16,17,21,22,25,26,29],"p",{},"The ",[18,19,20],"strong",{},"transportation problem"," is a staple: you have supplies at several sources,\ndemands at several destinations, and a per-unit shipping cost for each\nsource–destination pair. You want the shipping plan that meets every demand at\nminimum total cost. With ",[18,23,24],{},"quicopt"," it is a short ",[18,27,28],{},"linear program (LP)"," in\nPython.",[31,32,34],"h2",{"id":33},"the-naive-approach","The naive approach",[14,36,37,38,42],{},"The classic hand methods — northwest-corner, least-cost, Vogel's approximation —\nproduce ",[39,40,41],"em",{},"a"," feasible plan, but not necessarily the cheapest, and they are fiddly\nto code. Since the problem is linear, solve it for the exact optimum instead.",[31,44,46],{"id":45},"model-it-as-an-lp","Model it as an LP",[14,48,49,50,54,55,58,59,62],{},"A continuous variable ",[51,52,53],"code",{},"x[i][j]"," is the amount shipped from source ",[51,56,57],{},"i"," to\ndestination ",[51,60,61],{},"j",". Supply and demand rows must balance, and the objective sums the\nshipping cost:",[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\n\n# Ship units from supplies to demands at minimum total cost (balanced).\nsupply = [20.0, 30.0, 25.0]\ndemand = [15.0, 25.0, 20.0, 15.0]\ncost = [[8, 6, 10, 9], [9, 12, 13, 7], [14, 9, 16, 5]]\nS, D = len(supply), len(demand)\n\nmodel = mathopt.Model(name=\"transportation\")\nx = [[model.add_variable(lb=0.0, name=f\"x_{i}_{j}\") for j in range(D)] for i in range(S)]\nfor i in range(S):\n    model.add_linear_constraint(sum(x[i][j] for j in range(D)) == supply[i])\nfor j in range(D):\n    model.add_linear_constraint(sum(x[i][j] for i in range(S)) == demand[j])\nmodel.minimize(sum(cost[i][j] * x[i][j] for i in range(S) for j in range(D)))\n\nclient = Client()\nprint(client.solve(model).display)\n","transportation.py","python","",[51,72,73,92,105,112,119,149,176,247,267,272,296,377,391,420,434,459,498,503,514],{"__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],{"class":76,"line":107},3,[74,109,111],{"emptyLinePlaceholder":110},true,"\n",[74,113,115],{"class":76,"line":114},4,[74,116,118],{"class":117},"sAwPA","# Ship units from supplies to demands at minimum total cost (balanced).\n",[74,120,122,125,128,131,135,138,141,143,146],{"class":76,"line":121},5,[74,123,124],{"class":84},"supply ",[74,126,127],{"class":80},"=",[74,129,130],{"class":84}," [",[74,132,134],{"class":133},"sDLfK","20.0",[74,136,137],{"class":84},", ",[74,139,140],{"class":133},"30.0",[74,142,137],{"class":84},[74,144,145],{"class":133},"25.0",[74,147,148],{"class":84},"]\n",[74,150,152,155,157,159,162,164,166,168,170,172,174],{"class":76,"line":151},6,[74,153,154],{"class":84},"demand ",[74,156,127],{"class":80},[74,158,130],{"class":84},[74,160,161],{"class":133},"15.0",[74,163,137],{"class":84},[74,165,145],{"class":133},[74,167,137],{"class":84},[74,169,134],{"class":133},[74,171,137],{"class":84},[74,173,161],{"class":133},[74,175,148],{"class":84},[74,177,179,182,184,187,190,192,195,197,200,202,205,208,210,212,215,217,220,222,225,227,230,232,234,236,239,241,244],{"class":76,"line":178},7,[74,180,181],{"class":84},"cost ",[74,183,127],{"class":80},[74,185,186],{"class":84}," [[",[74,188,189],{"class":133},"8",[74,191,137],{"class":84},[74,193,194],{"class":133},"6",[74,196,137],{"class":84},[74,198,199],{"class":133},"10",[74,201,137],{"class":84},[74,203,204],{"class":133},"9",[74,206,207],{"class":84},"], [",[74,209,204],{"class":133},[74,211,137],{"class":84},[74,213,214],{"class":133},"12",[74,216,137],{"class":84},[74,218,219],{"class":133},"13",[74,221,137],{"class":84},[74,223,224],{"class":133},"7",[74,226,207],{"class":84},[74,228,229],{"class":133},"14",[74,231,137],{"class":84},[74,233,204],{"class":133},[74,235,137],{"class":84},[74,237,238],{"class":133},"16",[74,240,137],{"class":84},[74,242,243],{"class":133},"5",[74,245,246],{"class":84},"]]\n",[74,248,250,253,255,258,261,264],{"class":76,"line":249},8,[74,251,252],{"class":84},"S, D ",[74,254,127],{"class":80},[74,256,257],{"class":133}," len",[74,259,260],{"class":84},"(supply), ",[74,262,263],{"class":133},"len",[74,265,266],{"class":84},"(demand)\n",[74,268,270],{"class":76,"line":269},9,[74,271,111],{"emptyLinePlaceholder":110},[74,273,275,278,280,283,287,289,293],{"class":76,"line":274},10,[74,276,277],{"class":84},"model ",[74,279,127],{"class":80},[74,281,282],{"class":84}," mathopt.Model(",[74,284,286],{"class":285},"s9osk","name",[74,288,127],{"class":80},[74,290,292],{"class":291},"sU2Wk","\"transportation\"",[74,294,295],{"class":84},")\n",[74,297,299,302,304,307,310,312,315,317,319,321,324,327,330,332,335,338,340,342,344,347,350,353,356,359,362,365,367,370,372,374],{"class":76,"line":298},11,[74,300,301],{"class":84},"x ",[74,303,127],{"class":80},[74,305,306],{"class":84}," [[model.add_variable(",[74,308,309],{"class":285},"lb",[74,311,127],{"class":80},[74,313,314],{"class":133},"0.0",[74,316,137],{"class":84},[74,318,286],{"class":285},[74,320,127],{"class":80},[74,322,323],{"class":80},"f",[74,325,326],{"class":291},"\"x_",[74,328,329],{"class":133},"{",[74,331,57],{"class":84},[74,333,334],{"class":133},"}",[74,336,337],{"class":291},"_",[74,339,329],{"class":133},[74,341,61],{"class":84},[74,343,334],{"class":133},[74,345,346],{"class":291},"\"",[74,348,349],{"class":84},") ",[74,351,352],{"class":80},"for",[74,354,355],{"class":84}," j ",[74,357,358],{"class":80},"in",[74,360,361],{"class":133}," range",[74,363,364],{"class":84},"(D)] ",[74,366,352],{"class":80},[74,368,369],{"class":84}," i ",[74,371,358],{"class":80},[74,373,361],{"class":133},[74,375,376],{"class":84},"(S)]\n",[74,378,380,382,384,386,388],{"class":76,"line":379},12,[74,381,352],{"class":80},[74,383,369],{"class":84},[74,385,358],{"class":80},[74,387,361],{"class":133},[74,389,390],{"class":84},"(S):\n",[74,392,394,397,400,403,405,407,409,411,414,417],{"class":76,"line":393},13,[74,395,396],{"class":84},"    model.add_linear_constraint(",[74,398,399],{"class":133},"sum",[74,401,402],{"class":84},"(x[i][j] ",[74,404,352],{"class":80},[74,406,355],{"class":84},[74,408,358],{"class":80},[74,410,361],{"class":133},[74,412,413],{"class":84},"(D)) ",[74,415,416],{"class":80},"==",[74,418,419],{"class":84}," supply[i])\n",[74,421,423,425,427,429,431],{"class":76,"line":422},14,[74,424,352],{"class":80},[74,426,355],{"class":84},[74,428,358],{"class":80},[74,430,361],{"class":133},[74,432,433],{"class":84},"(D):\n",[74,435,437,439,441,443,445,447,449,451,454,456],{"class":76,"line":436},15,[74,438,396],{"class":84},[74,440,399],{"class":133},[74,442,402],{"class":84},[74,444,352],{"class":80},[74,446,369],{"class":84},[74,448,358],{"class":80},[74,450,361],{"class":133},[74,452,453],{"class":84},"(S)) ",[74,455,416],{"class":80},[74,457,458],{"class":84}," demand[j])\n",[74,460,462,465,467,470,473,476,478,480,482,484,487,489,491,493,495],{"class":76,"line":461},16,[74,463,464],{"class":84},"model.minimize(",[74,466,399],{"class":133},[74,468,469],{"class":84},"(cost[i][j] ",[74,471,472],{"class":80},"*",[74,474,475],{"class":84}," x[i][j] ",[74,477,352],{"class":80},[74,479,369],{"class":84},[74,481,358],{"class":80},[74,483,361],{"class":133},[74,485,486],{"class":84},"(S) ",[74,488,352],{"class":80},[74,490,355],{"class":84},[74,492,358],{"class":80},[74,494,361],{"class":133},[74,496,497],{"class":84},"(D)))\n",[74,499,501],{"class":76,"line":500},17,[74,502,111],{"emptyLinePlaceholder":110},[74,504,506,509,511],{"class":76,"line":505},18,[74,507,508],{"class":84},"client ",[74,510,127],{"class":80},[74,512,513],{"class":84}," Client()\n",[74,515,517,520],{"class":76,"line":516},19,[74,518,519],{"class":133},"print",[74,521,522],{"class":84},"(client.solve(model).display)\n",[524,525],"term-result",{":rows":526,"cmd":527},"[\"├── shots\",\"│   ├── 1 · primal-dual · global   635    0.0s  ◀ best\",\"│   └── 2 · primal-dual · global   635   0.01s\",\"├── status:     optimal\",\"├── feasible:   true\",\"├── objective:  635.0\",\"├── x:          x_0_0=0, x_0_1=15, x_0_2=5, x_0_3=0, x_1_0=15, x_1_1=0, …  (12 variables)\",\"└── solve_time: 0.0095 s\"]","$ python transportation.py",[31,529,531],{"id":530},"what-you-get","What you get",[14,533,534,537,538,541,542,545],{},[51,535,536],{},"status: optimal"," means the plan is ",[18,539,540],{},"proven"," minimum-cost — total cost ",[51,543,544],{},"635",",\nfound in a fraction of a second. The transportation problem is totally\nunimodular, so the LP already returns whole-unit shipments without needing\ninteger variables.",[14,547,548],{},"The same model scales from a 3×4 grid to thousands of routes — you change the\ndata, not the method.",[31,550,552],{"id":551},"next","Next",[554,555,556,564,571],"ul",{},[557,558,559,560],"li",{},"The problem class behind this: ",[41,561,563],{"href":562},"\u002Fproblems\u002Flp","Linear programming (LP)",[557,565,566,567],{},"A runnable model for every supported class: ",[41,568,570],{"href":569},"\u002Fdeveloper\u002Fexamples\u002Fby-class","Examples",[557,572,573,574],{},"Set up the client and solve your first model: ",[41,575,577],{"href":576},"\u002Fdeveloper\u002Fdocs\u002Fquickstart","Getting started",[14,579,580,583,584,587],{},[18,581,582],{},"Reference:"," F. L. Hitchcock, ",[39,585,586],{},"The Distribution of a Product from Several\nSources to Numerous Localities",", Journal of Mathematics and Physics, 1941.",[589,590,591],"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":70,"searchDepth":94,"depth":94,"links":593},[594,595,596,597],{"id":33,"depth":94,"text":34},{"id":45,"depth":94,"text":46},{"id":530,"depth":94,"text":531},{"id":551,"depth":94,"text":552},"The transportation problem is a staple: you have supplies at several sources,\ndemands at several destinations, and a per-unit shipping cost for each\nsource–destination pair. You want the shipping plan that meets every demand at\nminimum total cost. With quicopt it is a short linear program (LP) in\nPython.","md",[601,604,607],{"q":602,"a":603},"Is the northwest-corner or greedy method good enough?","Those give a feasible shipping plan, not a minimum-cost one. The LP returns the provably cheapest plan directly.",{"q":605,"a":606},"What if supply and demand don't balance?","Use \u003C= on supplies and >= on demands (or add a dummy source\u002Fsink). It stays a linear program; only the constraints change.",{"q":608,"a":609},"Is quicopt free to use?","Yes, to start: sign up for a free account, install the client with pip install \"quicopt[mathopt]\" and set your API key. The free account solves models with up to 50 variables and has a limited compute allowance; no license is needed.",{},false,"\u002Fdeveloper\u002Fexamples\u002Ftransportation",{"title":5,"description":598},"developer\u002Fexamples\u002Ftransportation","QsHN8uoo_XHfEp-wdH2jIooQw43_l7M4oGD3hDWdSos",1794337679418]