Skip to content

Commit fd1790c

Browse files
authored
Merge pull request #247 from Manas23601/manas-week-8
GSoC22 : Manas Sivakumar Week 8
2 parents 422c031 + 82ace2d commit fd1790c

20 files changed

+621
-537
lines changed

.github/workflows/ubuntu.yml

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,9 @@ jobs:
5757
postgresql-${{ matrix.psql }}-postgis-${{ matrix.postgis }} \
5858
postgresql-${{ matrix.psql }}-postgis-${{ matrix.postgis }}-scripts \
5959
postgresql-${{ matrix.psql }}-pgrouting \
60-
postgresql-server-dev-${{ matrix.psql }}
61-
wget https://github.com/google/or-tools/releases/download/v9.3/or-tools_amd64_ubuntu-20.04_v9.3.10502.tar.gz
62-
ls or-tools_amd64_ubuntu-20.04_v9.3.10502.tar.gz
63-
mkdir ortools
64-
tar xf or-tools_amd64_ubuntu-20.04_v9.3.10502.tar.gz -C ./ortools
65-
66-
60+
postgresql-server-dev-${{ matrix.psql }} \
61+
postgresql-plpython3-${{ matrix.psql }}
62+
6763
- name: Install VROOM dependencies
6864
run: |
6965
sudo apt-get install libssl-dev libasio-dev libglpk-dev

sql/or_tools/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
SET(LOCAL_FILES
2-
example.sql
2+
knapsack.sql
3+
multiple_knapsack.sql
4+
bin_packing.sql
35
)
46

57
foreach (f ${LOCAL_FILES})

sql/or_tools/bin_packing.sql

Lines changed: 110 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
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*/
127
DROP FUNCTION IF EXISTS vrp_bin_packing CASCADE;
228
DROP TABLE IF EXISTS bin_packing_data CASCADE;
329

@@ -9,21 +35,73 @@ VALUES
935
(48), (30), (19), (36), (36), (27), (42), (42), (36), (24), (30);
1036

1137

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
1444
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')
1779
data = {}
1880
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+
2189
data['weights'] = weights
2290
data['items'] = list(range(len(weights)))
2391
data['bins'] = data['items']
2492
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+
27105
x = {}
28106
for i in data['items']:
29107
for j in data['bins']:
@@ -37,7 +115,8 @@ AS $$
37115
solver.Add(sum(x[i, j] for j in data['bins']) == 1)
38116

39117
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'])
41120

42121
solver.Minimize(solver.Sum([y[j] for j in data['bins']]))
43122

@@ -48,20 +127,34 @@ AS $$
48127
for j in data['bins']:
49128
if y[j].solution_value() == 1:
50129
bin_items = []
130+
bin_weights = []
131+
bin_values = []
51132
bin_weight = 0
133+
bin_value = 0
52134
for i in data['items']:
53135
if x[i, j].solution_value() > 0:
54136
bin_items.append(i)
137+
bin_weights.append(data['weights'][i])
55138
bin_weight += data['weights'][i]
56139
if bin_weight > 0:
57140
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)
62146
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
66155

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+
';

sql/or_tools/knapsack.sql

Lines changed: 102 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,32 @@
1+
2+
/*PGR-GNU*****************************************************************
3+
File: knapsack.sql
4+
5+
Copyright (c) 2022 GSoC-2022 pgRouting developers
6+
7+
8+
Function's developer:
9+
Copyright (c) 2021 Manas Sivakumar
10+
11+
------
12+
13+
This program is free software; you can redistribute it and/or modify
14+
it under the terms of the GNU General Public License as published by
15+
the Free Software Foundation; either version 2 of the License, or
16+
(at your option) any later version.
17+
18+
This program is distributed in the hope that it will be useful,
19+
but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+
GNU General Public License for more details.
22+
23+
You should have received a copy of the GNU General Public License
24+
along with this program; if not, write to the Free Software
25+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26+
27+
********************************************************************PGR-GNU*/
128
DROP FUNCTION IF EXISTS vrp_knapsack;
2-
drop type if exists knapsack_items;
3-
drop table if exists knapsack_data;
29+
DROP TABLE IF EXISTS knapsack_data;
430

531
CREATE TABLE knapsack_data(
632
weight INTEGER,
@@ -14,48 +40,101 @@ VALUES
1440
(4, 10),
1541
(1, 2);
1642

17-
create type knapsack_items as(
18-
index integer,
19-
weight integer,
20-
cost integer
21-
);
22-
23-
CREATE FUNCTION vrp_knapsack(inner_query text, capacity integer)
24-
RETURNS SETOF knapsack_items
43+
CREATE OR REPLACE FUNCTION vrp_knapsack(
44+
inner_query TEXT, -- weights_cost SQL
45+
capacity INTEGER, -- Knapsack Capacity
46+
max_rows INTEGER = 100000 -- Maximum number of rows to be fetched. Default is 100000.
47+
)
48+
RETURNS TEXT
2549
AS $$
26-
from ortools.algorithms import pywrapknapsack_solver
50+
try:
51+
from ortools.algorithms import pywrapknapsack_solver
52+
except Exception as err:
53+
plpy.error(err)
54+
return "Failed"
2755

28-
solver = pywrapknapsack_solver.KnapsackSolver(
29-
pywrapknapsack_solver.KnapsackSolver.
30-
KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, 'KnapsackExample')
56+
try:
57+
solver = pywrapknapsack_solver.KnapsackSolver(
58+
pywrapknapsack_solver.KnapsackSolver.
59+
KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, 'KnapsackExample')
60+
except:
61+
plpy.error('Unable to Initialize Knapsack Solver')
62+
return "Failed"
63+
3164

3265
capacities = []
3366
capacities.append(capacity)
34-
inner_query_result = plpy.execute(inner_query, 5)
67+
68+
plpy.notice('Entering Knapsack program')
69+
plpy.notice('Starting Execution of inner query')
70+
71+
try:
72+
inner_query_result = plpy.execute(inner_query, max_rows)
73+
num_of_rows = inner_query_result.nrows()
74+
colnames = inner_query_result.colnames()
75+
coltypes = inner_query_result.coltypes()
76+
plpy.info("Number of rows processed : ", num_of_rows)
77+
except plpy.SPIError as error_msg:
78+
plpy.info("Details: ",error_msg)
79+
plpy.error("Error Processing Inner Query. The given query is not a valid SQL command")
80+
return "Failed"
81+
82+
if len(colnames) != 2:
83+
plpy.error("Expected 2 columns, Got ", len(colnames))
84+
return "Failed"
85+
if ('weight' in colnames) and ('cost' in colnames):
86+
plpy.notice("SQL query returned expected column names")
87+
else:
88+
plpy.error("Expected columns weight and cost, Got ", colnames)
89+
return "Failed"
90+
if coltypes == [23, 23]:
91+
plpy.notice("SQL query returned expected column types")
92+
else:
93+
plpy.error("Returned columns of different type. Expected Integer, Integer")
94+
95+
plpy.notice('Finished Execution of inner query')
96+
3597
values = []
3698
weight1 = []
3799
weights =[]
38-
for i in range(5):
100+
for i in range(num_of_rows):
39101
values.append(inner_query_result[i]["cost"])
40102
weight1.append(inner_query_result[i]["weight"])
41103
weights.append(weight1)
42-
43-
solver.Init(values, weights, capacities)
104+
105+
try:
106+
solver.Init(values, weights, capacities)
107+
except Exception as error_msg:
108+
plpy.error(error_msg)
109+
return "Failed"
44110
computed_value = solver.Solve()
45111

46112
packed_items = []
47113
packed_weights = []
48114
packed_values = []
49115
total_weight = 0
50-
plpy.warning('Total value =', computed_value)
116+
117+
plpy.info('Total value =', computed_value)
51118
for i in range(len(values)):
52119
if solver.BestSolutionContains(i):
53120
packed_items.append(i)
54121
packed_weights.append(weights[0][i])
55122
packed_values.append(values[i])
56123
total_weight += weights[0][i]
57-
yield (i, weights[0][i], values[i])
58-
plpy.warning('Total weight:', total_weight)
59-
$$ LANGUAGE plpython3u;
124+
plpy.info('Total weight:', total_weight)
125+
plpy.info("Packed items: ", packed_items)
126+
plpy.info("Packed weights: ", packed_weights)
127+
plpy.info("Packed values: ", packed_values)
128+
plpy.notice("Exiting program")
129+
return "Success"
130+
$$ LANGUAGE plpython3u VOLATILE STRICT;
131+
132+
-- SELECT * FROM vrp_knapsack('SELECT * FROM knapsack_data' , 15);
133+
134+
-- COMMENTS
60135

61-
SELECT * from vrp_knapsack('SELECT * from knapsack_data' , 15);
136+
COMMENT ON FUNCTION vrp_knapsack(TEXT, INTEGER, INTEGER)
137+
IS 'vrp_knapsack
138+
- Documentation:
139+
- ${PROJECT_DOC_LINK}/vrp_knapsack.html
140+
';

0 commit comments

Comments
 (0)