/* P-median problem in Picat. Model and data from the OPL Manual, which describes the problem: """ The P-Median problem is a well known problem in Operations Research. The problem can be stated very simply, like this: given a set of customers with known amounts of demand, a set of candidate locations for warehouses, and the distance between each pair of customer-warehouse, choose P warehouses to open that minimize the demand-weighted distance of serving all customers from those P warehouses. """ Model created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import cp. main => go. go => P = 2, Customers = ["Albert","Bob","Chris","Daniel"], NumCustomers = length(Customers), Warehouses = ["Santa Clara", "San Jose", "Berkeley"], NumWarehouses = length(Warehouses), writeln([numCustomers=NumCustomers,numWarehouses=NumWarehouses]), Demand = [100,80,80,70], Distance = [[2, 10, 50], [2, 10, 52], [50, 60, 3], [40, 60, 1]], % decision variables OpenWarehouse = new_list(NumWarehouses), OpenWarehouse :: 0..1, ShipToCustomer = new_array(NumCustomers,NumWarehouses), ShipToCustomer :: 0..1, Z #= sum([Demand[C]*Distance[C,W]*ShipToCustomer[C,W] : C in 1..NumCustomers, W in 1..NumWarehouses]), foreach(C in 1..NumCustomers) sum([ ShipToCustomer[C,W] : W in 1..NumWarehouses]) #= 1 end, sum(OpenWarehouse) #= P, foreach(C in 1..NumCustomers, W in 1..NumWarehouses) ShipToCustomer[C,W] #=< OpenWarehouse[W] end, Vars = OpenWarehouse ++ ShipToCustomer, solve([$min(Z)],Vars), writeln(z=Z), writeln(openWarehouse=OpenWarehouse), foreach(W in 1..NumWarehouses) if OpenWarehouse[W] == 1 then println(open=Warehouses[W]) end end, foreach(C in 1..NumCustomers) S = [ShipToCustomer[C,W] : W in 1..NumWarehouses], Cust = Customers[C], WW = [Warehouses[W]: W in 1..NumWarehouses, S[W] == 1], printf("Customer %w: %w %w\n",Cust,S,WW) end, nl.