1
+ /* PGR-GNU*****************************************************************
2
+ File: bin_packing.sql
3
+
4
+ Copyright (c) 2022 GSoC-2022 pgRouting developers
5
+
6
+
7
+ Function's developer:
8
+ Copyright (c) 2021 Manas Sivakumar
9
+
10
+ ------
11
+
12
+ This program is free software; you can redistribute it and/or modify
13
+ it under the terms of the GNU General Public License as published by
14
+ the Free Software Foundation; either version 2 of the License, or
15
+ (at your option) any later version.
16
+
17
+ This program is distributed in the hope that it will be useful,
18
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ GNU General Public License for more details.
21
+
22
+ You should have received a copy of the GNU General Public License
23
+ along with this program; if not, write to the Free Software
24
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25
+
26
+ ********************************************************************PGR-GNU*/
1
27
DROP FUNCTION IF EXISTS vrp_bin_packing CASCADE;
2
28
DROP TABLE IF EXISTS bin_packing_data CASCADE;
3
29
@@ -9,21 +35,73 @@ VALUES
9
35
(48 ), (30 ), (19 ), (36 ), (36 ), (27 ), (42 ), (42 ), (36 ), (24 ), (30 );
10
36
11
37
12
- CREATE FUNCTION vrp_bin_packing (inner_query text , bin_capacity integer )
13
- RETURNS integer
38
+ CREATE OR REPLACE FUNCTION vrp_bin_packing (
39
+ inner_query TEXT , -- weights SQL
40
+ bin_capacity INTEGER , -- Bin Capacity
41
+ max_rows INTEGER = 100000 -- Maximum number of rows to be fetched. Default is value = 100000.
42
+ )
43
+ RETURNS TEXT
14
44
AS $$
15
- from ortools .linear_solver import pywraplp
16
- inner_query_result = plpy .execute (inner_query, 11 )
45
+ try:
46
+ from ortools .linear_solver import pywraplp
47
+ except Exception as err:
48
+ plpy .error (err)
49
+ return " Failed"
50
+
51
+ plpy .notice (' Entering Bin Packing program' )
52
+ plpy .notice (' Starting Execution of inner query' )
53
+
54
+ try:
55
+ inner_query_result = plpy .execute (inner_query, max_rows)
56
+ num_of_rows = inner_query_result .nrows ()
57
+ colnames = inner_query_result .colnames ()
58
+ coltypes = inner_query_result .coltypes ()
59
+ plpy .info (" Number of rows processed : " , num_of_rows)
60
+ except plpy .SPIError as error_msg:
61
+ plpy .info (" Details: " ,error_msg)
62
+ plpy .error (" Error Processing Inner Query. The given query is not a valid SQL command" )
63
+ return " Failed"
64
+
65
+ if len(colnames) != 1 :
66
+ plpy .error (" Expected 1 column, Got " , len(colnames))
67
+ return " Failed"
68
+ if (' weight' in colnames):
69
+ plpy .notice (" SQL query returned expected column names" )
70
+ else:
71
+ plpy .error (" Expected column weight, Got " , colnames)
72
+ return " Failed"
73
+ if coltypes == [23 ]:
74
+ plpy .notice (" SQL query returned expected column types" )
75
+ else:
76
+ plpy .error (" Returned columns of different type. Expected Integer" )
77
+
78
+ plpy .notice (' Finished Execution of inner query' )
17
79
data = {}
18
80
weights = []
19
- for i in range(11 ):
20
- weights .append (inner_query_result[i][" weight" ])
81
+
82
+ for i in range(num_of_rows):
83
+ if type(inner_query_result[i][" weight" ]) == int :
84
+ weights .append (inner_query_result[i][" weight" ])
85
+ else:
86
+ plpy .error (" Type Mismatch. Check Table Data" )
87
+ return " Failed"
88
+
21
89
data[' weights' ] = weights
22
90
data[' items' ] = list(range(len(weights)))
23
91
data[' bins' ] = data[' items' ]
24
92
data[' bin_capacity' ] = bin_capacity
25
-
26
- solver = pywraplp .Solver .CreateSolver(' SCIP' )
93
+
94
+ try:
95
+ solver = pywraplp .Solver .CreateSolver(' SCIP' )
96
+ except:
97
+ plpy .error (" Unable to Initialize solver" )
98
+
99
+ if solver is None:
100
+ plpy .error (' SCIP solver unavailable.' )
101
+ return " Failed"
102
+
103
+ plpy .notice (' SCIP solver ready!' )
104
+
27
105
x = {}
28
106
for i in data[' items' ]:
29
107
for j in data[' bins' ]:
37
115
solver .Add (sum (x[i, j] for j in data[' bins' ]) == 1 )
38
116
39
117
for j in data[' bins' ]:
40
- solver .Add (sum (x[(i, j)] * data[' weights' ][i] for i in data[' items' ]) <= y[j] * data[' bin_capacity' ])
118
+ solver .Add (sum (x[(i, j)] * data[' weights' ][i]
119
+ for i in data[' items' ]) <= y[j] * data[' bin_capacity' ])
41
120
42
121
solver .Minimize (solver .Sum ([y[j] for j in data[' bins' ]]))
43
122
@@ -48,20 +127,34 @@ AS $$
48
127
for j in data[' bins' ]:
49
128
if y[j].solution_value() == 1 :
50
129
bin_items = []
130
+ bin_weights = []
131
+ bin_values = []
51
132
bin_weight = 0
133
+ bin_value = 0
52
134
for i in data[' items' ]:
53
135
if x[i, j].solution_value() > 0 :
54
136
bin_items .append (i)
137
+ bin_weights .append (data[' weights' ][i])
55
138
bin_weight + = data[' weights' ][i]
56
139
if bin_weight > 0 :
57
140
num_bins + = 1
58
- plpy .warning (' Bin number' , j)
59
- plpy .warning (' Items packed' , bin_items)
60
- plpy .warning (' Total weight' , bin_weight)
61
- plpy .warning (' Number of bins used' , num_bins)
141
+ plpy .info (' Bin number' , j)
142
+ plpy .info (' Items packed' , bin_items)
143
+ plpy .info (' Item weights' , bin_weights)
144
+ plpy .info (' Total weight' , bin_weight)
145
+ plpy .info (' Number of bins used' , num_bins)
62
146
else:
63
- plpy .error (' The problem does not have an optimal solution' )
64
- return 1
65
- $$ LANGUAGE plpython3u;
147
+ plpy .notice (' The problem does not have an optimal solution' )
148
+ plpy .notice (' Exiting Bin Packing program' )
149
+ return " Success"
150
+ $$ LANGUAGE plpython3u VOLATILE STRICT;
151
+
152
+ -- SELECT * FROM vrp_bin_packing('SELECT * FROM bin_packing_data', 100);
153
+
154
+ -- COMMENTS
66
155
67
- SELECT * from vrp_bin_packing(' SELECT * from bin_packing_data' , 100 );
156
+ COMMENT ON FUNCTION vrp_bin_packing(TEXT , INTEGER , INTEGER )
157
+ IS ' vrp_bin_packing
158
+ - Documentation:
159
+ - ${PROJECT_DOC_LINK}/vrp_bin_packing.html
160
+ ' ;
0 commit comments