[{"data":1,"prerenderedAt":1884},["ShallowReactive",2],{"technical-blog-page-content":3,"technical-blog-post-problem-solved-implementing-or-tools-assigning-part-3-of-3":30,"technical-blog-author-problem-solved-implementing-or-tools-assigning-part-3-of-3":1872},{"id":4,"title":5,"author":6,"blogTags":6,"body":7,"customExcerpt":6,"date":6,"description":11,"excerpt":6,"extension":14,"h1":15,"image":6,"meta":16,"navigation":17,"path":18,"readingStats":19,"seo":24,"stem":28,"__hash__":29},"technicalBlogPage\u002Ftechnical-blog-page.md","Technical Blog Page",null,{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"md","Technical insights, stories and opinions from our team of consultants, analysts, developers and testers.",{},true,"\u002Ftechnical-blog-page",{"text":20,"minutes":21,"time":22,"words":23},"1 min read",0.29,17400,58,{"title":25,"description":26,"keywords":27},"Technology Insights | Audacia Digital Transformation","Technical insights, stories and opinions from leading software development company Audacia's teams of consultants, analysts, developers and testers.","Digital transformation technology, Technology blog, Technology insights, software development blog, software engineering blog","technical-blog-page","XD1gWfEur9Mu64WptQ5pF-e7Ej60LGiq7sRC58wOAeQ",{"id":31,"title":32,"author":33,"blogTags":34,"body":37,"customExcerpt":1854,"date":1855,"description":1856,"excerpt":1857,"extension":14,"h1":6,"image":1858,"meta":1859,"navigation":17,"path":1860,"readingStats":1861,"seo":1866,"stem":1870,"__hash__":1871},"technicalBlog\u002Ftechnical-blog\u002Fproblem-solved-implementing-or-tools-assigning-part-3-of-3.md","Problem Solved: Implementing OR-Tools - Assigning (Part 3 of 3)","Owen Lacey",[35,36],"OR-Tools","NET",{"type":8,"value":38,"toc":1851},[39,49,54,57,60,66,69,74,77,507,510,753,756,1094,1097,1100,1104,1318,1321,1324,1327,1503,1506,1800,1803,1806,1816,1835,1838,1841,1847],[40,41,42,43,48],"p",{},"In ",[44,45,47],"a",{"href":46},"\u002Ftechnical-blog\u002Fproblem-solved-implementing-or-tools-scheduling-part-2-of-3","part two"," of our OR-Tools series, we showed how to solve a scheduling problem using OR-Tools. The third and final instalment of this series concerns an assignment problem - handing out pizzas to employees. Put differently, each pizza must be assigned to an employee and optimise how much they like their pizza in the process.",[50,51,53],"h2",{"id":52},"_3-assigning","3. Assigning",[40,55,56],{},"As with previous stages, we have several rules that will condition the execution:",[40,58,59],{},"Each employee is given a maximum of one pizza\nEach pizza is distributed once (you can’t share a pizza!)\nPizzas are leftover if there are more pizzas than employees",[40,61,62],{},[63,64],"img",{"alt":11,"src":65},"\u002Fimg\u002Ftechnical-blog\u002Fpizza-employee-diagram.jpg",[40,67,68],{},"Here we have a bipartite graph with many-to-many correspondences. This graph is showing us that, while we can have a leftover pizza, every employee must be assigned a pizza first.",[70,71,73],"h4",{"id":72},"_31-unit-tests","3.1. Unit Tests",[40,75,76],{},"The first test is Each_employee_gets_a_pizza() (below). The test is not specifying preference at this point. All we are concerned with is that the dictionary returns a count of employees; so, it has X amount items in it, where X is the number of employees, regardless of their assigned pizza type.",[78,79,83],"pre",{"className":80,"code":81,"language":82,"meta":11,"style":11},"language-csharp shiki shiki-themes github-light","[Fact]\npublic void Each_employee_gets_a_pizza()\n{\n    var random = new System.Random();\n    var employees = new List\n    {\n        new(random.Forename(), random.Next(0, 10), random.Next(0, 10), random.Next(0, 10)),\n        new(random.Forename(), random.Next(0, 10), random.Next(0, 10), random.Next(0, 10)),\n        new(random.Forename(), random.Next(0, 10), random.Next(0, 10), random.Next(0, 10))\n    };\n    var model = new AssignPizzaModel\n    {\n        Employees = employees,\n        \u002F\u002F Make more than enough pizzas\n        Pizzas = Enumerable.Range(0, 10)\n            .Select(_ => random.Enum())\n            .ToList()\n    };\n \n    var solver = new AssignPizzaSolver(model);\n    var assignment = solver.Solve();\n \n    assignment.Should().HaveCount(employees.Count);\n}\n","csharp",[84,85,86,102,117,123,150,165,171,230,277,325,331,346,351,363,370,395,421,431,436,442,460,478,483,501],"code",{"__ignoreMap":11},[87,88,91,95,99],"span",{"class":89,"line":90},"line",1,[87,92,94],{"class":93},"sgsFI","[",[87,96,98],{"class":97},"s7eDp","Fact",[87,100,101],{"class":93},"]\n",[87,103,104,108,111,114],{"class":89,"line":12},[87,105,107],{"class":106},"sD7c4","public",[87,109,110],{"class":106}," void",[87,112,113],{"class":97}," Each_employee_gets_a_pizza",[87,115,116],{"class":93},"()\n",[87,118,120],{"class":89,"line":119},3,[87,121,122],{"class":93},"{\n",[87,124,126,129,132,135,138,141,144,147],{"class":89,"line":125},4,[87,127,128],{"class":106},"    var",[87,130,131],{"class":97}," random",[87,133,134],{"class":106}," =",[87,136,137],{"class":106}," new",[87,139,140],{"class":97}," System",[87,142,143],{"class":93},".",[87,145,146],{"class":97},"Random",[87,148,149],{"class":93},"();\n",[87,151,153,155,158,160,162],{"class":89,"line":152},5,[87,154,128],{"class":106},[87,156,157],{"class":97}," employees",[87,159,134],{"class":106},[87,161,137],{"class":106},[87,163,164],{"class":97}," List\n",[87,166,168],{"class":89,"line":167},6,[87,169,170],{"class":93},"    {\n",[87,172,174,177,180,183,186,189,192,196,199,202,205,207,209,211,213,215,217,219,221,223,225,227],{"class":89,"line":173},7,[87,175,176],{"class":106},"        new",[87,178,179],{"class":93},"(random.",[87,181,182],{"class":97},"Forename",[87,184,185],{"class":93},"(), random.",[87,187,188],{"class":97},"Next",[87,190,191],{"class":93},"(",[87,193,195],{"class":194},"sYu0t","0",[87,197,198],{"class":93},", ",[87,200,201],{"class":194},"10",[87,203,204],{"class":93},"), random.",[87,206,188],{"class":97},[87,208,191],{"class":93},[87,210,195],{"class":194},[87,212,198],{"class":93},[87,214,201],{"class":194},[87,216,204],{"class":93},[87,218,188],{"class":97},[87,220,191],{"class":93},[87,222,195],{"class":194},[87,224,198],{"class":93},[87,226,201],{"class":194},[87,228,229],{"class":93},")),\n",[87,231,233,235,237,239,241,243,245,247,249,251,253,255,257,259,261,263,265,267,269,271,273,275],{"class":89,"line":232},8,[87,234,176],{"class":106},[87,236,179],{"class":93},[87,238,182],{"class":97},[87,240,185],{"class":93},[87,242,188],{"class":97},[87,244,191],{"class":93},[87,246,195],{"class":194},[87,248,198],{"class":93},[87,250,201],{"class":194},[87,252,204],{"class":93},[87,254,188],{"class":97},[87,256,191],{"class":93},[87,258,195],{"class":194},[87,260,198],{"class":93},[87,262,201],{"class":194},[87,264,204],{"class":93},[87,266,188],{"class":97},[87,268,191],{"class":93},[87,270,195],{"class":194},[87,272,198],{"class":93},[87,274,201],{"class":194},[87,276,229],{"class":93},[87,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308,310,312,314,316,318,320,322],{"class":89,"line":279},9,[87,281,176],{"class":106},[87,283,179],{"class":93},[87,285,182],{"class":97},[87,287,185],{"class":93},[87,289,188],{"class":97},[87,291,191],{"class":93},[87,293,195],{"class":194},[87,295,198],{"class":93},[87,297,201],{"class":194},[87,299,204],{"class":93},[87,301,188],{"class":97},[87,303,191],{"class":93},[87,305,195],{"class":194},[87,307,198],{"class":93},[87,309,201],{"class":194},[87,311,204],{"class":93},[87,313,188],{"class":97},[87,315,191],{"class":93},[87,317,195],{"class":194},[87,319,198],{"class":93},[87,321,201],{"class":194},[87,323,324],{"class":93},"))\n",[87,326,328],{"class":89,"line":327},10,[87,329,330],{"class":93},"    };\n",[87,332,334,336,339,341,343],{"class":89,"line":333},11,[87,335,128],{"class":106},[87,337,338],{"class":97}," model",[87,340,134],{"class":106},[87,342,137],{"class":106},[87,344,345],{"class":97}," AssignPizzaModel\n",[87,347,349],{"class":89,"line":348},12,[87,350,170],{"class":93},[87,352,354,357,360],{"class":89,"line":353},13,[87,355,356],{"class":93},"        Employees ",[87,358,359],{"class":106},"=",[87,361,362],{"class":93}," employees,\n",[87,364,366],{"class":89,"line":365},14,[87,367,369],{"class":368},"sAwPA","        \u002F\u002F Make more than enough pizzas\n",[87,371,373,376,378,381,384,386,388,390,392],{"class":89,"line":372},15,[87,374,375],{"class":93},"        Pizzas ",[87,377,359],{"class":106},[87,379,380],{"class":93}," Enumerable.",[87,382,383],{"class":97},"Range",[87,385,191],{"class":93},[87,387,195],{"class":194},[87,389,198],{"class":93},[87,391,201],{"class":194},[87,393,394],{"class":93},")\n",[87,396,398,401,404,406,409,412,415,418],{"class":89,"line":397},16,[87,399,400],{"class":93},"            .",[87,402,403],{"class":97},"Select",[87,405,191],{"class":93},[87,407,408],{"class":97},"_",[87,410,411],{"class":106}," =>",[87,413,414],{"class":93}," random.",[87,416,417],{"class":97},"Enum",[87,419,420],{"class":93},"())\n",[87,422,424,426,429],{"class":89,"line":423},17,[87,425,400],{"class":93},[87,427,428],{"class":97},"ToList",[87,430,116],{"class":93},[87,432,434],{"class":89,"line":433},18,[87,435,330],{"class":93},[87,437,439],{"class":89,"line":438},19,[87,440,441],{"class":93}," \n",[87,443,445,447,450,452,454,457],{"class":89,"line":444},20,[87,446,128],{"class":106},[87,448,449],{"class":97}," solver",[87,451,134],{"class":106},[87,453,137],{"class":106},[87,455,456],{"class":97}," AssignPizzaSolver",[87,458,459],{"class":93},"(model);\n",[87,461,463,465,468,470,473,476],{"class":89,"line":462},21,[87,464,128],{"class":106},[87,466,467],{"class":97}," assignment",[87,469,134],{"class":106},[87,471,472],{"class":93}," solver.",[87,474,475],{"class":97},"Solve",[87,477,149],{"class":93},[87,479,481],{"class":89,"line":480},22,[87,482,441],{"class":93},[87,484,486,489,492,495,498],{"class":89,"line":485},23,[87,487,488],{"class":93},"    assignment.",[87,490,491],{"class":97},"Should",[87,493,494],{"class":93},"().",[87,496,497],{"class":97},"HaveCount",[87,499,500],{"class":93},"(employees.Count);\n",[87,502,504],{"class":89,"line":503},24,[87,505,506],{"class":93},"}\n",[40,508,509],{},"Moving on, Undesirable_pizzas_are_left_over() is for when we have a surplus of pizzas, and employees do not like one type of pizza as much as the other.",[78,511,513],{"className":80,"code":512,"language":82,"meta":11,"style":11},"[Fact]\npublic void Undesirable_pizzas_are_left_over()\n{\n    \u002F\u002F Create some employees that all don't like hawaiian as much as the other types\n    var random = new System.Random();\n    var employees = new List\n    {\n        new(random.Forename(), margheritaPreference: 10, pepperoniPreference: 10, hawaiianPreference: 9),\n        new(random.Forename(), margheritaPreference: 10, pepperoniPreference: 10, hawaiianPreference: 9)\n    };\n    var model = new AssignPizzaModel\n    {\n        Employees = employees,\n        Pizzas = new List {PizzaType.Margherita, PizzaType.Pepperoni, PizzaType.Hawaiian}\n    };\n \n    var solver = new AssignPizzaSolver(model);\n    var assignment = solver.Solve();\n \n    assignment.Values.Should().NotContain(PizzaType.Hawaiian);\n}\n",[84,514,515,523,534,538,543,561,573,577,618,652,656,668,672,680,694,698,702,716,730,734,749],{"__ignoreMap":11},[87,516,517,519,521],{"class":89,"line":90},[87,518,94],{"class":93},[87,520,98],{"class":97},[87,522,101],{"class":93},[87,524,525,527,529,532],{"class":89,"line":12},[87,526,107],{"class":106},[87,528,110],{"class":106},[87,530,531],{"class":97}," Undesirable_pizzas_are_left_over",[87,533,116],{"class":93},[87,535,536],{"class":89,"line":119},[87,537,122],{"class":93},[87,539,540],{"class":89,"line":125},[87,541,542],{"class":368},"    \u002F\u002F Create some employees that all don't like hawaiian as much as the other types\n",[87,544,545,547,549,551,553,555,557,559],{"class":89,"line":152},[87,546,128],{"class":106},[87,548,131],{"class":97},[87,550,134],{"class":106},[87,552,137],{"class":106},[87,554,140],{"class":97},[87,556,143],{"class":93},[87,558,146],{"class":97},[87,560,149],{"class":93},[87,562,563,565,567,569,571],{"class":89,"line":167},[87,564,128],{"class":106},[87,566,157],{"class":97},[87,568,134],{"class":106},[87,570,137],{"class":106},[87,572,164],{"class":97},[87,574,575],{"class":89,"line":173},[87,576,170],{"class":93},[87,578,579,581,583,585,588,591,594,596,598,601,603,605,607,610,612,615],{"class":89,"line":232},[87,580,176],{"class":106},[87,582,179],{"class":93},[87,584,182],{"class":97},[87,586,587],{"class":93},"(), ",[87,589,590],{"class":97},"margheritaPreference",[87,592,593],{"class":93},": ",[87,595,201],{"class":194},[87,597,198],{"class":93},[87,599,600],{"class":97},"pepperoniPreference",[87,602,593],{"class":93},[87,604,201],{"class":194},[87,606,198],{"class":93},[87,608,609],{"class":97},"hawaiianPreference",[87,611,593],{"class":93},[87,613,614],{"class":194},"9",[87,616,617],{"class":93},"),\n",[87,619,620,622,624,626,628,630,632,634,636,638,640,642,644,646,648,650],{"class":89,"line":279},[87,621,176],{"class":106},[87,623,179],{"class":93},[87,625,182],{"class":97},[87,627,587],{"class":93},[87,629,590],{"class":97},[87,631,593],{"class":93},[87,633,201],{"class":194},[87,635,198],{"class":93},[87,637,600],{"class":97},[87,639,593],{"class":93},[87,641,201],{"class":194},[87,643,198],{"class":93},[87,645,609],{"class":97},[87,647,593],{"class":93},[87,649,614],{"class":194},[87,651,394],{"class":93},[87,653,654],{"class":89,"line":327},[87,655,330],{"class":93},[87,657,658,660,662,664,666],{"class":89,"line":333},[87,659,128],{"class":106},[87,661,338],{"class":97},[87,663,134],{"class":106},[87,665,137],{"class":106},[87,667,345],{"class":97},[87,669,670],{"class":89,"line":348},[87,671,170],{"class":93},[87,673,674,676,678],{"class":89,"line":353},[87,675,356],{"class":93},[87,677,359],{"class":106},[87,679,362],{"class":93},[87,681,682,684,686,688,691],{"class":89,"line":365},[87,683,375],{"class":93},[87,685,359],{"class":106},[87,687,137],{"class":106},[87,689,690],{"class":97}," List",[87,692,693],{"class":93}," {PizzaType.Margherita, PizzaType.Pepperoni, PizzaType.Hawaiian}\n",[87,695,696],{"class":89,"line":372},[87,697,330],{"class":93},[87,699,700],{"class":89,"line":397},[87,701,441],{"class":93},[87,703,704,706,708,710,712,714],{"class":89,"line":423},[87,705,128],{"class":106},[87,707,449],{"class":97},[87,709,134],{"class":106},[87,711,137],{"class":106},[87,713,456],{"class":97},[87,715,459],{"class":93},[87,717,718,720,722,724,726,728],{"class":89,"line":433},[87,719,128],{"class":106},[87,721,467],{"class":97},[87,723,134],{"class":106},[87,725,472],{"class":93},[87,727,475],{"class":97},[87,729,149],{"class":93},[87,731,732],{"class":89,"line":438},[87,733,441],{"class":93},[87,735,736,739,741,743,746],{"class":89,"line":444},[87,737,738],{"class":93},"    assignment.Values.",[87,740,491],{"class":97},[87,742,494],{"class":93},[87,744,745],{"class":97},"NotContain",[87,747,748],{"class":93},"(PizzaType.Hawaiian);\n",[87,750,751],{"class":89,"line":462},[87,752,506],{"class":93},[40,754,755],{},"As we’re still making every type of pizza, what we are stating here is that the values do not contain the undesirable pizza type. In this case, we see that Hawaiian has been specified as the undesirable type, which means that one employee would receive margherita, one would receive pepperoni and the Hawaiian would be leftover.",[78,757,759],{"className":80,"code":758,"language":82,"meta":11,"style":11},"[Fact]\npublic void Assigns_pizzas_that_people_like_the_most()\n{\n    var random = new System.Random();\n    var firstPerson = random.Forename();\n    var secondPerson = random.Forename();\n    var thirdPerson = random.Forename();\n    var employees = new List\n    {\n        new(firstPerson, margheritaPreference: 6, pepperoniPreference: 2, hawaiianPreference: 2),\n        new(secondPerson, margheritaPreference: 10, pepperoniPreference: 8, hawaiianPreference: 7),\n        new(thirdPerson, margheritaPreference: 10, pepperoniPreference: 9, hawaiianPreference: 2)\n    };\n    var model = new AssignPizzaModel\n    {\n        Employees = employees,\n        Pizzas = new List {PizzaType.Margherita, PizzaType.Pepperoni, PizzaType.Hawaiian}\n    };\n \n    var solver = new AssignPizzaSolver(model);\n    var assignment = solver.Solve();\n \n    \u002F\u002F Though the first person isn't as passionate about margherita as the rest, they really don't like the others\n    assignment[firstPerson].Should().Be(PizzaType.Margherita);\n    assignment[secondPerson].Should().Be(PizzaType.Hawaiian);\n    assignment[thirdPerson].Should().Be(PizzaType.Pepperoni);\n}\n",[84,760,761,769,780,784,802,817,832,847,859,863,896,929,960,964,976,980,988,1000,1004,1008,1022,1036,1040,1045,1060,1074,1089],{"__ignoreMap":11},[87,762,763,765,767],{"class":89,"line":90},[87,764,94],{"class":93},[87,766,98],{"class":97},[87,768,101],{"class":93},[87,770,771,773,775,778],{"class":89,"line":12},[87,772,107],{"class":106},[87,774,110],{"class":106},[87,776,777],{"class":97}," Assigns_pizzas_that_people_like_the_most",[87,779,116],{"class":93},[87,781,782],{"class":89,"line":119},[87,783,122],{"class":93},[87,785,786,788,790,792,794,796,798,800],{"class":89,"line":125},[87,787,128],{"class":106},[87,789,131],{"class":97},[87,791,134],{"class":106},[87,793,137],{"class":106},[87,795,140],{"class":97},[87,797,143],{"class":93},[87,799,146],{"class":97},[87,801,149],{"class":93},[87,803,804,806,809,811,813,815],{"class":89,"line":152},[87,805,128],{"class":106},[87,807,808],{"class":97}," firstPerson",[87,810,134],{"class":106},[87,812,414],{"class":93},[87,814,182],{"class":97},[87,816,149],{"class":93},[87,818,819,821,824,826,828,830],{"class":89,"line":167},[87,820,128],{"class":106},[87,822,823],{"class":97}," secondPerson",[87,825,134],{"class":106},[87,827,414],{"class":93},[87,829,182],{"class":97},[87,831,149],{"class":93},[87,833,834,836,839,841,843,845],{"class":89,"line":173},[87,835,128],{"class":106},[87,837,838],{"class":97}," thirdPerson",[87,840,134],{"class":106},[87,842,414],{"class":93},[87,844,182],{"class":97},[87,846,149],{"class":93},[87,848,849,851,853,855,857],{"class":89,"line":232},[87,850,128],{"class":106},[87,852,157],{"class":97},[87,854,134],{"class":106},[87,856,137],{"class":106},[87,858,164],{"class":97},[87,860,861],{"class":89,"line":279},[87,862,170],{"class":93},[87,864,865,867,870,872,874,877,879,881,883,886,888,890,892,894],{"class":89,"line":327},[87,866,176],{"class":106},[87,868,869],{"class":93},"(firstPerson, ",[87,871,590],{"class":97},[87,873,593],{"class":93},[87,875,876],{"class":194},"6",[87,878,198],{"class":93},[87,880,600],{"class":97},[87,882,593],{"class":93},[87,884,885],{"class":194},"2",[87,887,198],{"class":93},[87,889,609],{"class":97},[87,891,593],{"class":93},[87,893,885],{"class":194},[87,895,617],{"class":93},[87,897,898,900,903,905,907,909,911,913,915,918,920,922,924,927],{"class":89,"line":333},[87,899,176],{"class":106},[87,901,902],{"class":93},"(secondPerson, ",[87,904,590],{"class":97},[87,906,593],{"class":93},[87,908,201],{"class":194},[87,910,198],{"class":93},[87,912,600],{"class":97},[87,914,593],{"class":93},[87,916,917],{"class":194},"8",[87,919,198],{"class":93},[87,921,609],{"class":97},[87,923,593],{"class":93},[87,925,926],{"class":194},"7",[87,928,617],{"class":93},[87,930,931,933,936,938,940,942,944,946,948,950,952,954,956,958],{"class":89,"line":348},[87,932,176],{"class":106},[87,934,935],{"class":93},"(thirdPerson, ",[87,937,590],{"class":97},[87,939,593],{"class":93},[87,941,201],{"class":194},[87,943,198],{"class":93},[87,945,600],{"class":97},[87,947,593],{"class":93},[87,949,614],{"class":194},[87,951,198],{"class":93},[87,953,609],{"class":97},[87,955,593],{"class":93},[87,957,885],{"class":194},[87,959,394],{"class":93},[87,961,962],{"class":89,"line":353},[87,963,330],{"class":93},[87,965,966,968,970,972,974],{"class":89,"line":365},[87,967,128],{"class":106},[87,969,338],{"class":97},[87,971,134],{"class":106},[87,973,137],{"class":106},[87,975,345],{"class":97},[87,977,978],{"class":89,"line":372},[87,979,170],{"class":93},[87,981,982,984,986],{"class":89,"line":397},[87,983,356],{"class":93},[87,985,359],{"class":106},[87,987,362],{"class":93},[87,989,990,992,994,996,998],{"class":89,"line":423},[87,991,375],{"class":93},[87,993,359],{"class":106},[87,995,137],{"class":106},[87,997,690],{"class":97},[87,999,693],{"class":93},[87,1001,1002],{"class":89,"line":433},[87,1003,330],{"class":93},[87,1005,1006],{"class":89,"line":438},[87,1007,441],{"class":93},[87,1009,1010,1012,1014,1016,1018,1020],{"class":89,"line":444},[87,1011,128],{"class":106},[87,1013,449],{"class":97},[87,1015,134],{"class":106},[87,1017,137],{"class":106},[87,1019,456],{"class":97},[87,1021,459],{"class":93},[87,1023,1024,1026,1028,1030,1032,1034],{"class":89,"line":462},[87,1025,128],{"class":106},[87,1027,467],{"class":97},[87,1029,134],{"class":106},[87,1031,472],{"class":93},[87,1033,475],{"class":97},[87,1035,149],{"class":93},[87,1037,1038],{"class":89,"line":480},[87,1039,441],{"class":93},[87,1041,1042],{"class":89,"line":485},[87,1043,1044],{"class":368},"    \u002F\u002F Though the first person isn't as passionate about margherita as the rest, they really don't like the others\n",[87,1046,1047,1050,1052,1054,1057],{"class":89,"line":503},[87,1048,1049],{"class":93},"    assignment[firstPerson].",[87,1051,491],{"class":97},[87,1053,494],{"class":93},[87,1055,1056],{"class":97},"Be",[87,1058,1059],{"class":93},"(PizzaType.Margherita);\n",[87,1061,1063,1066,1068,1070,1072],{"class":89,"line":1062},25,[87,1064,1065],{"class":93},"    assignment[secondPerson].",[87,1067,491],{"class":97},[87,1069,494],{"class":93},[87,1071,1056],{"class":97},[87,1073,748],{"class":93},[87,1075,1077,1080,1082,1084,1086],{"class":89,"line":1076},26,[87,1078,1079],{"class":93},"    assignment[thirdPerson].",[87,1081,491],{"class":97},[87,1083,494],{"class":93},[87,1085,1056],{"class":97},[87,1087,1088],{"class":93},"(PizzaType.Pepperoni);\n",[87,1090,1092],{"class":89,"line":1091},27,[87,1093,506],{"class":93},[40,1095,1096],{},"Our third and final test looks at how best to optimise the satisfaction of employees through the pizzas they receive. In our example here, we can see that the first employee likes margherita (with a score of 6) not as much as his colleagues, but really dislikes pepperoni (which is scored at 2).",[40,1098,1099],{},"The model adds up the scores of the pizzas that people like and the only way to get 22 - the highest score and optimal solution - is by assigning pizzas that contribute to the higher score. On this basis, the first employee should get a margherita pizza even if they do not like it as much as everyone else.",[70,1101,1103],{"id":1102},"_32-assign-pizza-solver-explained","3.2. Assign Pizza Solver Explained",[78,1105,1107],{"className":80,"code":1106,"language":82,"meta":11,"style":11},"var model = new CpModel();\n \nIntVar[,] costVars = new IntVar[_numEmployees, _numPizzas];\nIntVar[] flattenedCostVars = new IntVar[_numEmployees * _numPizzas];\nint[] flattenedCosts = new int[_numEmployees * _numPizzas];\nSetModelVars(costVars, model, flattenedCostVars, flattenedCosts);\n \nAddConstraints(costVars, model);\n \n\u002F\u002F set the objective of the model\nmodel.Maximize(LinearExpr.ScalProd(flattenedCostVars, flattenedCosts));\n \n\u002F\u002F Solve\nCpSolver solver = new ();\nvar status = solver.Solve(model);\nif (status != CpSolverStatus.Optimal)\n{\n    throw OptimisationException.SubOptimalCpSolution(status);\n}\n",[84,1108,1109,1125,1129,1150,1175,1198,1206,1210,1218,1222,1227,1244,1248,1253,1267,1282,1296,1300,1314],{"__ignoreMap":11},[87,1110,1111,1114,1116,1118,1120,1123],{"class":89,"line":90},[87,1112,1113],{"class":106},"var",[87,1115,338],{"class":97},[87,1117,134],{"class":106},[87,1119,137],{"class":106},[87,1121,1122],{"class":97}," CpModel",[87,1124,149],{"class":93},[87,1126,1127],{"class":89,"line":12},[87,1128,441],{"class":93},[87,1130,1131,1134,1137,1140,1142,1144,1147],{"class":89,"line":119},[87,1132,1133],{"class":97},"IntVar",[87,1135,1136],{"class":93},"[,] ",[87,1138,1139],{"class":97},"costVars",[87,1141,134],{"class":106},[87,1143,137],{"class":106},[87,1145,1146],{"class":97}," IntVar",[87,1148,1149],{"class":93},"[_numEmployees, _numPizzas];\n",[87,1151,1152,1154,1157,1160,1162,1164,1166,1169,1172],{"class":89,"line":125},[87,1153,1133],{"class":97},[87,1155,1156],{"class":93},"[] ",[87,1158,1159],{"class":97},"flattenedCostVars",[87,1161,134],{"class":106},[87,1163,137],{"class":106},[87,1165,1146],{"class":97},[87,1167,1168],{"class":93},"[_numEmployees ",[87,1170,1171],{"class":106},"*",[87,1173,1174],{"class":93}," _numPizzas];\n",[87,1176,1177,1180,1182,1185,1187,1189,1192,1194,1196],{"class":89,"line":152},[87,1178,1179],{"class":106},"int",[87,1181,1156],{"class":93},[87,1183,1184],{"class":97},"flattenedCosts",[87,1186,134],{"class":106},[87,1188,137],{"class":106},[87,1190,1191],{"class":106}," int",[87,1193,1168],{"class":93},[87,1195,1171],{"class":106},[87,1197,1174],{"class":93},[87,1199,1200,1203],{"class":89,"line":167},[87,1201,1202],{"class":97},"SetModelVars",[87,1204,1205],{"class":93},"(costVars, model, flattenedCostVars, flattenedCosts);\n",[87,1207,1208],{"class":89,"line":173},[87,1209,441],{"class":93},[87,1211,1212,1215],{"class":89,"line":232},[87,1213,1214],{"class":97},"AddConstraints",[87,1216,1217],{"class":93},"(costVars, model);\n",[87,1219,1220],{"class":89,"line":279},[87,1221,441],{"class":93},[87,1223,1224],{"class":89,"line":327},[87,1225,1226],{"class":368},"\u002F\u002F set the objective of the model\n",[87,1228,1229,1232,1235,1238,1241],{"class":89,"line":333},[87,1230,1231],{"class":93},"model.",[87,1233,1234],{"class":97},"Maximize",[87,1236,1237],{"class":93},"(LinearExpr.",[87,1239,1240],{"class":97},"ScalProd",[87,1242,1243],{"class":93},"(flattenedCostVars, flattenedCosts));\n",[87,1245,1246],{"class":89,"line":348},[87,1247,441],{"class":93},[87,1249,1250],{"class":89,"line":353},[87,1251,1252],{"class":368},"\u002F\u002F Solve\n",[87,1254,1255,1258,1260,1262,1264],{"class":89,"line":365},[87,1256,1257],{"class":97},"CpSolver",[87,1259,449],{"class":97},[87,1261,134],{"class":106},[87,1263,137],{"class":106},[87,1265,1266],{"class":93}," ();\n",[87,1268,1269,1271,1274,1276,1278,1280],{"class":89,"line":372},[87,1270,1113],{"class":106},[87,1272,1273],{"class":97}," status",[87,1275,134],{"class":106},[87,1277,472],{"class":93},[87,1279,475],{"class":97},[87,1281,459],{"class":93},[87,1283,1284,1287,1290,1293],{"class":89,"line":397},[87,1285,1286],{"class":106},"if",[87,1288,1289],{"class":93}," (status ",[87,1291,1292],{"class":106},"!=",[87,1294,1295],{"class":93}," CpSolverStatus.Optimal)\n",[87,1297,1298],{"class":89,"line":423},[87,1299,122],{"class":93},[87,1301,1302,1305,1308,1311],{"class":89,"line":433},[87,1303,1304],{"class":106},"    throw",[87,1306,1307],{"class":93}," OptimisationException.",[87,1309,1310],{"class":97},"SubOptimalCpSolution",[87,1312,1313],{"class":93},"(status);\n",[87,1315,1316],{"class":89,"line":438},[87,1317,506],{"class":93},[40,1319,1320],{},"If we recall our 2x2 matrix, the costVars is a two-dimensional matrix of 0s and 1s, which refers to whether employees have a pizza or not - if it's a 0 they do not have a pizza, if it is a 1 then they do.",[40,1322,1323],{},"For each costVars, we create a flattenedCostVars, which can be thought of as a flattened matrix or a long list of 0s and 1s. This is how much every employee likes pizza, formatted as one long list.",[40,1325,1326],{},"In terms of the objective of the model; we are multiplying a list of 1s and 0s with a list of how much each employee likes every pizza. So, the scale product of the flattenedCostVars - which are the variables that the model is deciding to set to 1 or 0 with the known list of costs is our score that we are trying to maximise.",[78,1328,1330],{"className":80,"code":1329,"language":82,"meta":11,"style":11},"for (var employeeIndex = 0; employeeIndex \u003C _numEmployees; ++employeeIndex)\n{\n    for (var pizzaIndex = 0; pizzaIndex \u003C _numPizzas; ++pizzaIndex)\n    {\n        \u002F\u002F create a variable that is set to 1 if this employee is given this pizza, and 0 otherwise\n        costVars[employeeIndex, pizzaIndex] = model.NewIntVar(0, 1, $\"employee_{employeeIndex}_pizza_{pizzaIndex}\");\n        var flattenedIndex = employeeIndex * _numPizzas + pizzaIndex;\n        flattenedCostVars[flattenedIndex] = costVars[employeeIndex, pizzaIndex];\n        flattenedCosts[flattenedIndex] = _costs[employeeIndex, pizzaIndex];\n    }\n}\n",[84,1331,1332,1365,1369,1398,1402,1407,1450,1474,1484,1494,1499],{"__ignoreMap":11},[87,1333,1334,1337,1340,1342,1345,1347,1350,1353,1356,1359,1362],{"class":89,"line":90},[87,1335,1336],{"class":106},"for",[87,1338,1339],{"class":93}," (",[87,1341,1113],{"class":106},[87,1343,1344],{"class":97}," employeeIndex",[87,1346,134],{"class":106},[87,1348,1349],{"class":194}," 0",[87,1351,1352],{"class":93},"; employeeIndex ",[87,1354,1355],{"class":106},"\u003C",[87,1357,1358],{"class":93}," _numEmployees; ",[87,1360,1361],{"class":106},"++",[87,1363,1364],{"class":93},"employeeIndex)\n",[87,1366,1367],{"class":89,"line":12},[87,1368,122],{"class":93},[87,1370,1371,1374,1376,1378,1381,1383,1385,1388,1390,1393,1395],{"class":89,"line":119},[87,1372,1373],{"class":106},"    for",[87,1375,1339],{"class":93},[87,1377,1113],{"class":106},[87,1379,1380],{"class":97}," pizzaIndex",[87,1382,134],{"class":106},[87,1384,1349],{"class":194},[87,1386,1387],{"class":93},"; pizzaIndex ",[87,1389,1355],{"class":106},[87,1391,1392],{"class":93}," _numPizzas; ",[87,1394,1361],{"class":106},[87,1396,1397],{"class":93},"pizzaIndex)\n",[87,1399,1400],{"class":89,"line":125},[87,1401,170],{"class":93},[87,1403,1404],{"class":89,"line":152},[87,1405,1406],{"class":368},"        \u002F\u002F create a variable that is set to 1 if this employee is given this pizza, and 0 otherwise\n",[87,1408,1409,1412,1414,1417,1420,1422,1424,1426,1429,1431,1435,1438,1441,1444,1447],{"class":89,"line":167},[87,1410,1411],{"class":93},"        costVars[employeeIndex, pizzaIndex] ",[87,1413,359],{"class":106},[87,1415,1416],{"class":93}," model.",[87,1418,1419],{"class":97},"NewIntVar",[87,1421,191],{"class":93},[87,1423,195],{"class":194},[87,1425,198],{"class":93},[87,1427,1428],{"class":194},"1",[87,1430,198],{"class":93},[87,1432,1434],{"class":1433},"sYBdl","$\"employee_{",[87,1436,1437],{"class":93},"employeeIndex",[87,1439,1440],{"class":1433},"}_pizza_{",[87,1442,1443],{"class":93},"pizzaIndex",[87,1445,1446],{"class":1433},"}\"",[87,1448,1449],{"class":93},");\n",[87,1451,1452,1455,1458,1460,1463,1465,1468,1471],{"class":89,"line":173},[87,1453,1454],{"class":106},"        var",[87,1456,1457],{"class":97}," flattenedIndex",[87,1459,134],{"class":106},[87,1461,1462],{"class":93}," employeeIndex ",[87,1464,1171],{"class":106},[87,1466,1467],{"class":93}," _numPizzas ",[87,1469,1470],{"class":106},"+",[87,1472,1473],{"class":93}," pizzaIndex;\n",[87,1475,1476,1479,1481],{"class":89,"line":232},[87,1477,1478],{"class":93},"        flattenedCostVars[flattenedIndex] ",[87,1480,359],{"class":106},[87,1482,1483],{"class":93}," costVars[employeeIndex, pizzaIndex];\n",[87,1485,1486,1489,1491],{"class":89,"line":279},[87,1487,1488],{"class":93},"        flattenedCosts[flattenedIndex] ",[87,1490,359],{"class":106},[87,1492,1493],{"class":93}," _costs[employeeIndex, pizzaIndex];\n",[87,1495,1496],{"class":89,"line":327},[87,1497,1498],{"class":93},"    }\n",[87,1500,1501],{"class":89,"line":333},[87,1502,506],{"class":93},[40,1504,1505],{},"We set the model.NewIntVar and, for each employee and for each pizza, we declare a variable between 0 and 1. This is then set on the array and the constraints are added.",[78,1507,1509],{"className":80,"code":1508,"language":82,"meta":11,"style":11},"private void AddConstraints(IntVar[,] costVars, CpModel model)\n{\n    \u002F\u002F Ensure one pizza per employee\n    for (var employeeIndex = 0; employeeIndex \u003C _numEmployees; employeeIndex++)\n    {\n        IntVar[] assignments = new IntVar[_numPizzas];\n        for (var pizzaIndex = 0; pizzaIndex \u003C _numPizzas; pizzaIndex++)\n        {\n            assignments[pizzaIndex] = costVars[employeeIndex, pizzaIndex];\n        }\n \n        model.Add(LinearExpr.Sum(assignments) == 1);\n    }\n \n    \u002F\u002F Ensure no pizza is given out more than once\n    for (var pizzaIndex = 0; pizzaIndex \u003C _numPizzas; ++pizzaIndex)\n    {\n        IntVar[] vars = new IntVar[_numEmployees];\n        for (var employeeIndex = 0; employeeIndex \u003C _numEmployees; ++employeeIndex)\n        {\n            vars[employeeIndex] = costVars[employeeIndex, pizzaIndex];\n        }\n \n        model.Add(LinearExpr.Sum(vars) \u003C= 1);\n    }\n}\n",[84,1510,1511,1538,1542,1547,1572,1576,1595,1621,1626,1635,1640,1644,1668,1672,1676,1681,1705,1709,1727,1751,1755,1764,1768,1772,1792,1796],{"__ignoreMap":11},[87,1512,1513,1516,1518,1521,1523,1525,1527,1529,1531,1534,1536],{"class":89,"line":90},[87,1514,1515],{"class":106},"private",[87,1517,110],{"class":106},[87,1519,1520],{"class":97}," AddConstraints",[87,1522,191],{"class":93},[87,1524,1133],{"class":97},[87,1526,1136],{"class":93},[87,1528,1139],{"class":97},[87,1530,198],{"class":93},[87,1532,1533],{"class":97},"CpModel",[87,1535,338],{"class":97},[87,1537,394],{"class":93},[87,1539,1540],{"class":89,"line":12},[87,1541,122],{"class":93},[87,1543,1544],{"class":89,"line":119},[87,1545,1546],{"class":368},"    \u002F\u002F Ensure one pizza per employee\n",[87,1548,1549,1551,1553,1555,1557,1559,1561,1563,1565,1568,1570],{"class":89,"line":125},[87,1550,1373],{"class":106},[87,1552,1339],{"class":93},[87,1554,1113],{"class":106},[87,1556,1344],{"class":97},[87,1558,134],{"class":106},[87,1560,1349],{"class":194},[87,1562,1352],{"class":93},[87,1564,1355],{"class":106},[87,1566,1567],{"class":93}," _numEmployees; employeeIndex",[87,1569,1361],{"class":106},[87,1571,394],{"class":93},[87,1573,1574],{"class":89,"line":152},[87,1575,170],{"class":93},[87,1577,1578,1581,1583,1586,1588,1590,1592],{"class":89,"line":167},[87,1579,1580],{"class":97},"        IntVar",[87,1582,1156],{"class":93},[87,1584,1585],{"class":97},"assignments",[87,1587,134],{"class":106},[87,1589,137],{"class":106},[87,1591,1146],{"class":97},[87,1593,1594],{"class":93},"[_numPizzas];\n",[87,1596,1597,1600,1602,1604,1606,1608,1610,1612,1614,1617,1619],{"class":89,"line":173},[87,1598,1599],{"class":106},"        for",[87,1601,1339],{"class":93},[87,1603,1113],{"class":106},[87,1605,1380],{"class":97},[87,1607,134],{"class":106},[87,1609,1349],{"class":194},[87,1611,1387],{"class":93},[87,1613,1355],{"class":106},[87,1615,1616],{"class":93}," _numPizzas; pizzaIndex",[87,1618,1361],{"class":106},[87,1620,394],{"class":93},[87,1622,1623],{"class":89,"line":232},[87,1624,1625],{"class":93},"        {\n",[87,1627,1628,1631,1633],{"class":89,"line":279},[87,1629,1630],{"class":93},"            assignments[pizzaIndex] ",[87,1632,359],{"class":106},[87,1634,1483],{"class":93},[87,1636,1637],{"class":89,"line":327},[87,1638,1639],{"class":93},"        }\n",[87,1641,1642],{"class":89,"line":333},[87,1643,441],{"class":93},[87,1645,1646,1649,1652,1654,1657,1660,1663,1666],{"class":89,"line":348},[87,1647,1648],{"class":93},"        model.",[87,1650,1651],{"class":97},"Add",[87,1653,1237],{"class":93},[87,1655,1656],{"class":97},"Sum",[87,1658,1659],{"class":93},"(assignments) ",[87,1661,1662],{"class":106},"==",[87,1664,1665],{"class":194}," 1",[87,1667,1449],{"class":93},[87,1669,1670],{"class":89,"line":353},[87,1671,1498],{"class":93},[87,1673,1674],{"class":89,"line":365},[87,1675,441],{"class":93},[87,1677,1678],{"class":89,"line":372},[87,1679,1680],{"class":368},"    \u002F\u002F Ensure no pizza is given out more than once\n",[87,1682,1683,1685,1687,1689,1691,1693,1695,1697,1699,1701,1703],{"class":89,"line":397},[87,1684,1373],{"class":106},[87,1686,1339],{"class":93},[87,1688,1113],{"class":106},[87,1690,1380],{"class":97},[87,1692,134],{"class":106},[87,1694,1349],{"class":194},[87,1696,1387],{"class":93},[87,1698,1355],{"class":106},[87,1700,1392],{"class":93},[87,1702,1361],{"class":106},[87,1704,1397],{"class":93},[87,1706,1707],{"class":89,"line":423},[87,1708,170],{"class":93},[87,1710,1711,1713,1715,1718,1720,1722,1724],{"class":89,"line":433},[87,1712,1580],{"class":97},[87,1714,1156],{"class":93},[87,1716,1717],{"class":97},"vars",[87,1719,134],{"class":106},[87,1721,137],{"class":106},[87,1723,1146],{"class":97},[87,1725,1726],{"class":93},"[_numEmployees];\n",[87,1728,1729,1731,1733,1735,1737,1739,1741,1743,1745,1747,1749],{"class":89,"line":438},[87,1730,1599],{"class":106},[87,1732,1339],{"class":93},[87,1734,1113],{"class":106},[87,1736,1344],{"class":97},[87,1738,134],{"class":106},[87,1740,1349],{"class":194},[87,1742,1352],{"class":93},[87,1744,1355],{"class":106},[87,1746,1358],{"class":93},[87,1748,1361],{"class":106},[87,1750,1364],{"class":93},[87,1752,1753],{"class":89,"line":444},[87,1754,1625],{"class":93},[87,1756,1757,1760,1762],{"class":89,"line":462},[87,1758,1759],{"class":93},"            vars[employeeIndex] ",[87,1761,359],{"class":106},[87,1763,1483],{"class":93},[87,1765,1766],{"class":89,"line":480},[87,1767,1639],{"class":93},[87,1769,1770],{"class":89,"line":485},[87,1771,441],{"class":93},[87,1773,1774,1776,1778,1780,1782,1785,1788,1790],{"class":89,"line":503},[87,1775,1648],{"class":93},[87,1777,1651],{"class":97},[87,1779,1237],{"class":93},[87,1781,1656],{"class":97},[87,1783,1784],{"class":93},"(vars) ",[87,1786,1787],{"class":106},"\u003C=",[87,1789,1665],{"class":194},[87,1791,1449],{"class":93},[87,1793,1794],{"class":89,"line":1062},[87,1795,1498],{"class":93},[87,1797,1798],{"class":89,"line":1076},[87,1799,506],{"class":93},[40,1801,1802],{},"We then add the constraints which are that, for each employee, we have in the costVars and we say that the assignments is a list of all the pizzas that employees could have. The sum of the array must equal 1, to ensure that each employee gets no more or less than their one allocated pizza.",[40,1804,1805],{},"And then we say to ensure that no pizza is given out more than once. This function is like the constraint that follows it, but with the exception that this is less than or equal to. This is so that if there are more employees than pizza, the model will not give out the worst pizza.",[40,1807,1808,1809,1815],{},"Final Statements\nThis is a very dense example, which can feel particularly complex upon first viewing. Should you wish to revisit the case study, or try it out for yourself, you can access the code samples by cloning our OrToolsPlayground repo ",[44,1810,1814],{"href":1811,"rel":1812},"https:\u002F\u002Fgithub.com\u002Faudaciaconsulting\u002FAudacia.OrToolsPlayground",[1813],"nofollow","here",". You can also find the Audacia.Random repo under the same organisation.",[40,1817,1818,1823,1824,1829,1830,143],{},[44,1819,1822],{"href":1820,"rel":1821},"https:\u002F\u002Fgithub.com\u002Fgoogle\u002For-tools",[1813],"OR-Tools repo"," is also available; this is the source code for Google OR-Tools and will showcase some more examples, some of which ",[44,1825,1828],{"href":1826,"rel":1827},"https:\u002F\u002Fgithub.com\u002Fgoogle\u002For-tools\u002Fpull\u002F2358",[1813],"Audacia has contributed to",". For a variety of examples in different languages, look to the ",[44,1831,1834],{"href":1832,"rel":1833},"https:\u002F\u002Fdevelopers.google.com\u002Foptimization",[1813],"OR-Tools homepage",[40,1836,1837],{},"This piece was originally delivered as a lecture for the Leeds Digital Festival.",[40,1839,1840],{},"Audacia is a software development company based in the UK, headquartered in Leeds. View more technical insights from our teams of consultants, business analysts, developers and testers on our technology insights blog.",[44,1842,1846],{"className":1843,"href":1845},[1844],"blog-button-block","https:\u002F\u002Faudacia.co.uk\u002Ftechnical-blog\u002F","\n  Technology Insights\n",[1848,1849,1850],"style",{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}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);}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}",{"title":11,"searchDepth":12,"depth":12,"links":1852},[1853],{"id":52,"depth":12,"text":53},"The third and final instalment of this series concerns an assignment problem - handing out pizzas to employees.","2022-01-11T18:00:00.000Z","In part two of our OR-Tools series, we showed how to solve a scheduling problem using OR-Tools. The third and final instalment of this series concerns an assignment problem - handing out pizzas to employees. Put differently, each pizza must be assigned to an employee and optimise how much they like their pizza in the process.","[object Object]","\u002Fimg\u002Ftechnical-blog\u002For-tools-part-3.jpg",{},"\u002Ftechnical-blog\u002Fproblem-solved-implementing-or-tools-assigning-part-3-of-3",{"text":1862,"minutes":1863,"time":1864,"words":1865},"7 min read",6.92,415200,1384,{"description":1867,"keywords":1868,"title":1869},"Principal Consultant at software development company Audacia explains how to solve an assignment problem with Google OR-Tools. Part 3\u002F3.","Google OR Tools, software development, machine learning, software engineering, assignment problem, software development company","Implementing OR-Tools to solve assignment problems | Audacia","technical-blog\u002Fproblem-solved-implementing-or-tools-assigning-part-3-of-3","QfaEqOVnqRhclcVOMWWqc32-U2cOBuB927dxWzvC3cg",{"id":1873,"title":33,"bio":1874,"extension":14,"image":1875,"meta":1876,"stem":1882,"__hash__":1883},"author\u002Fauthors\u002Fowen-lacey.md","Owen Lacey was a Principal Software Consultant at Audacia for over 8 years. He worked across a number of industries as a developer, including manufacturing, automotive repairs and no-code development. As well as development, he oversaw the delivery of a number of projects, and was involved in consultancy for more advanced features such as machine learning and Google OR Tools.","\u002Fimg\u002Fauthors\u002Fowenheadshot.jpg",{"path":1877,"description":11,"body":1878},"\u002Fauthors\u002Fowen-lacey",{"type":8,"value":1879,"toc":1880},[],{"title":11,"searchDepth":12,"depth":12,"links":1881},[],"authors\u002Fowen-lacey","p9bCaZuwDvQLbcJQDSmEWAYqzx-Ycg3DaJgRALNfKLo",1778146006001]