[{"data":1,"prerenderedAt":625},["ShallowReactive",2],{"dev-\u002Fdeveloper\u002Fguides\u002Ftransportation":3},{"id":4,"title":5,"body":6,"description":608,"extension":609,"faq":610,"meta":620,"navigation":110,"noindex":110,"path":621,"seo":622,"stem":623,"__hash__":624},"content\u002Fdeveloper\u002Fguides\u002Ftransportation.md","Solve the transportation problem in Python",{"type":7,"value":8,"toc":602},"minimark",[9,13,30,35,43,47,63,528,533,537,551,554,558,583,593,598],[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(\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\")\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,519],{"__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,514,517],{"class":76,"line":505},18,[74,507,508],{"class":84},"client ",[74,510,127],{"class":80},[74,512,513],{"class":84}," Client(",[74,515,516],{"class":291},"\"https:\u002F\u002Ftry.quicoptapi.pgi.fz-juelich.de\"",[74,518,295],{"class":84},[74,520,522,525],{"class":76,"line":521},19,[74,523,524],{"class":133},"print",[74,526,527],{"class":84},"(client.solve(model).display)\n",[529,530],"term-result",{":rows":531,"cmd":532},"[\"├── 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.0023 s\"]","$ python transportation.py",[31,534,536],{"id":535},"what-you-get","What you get",[14,538,539,542,543,546,547,550],{},[51,540,541],{},"status: optimal"," means the plan is ",[18,544,545],{},"proven"," minimum-cost — total cost ",[51,548,549],{},"635",",\nfound in a couple of milliseconds. The transportation problem is totally\nunimodular, so the LP already returns whole-unit shipments without needing\ninteger variables.",[14,552,553],{},"The same model scales from a 3×4 grid to thousands of routes — you change the\ndata, not the method.",[31,555,557],{"id":556},"next","Next",[559,560,561,569,576],"ul",{},[562,563,564,565],"li",{},"The problem class behind this: ",[41,566,568],{"href":567},"\u002Fproblems\u002Flp","Linear programming (LP)",[562,570,571,572],{},"A runnable model for every supported class: ",[41,573,575],{"href":574},"\u002Fdeveloper\u002Fexamples","Examples",[562,577,578,579],{},"Set up the client and solve your first model: ",[41,580,582],{"href":581},"\u002Fdeveloper\u002Fgetting-started","Getting started",[14,584,585,588,589,592],{},[18,586,587],{},"Reference:"," F. L. Hitchcock, ",[39,590,591],{},"The Distribution of a Product from Several\nSources to Numerous Localities",", Journal of Mathematics and Physics, 1941.",[594,595],"contact-cta",{"sub":596,"title":597},"Tell us what you're optimizing. We'll help you model it and point you at the right approach.","A bigger network — or a different problem?",[599,600,601],"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":603},[604,605,606,607],{"id":33,"depth":94,"text":34},{"id":45,"depth":94,"text":46},{"id":535,"depth":94,"text":536},{"id":556,"depth":94,"text":557},"Ship units from supplies to demands at minimum total cost in Python — the transportation problem modeled as a linear program (LP) and solved with quicopt in a few lines.","md",[611,614,617],{"q":612,"a":613},"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":615,"a":616},"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":618,"a":619},"Is quicopt free to use?","Yes — pip install quicopt and your first call sets up a free key, no license.",{},"\u002Fdeveloper\u002Fguides\u002Ftransportation",{"title":5,"description":608},"developer\u002Fguides\u002Ftransportation","yT_gqn9JUV_vrYppSiWUjg4JbbNSBa65zzLQ8QvvvcQ",1784110685996]