From 89eaca458f000c88bca9c963ddd1ebc8a4f4122e Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Thu, 22 Dec 2022 11:32:06 -0500 Subject: [PATCH 1/5] update predefined constraint signature --- spopt/locate/base.py | 172 +++++++++++++++++------------------ spopt/locate/coverage.py | 38 ++++---- spopt/locate/p_center.py | 4 +- spopt/locate/p_dispersion.py | 10 +- spopt/locate/p_median.py | 15 +-- spopt/tests/test_locate.py | 4 +- 6 files changed, 120 insertions(+), 123 deletions(-) diff --git a/spopt/locate/base.py b/spopt/locate/base.py index f55bfa42..62a3ee3d 100644 --- a/spopt/locate/base.py +++ b/spopt/locate/base.py @@ -178,11 +178,11 @@ def add_facility_integer_variable( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - range_facility: range + range_facility : range The range of facility points. - var_name: str + var_name : str A formatted string for the facility variable name. Returns @@ -209,11 +209,11 @@ def add_client_integer_variable( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - range_client: range + range_client : range The range of demand points. - var_name: str + var_name : str A formatted string for the demand variable name. Returns @@ -244,15 +244,15 @@ def add_client_assign_integer_variable( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - range_client: range + range_client : range The range of demand points. - range_facility: range + range_facility : range The range of facility points. - var_name: str + var_name : str A formatted string for the client assignment variable name. - lp_category: pulp.LpVariable parameter + lp_category : pulp.LpVariable parameter The category this variable is in, ``pulp.LpInteger`` or ``pulp.LpContinuous``. @@ -263,15 +263,20 @@ def add_client_assign_integer_variable( """ - cli_assgn_vars = [ + cli_assgn_vars = np.array( [ - pulp.LpVariable( - var_name.format(i=i, j=j), lowBound=0, upBound=1, cat=lp_category - ) - for j in range_facility + [ + pulp.LpVariable( + var_name.format(i=i, j=j), + lowBound=0, + upBound=1, + cat=lp_category, + ) + for j in range_facility + ] + for i in range_client ] - for i in range_client - ] + ) setattr(obj, "cli_assgn_vars", cli_assgn_vars) @@ -281,7 +286,7 @@ def add_weight_continuous_variable(obj: T_FacModel) -> None: Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. Returns @@ -301,7 +306,7 @@ def add_maximized_min_variable(obj: T_FacModel) -> None: Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. Returns @@ -316,10 +321,8 @@ def add_maximized_min_variable(obj: T_FacModel) -> None: @staticmethod def add_set_covering_constraint( obj: T_FacModel, - model: pulp.LpProblem, - ni: np.array, - range_facility: range, range_client: range, + range_facility: range, ) -> None: """ Create set covering constraints. @@ -329,17 +332,12 @@ def add_set_covering_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model: pulp.LpProblem - A ``pulp`` instance of an optimization model. - ni: numpy.array - A 2D array that defines candidate sites between facility - points within a distance to supply demand points. - range_facility: range - The range of facility points. - range_client: range + range_client : range The range of demand points. + range_facility : range + The range of facility points. Returns ------- @@ -349,9 +347,11 @@ def add_set_covering_constraint( """ if hasattr(obj, "fac_vars"): fac_vars = getattr(obj, "fac_vars") + model = getattr(obj, "problem") + ni = getattr(obj, "aij") for i in range_client: model += ( - pulp.lpSum([ni[i][j] * fac_vars[j] for j in range_facility]) >= 1 + pulp.lpSum([ni[i, j] * fac_vars[j] for j in range_facility]) >= 1 ) else: raise AttributeError( @@ -374,16 +374,16 @@ def add_backup_covering_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model: pulp.LpProblem + model : pulp.LpProblem A ``pulp`` instance of an optimization model. - ni: numpy.array + ni : numpy.array A 2D array that defines candidate sites between facility points within a distance to supply demand points. - range_facility: range + range_facility : range The range of facility points. - range_client: range + range_client : range The range of demand points. Returns @@ -428,11 +428,11 @@ def add_facility_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model: pulp.LpProblem + model : pulp.LpProblem A ``pulp`` instance of an optimization model. - p_facilities: int + p_facilities : int The number of facilities to be sited. Returns @@ -451,7 +451,7 @@ def add_facility_constraint( @staticmethod def add_predefined_facility_constraint( - obj: T_FacModel, model: pulp.LpProblem, predefined_fac: np.array + obj: T_FacModel, predefined_fac: np.array ) -> None: """ Create predefined demand constraints. @@ -459,11 +459,9 @@ def add_predefined_facility_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model: pulp.LpProblem - A ``pulp`` instance of an optimization model. - facility_indexes: numpy.array + facility_indexes : numpy.array Indexes of facilities that are already located (zero-indexed). Returns @@ -474,6 +472,7 @@ def add_predefined_facility_constraint( """ if hasattr(obj, "fac_vars"): fac_vars = getattr(obj, "fac_vars") + model = getattr(obj, "problem") for ind in range(len(predefined_fac)): if predefined_fac[ind]: fac_vars[ind].setInitialValue(1) @@ -486,7 +485,7 @@ def add_predefined_facility_constraint( @staticmethod def add_facility_capacity_constraint( - obj: T_FacModel, model, cl_ni, dq_ni, range_facility, range_client + obj: T_FacModel, dq_ni, cl_ni, range_client, range_facility ) -> None: """ set facility capacity constraint: @@ -496,30 +495,31 @@ def add_facility_capacity_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel bounded type of LocateSolver class - model: pulp.LpProblem - optimization model problem - cl_ni: np.array - one-dimensional array that defines capacity limits of facility points - dq_ni: np.array + dq_ni : np.array one-dimensional array that defines demand quantities for demand points - range_facility: range - range of facility points quantity - range_client: range + cl_ni : np.array + one-dimensional array that defines capacity limits of facility points + range_client : range range of demand points quantity + range_facility : range + range of facility points quantity Returns ------- + None + """ if hasattr(obj, "fac_vars") and hasattr(obj, "cli_assgn_vars"): fac_vars = getattr(obj, "fac_vars") cli_assn_vars = getattr(obj, "cli_assgn_vars") + model = getattr(obj, "problem") for j in range_facility: model += ( - pulp.lpSum([dq_ni[i] * cli_assn_vars[i][j] for i in range_client]) + pulp.lpSum([dq_ni[i] * cli_assn_vars[i, j] for i in range_client]) <= cl_ni[j] * fac_vars[j] ) else: @@ -529,34 +529,34 @@ def add_facility_capacity_constraint( @staticmethod def add_client_demand_satisfaction_constraint( - obj: T_FacModel, model, ni, range_client, range_facility + obj: T_FacModel, range_client, range_facility ) -> None: """ Parameters ---------- - obj: T_FacModel + obj : T_FacModel bounded type of LocateSolver class - model: pulp.LpProblem - optimization model problem - ni: np.array - two-dimensional array that defines candidate sites between facility points within a distance to supply {i} demand point - range_client: range + range_client : range range of demand points quantity - range_facility: range + range_facility : range range of facility points quantity Returns ------- + None + """ if hasattr(obj, "fac_vars") and hasattr(obj, "cli_assgn_vars"): cli_assn_vars = getattr(obj, "cli_assgn_vars") + model = getattr(obj, "problem") + aij = getattr(obj, "aij") for i in range_client: model += ( pulp.lpSum( - [int(ni[i][j]) * cli_assn_vars[i][j] for j in range_facility] + [int(aij[i, j]) * cli_assn_vars[i, j] for j in range_facility] ) == 1 ) @@ -581,16 +581,16 @@ def add_maximal_coverage_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model: pulp.LpProblem + model : pulp.LpProblem A ``pulp`` instance of an optimization model. - ni: numpy.array + ni : numpy.array A 2D array that defines candidate sites between facility points within a distance to supply demand points. - range_facility: range + range_facility : range The range of facility points. - range_client: range + range_client : range The range of demand points. Returns @@ -629,13 +629,13 @@ def add_assignment_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model: pulp.LpProblem + model : pulp.LpProblem A ``pulp`` instance of an optimization model. - range_facility: range + range_facility : range The range of facility points. - range_client: range + range_client : range The range of demand points. Returns @@ -670,13 +670,13 @@ def add_opening_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model: pulp.LpProblem + model : pulp.LpProblem A ``pulp`` instance of an optimization model. - range_facility: range + range_facility : range The range of facility points. - range_client: range + range_client : range The range of demand points. Returns @@ -714,15 +714,15 @@ def add_minimized_maximum_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model: pulp.LpProblem + model : pulp.LpProblem A ``pulp`` instance of an optimization model. cost_matrix : numpy.array A cost matrix in the form of a 2D array between origins and destinations. - range_facility: range + range_facility : range The range of facility points. - range_client: range + range_client : range The range of demand points. Returns @@ -772,13 +772,13 @@ def add_p_dispersion_interfacility_constraint( Parameters ---------- - obj: T_FacModel + obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model: pulp.LpProblem + model : pulp.LpProblem A ``pulp`` instance of an optimization model. cost_matrix : numpy.array A cost matrix in the form of a 2D array between all facility points. - range_facility: range + range_facility : range The range of facility points. Returns diff --git a/spopt/locate/coverage.py b/spopt/locate/coverage.py index 87007677..e8157081 100644 --- a/spopt/locate/coverage.py +++ b/spopt/locate/coverage.py @@ -181,8 +181,9 @@ def from_cost_matrix( """ + n_cli = cost_matrix.shape[0] + r_cli = range(n_cli) r_fac = range(cost_matrix.shape[1]) - r_cli = range(cost_matrix.shape[0]) model = pulp.LpProblem(name, pulp.LpMinimize) lscp = LSCP(name, model) @@ -198,13 +199,13 @@ def from_cost_matrix( lscp.aij[cost_matrix <= service_radius] = 1 if (demand_quantity_arr is None) and (facility_capacity_arr is not None): - demand_quantity_arr = np.ones(cost_matrix.shape[0]) + demand_quantity_arr = np.ones(n_cli) FacilityModelBuilder.add_facility_integer_variable(lscp, r_fac, "y[{i}]") if predefined_facilities_arr is not None: FacilityModelBuilder.add_predefined_facility_constraint( - lscp, lscp.problem, predefined_facilities_arr + lscp, predefined_facilities_arr ) if demand_quantity_arr is not None: @@ -222,22 +223,15 @@ def from_cost_matrix( ) FacilityModelBuilder.add_facility_capacity_constraint( - lscp, - lscp.problem, - facility_capacity_arr, - demand_quantity_arr, - r_fac, - r_cli, + lscp, demand_quantity_arr, facility_capacity_arr, r_cli, r_fac ) FacilityModelBuilder.add_client_demand_satisfaction_constraint( - lscp, lscp.problem, lscp.aij, r_cli, r_fac + lscp, r_cli, r_fac ) else: - FacilityModelBuilder.add_set_covering_constraint( - lscp, lscp.problem, lscp.aij, r_fac, r_cli - ) + FacilityModelBuilder.add_set_covering_constraint(lscp, r_cli, r_fac) lscp.__add_obj() @@ -432,7 +426,7 @@ def facility_client_array(self) -> None: array_cli = [] if fac_vars[j].value() > 0: for i in range(self.aij.shape[0]): - if self.aij[i][j] > 0: + if self.aij[i, j] > 0: array_cli.append(i) self.fac2cli.append(array_cli) @@ -666,8 +660,8 @@ def from_cost_matrix( lscp = LSCP.from_cost_matrix(cost_matrix, service_radius) lscp.solve(solver) - r_fac = range(cost_matrix.shape[1]) r_cli = range(cost_matrix.shape[0]) + r_fac = range(cost_matrix.shape[1]) model = pulp.LpProblem(name, pulp.LpMaximize) @@ -682,7 +676,7 @@ def from_cost_matrix( if predefined_facilities_arr is not None: FacilityModelBuilder.add_predefined_facility_constraint( - lscpb, lscpb.problem, predefined_facilities_arr + lscpb, predefined_facilities_arr ) lscpb.__add_obj() @@ -874,7 +868,7 @@ def facility_client_array(self) -> None: array_cli = [] if fac_vars[j].value() > 0: for i in range(self.aij.shape[0]): - if self.aij[i][j] > 0: + if self.aij[i, j] > 0: array_cli.append(i) self.fac2cli.append(array_cli) @@ -1101,8 +1095,10 @@ def from_cost_matrix( 99.0 """ + + n_cli = cost_matrix.shape[0] + r_cli = range(n_cli) r_fac = range(cost_matrix.shape[1]) - r_cli = range(cost_matrix.shape[0]) model = pulp.LpProblem(name, pulp.LpMaximize) mclp = MCLP(name, model) @@ -1112,13 +1108,13 @@ def from_cost_matrix( mclp.aij = np.zeros(cost_matrix.shape) mclp.aij[cost_matrix <= service_radius] = 1 - weights = np.reshape(weights, (cost_matrix.shape[0], 1)) + weights = np.reshape(weights, (n_cli, 1)) mclp.__add_obj(weights, r_cli) if predefined_facilities_arr is not None: FacilityModelBuilder.add_predefined_facility_constraint( - mclp, mclp.problem, predefined_facilities_arr + mclp, predefined_facilities_arr ) FacilityModelBuilder.add_maximal_coverage_constraint( @@ -1327,7 +1323,7 @@ def facility_client_array(self) -> None: if fac_vars[j].value() > 0: for i in range(self.aij.shape[0]): if cli_vars[i].value() > 0: - if self.aij[i][j] > 0: + if self.aij[i, j] > 0: array_cli.append(i) self.fac2cli.append(array_cli) diff --git a/spopt/locate/p_center.py b/spopt/locate/p_center.py index d1ab3fcc..f959a65a 100644 --- a/spopt/locate/p_center.py +++ b/spopt/locate/p_center.py @@ -200,7 +200,7 @@ def from_cost_matrix( if predefined_facilities_arr is not None: FacilityModelBuilder.add_predefined_facility_constraint( - p_center, p_center.problem, predefined_facilities_arr + p_center, predefined_facilities_arr ) p_center.__add_obj() @@ -388,7 +388,7 @@ def facility_client_array(self) -> None: array_cli = [] if fac_vars[j].value() > 0: for i in range(len(cli_vars)): - if cli_vars[i][j].value() > 0: + if cli_vars[i, j].value() > 0: array_cli.append(i) self.fac2cli.append(array_cli) diff --git a/spopt/locate/p_dispersion.py b/spopt/locate/p_dispersion.py index 2efc2b21..d4ae09ab 100644 --- a/spopt/locate/p_dispersion.py +++ b/spopt/locate/p_dispersion.py @@ -88,13 +88,13 @@ def from_cost_matrix( Parameters ---------- - cost_matrix: np.array + cost_matrix : np.array A cost matrix in the form of a 2D array between origins and destinations. p_facilities : int The number of facilities to be located. predefined_facilities_arr : numpy.array (default None) Predefined facilities that must appear in the solution. - name: str (default 'P-Dispersion') + name : str (default 'P-Dispersion') The name of the problem. Returns @@ -178,7 +178,7 @@ def from_cost_matrix( if predefined_facilities_arr is not None: FacilityModelBuilder.add_predefined_facility_constraint( - p_dispersion, p_dispersion.problem, predefined_facilities_arr + p_dispersion, predefined_facilities_arr ) FacilityModelBuilder.add_p_dispersion_interfacility_constraint( @@ -208,14 +208,14 @@ def from_geodataframe( Facility locations. facility_col : str Facility candidate sites geometry column name. - p_facilities: int + p_facilities : int The number of facilities to be located. predefined_facility_col : str (default None) Column name representing facilities are already defined. distance_metric : str (default 'euclidean') A metric used for the distance calculations supported by `scipy.spatial.distance.cdist `_. - name: str (default 'P-Dispersion') + name : str (default 'P-Dispersion') The name of the problem. Returns diff --git a/spopt/locate/p_median.py b/spopt/locate/p_median.py index 01ad49d9..cbdf623f 100644 --- a/spopt/locate/p_median.py +++ b/spopt/locate/p_median.py @@ -99,9 +99,9 @@ def __add_obj(self, range_clients: range, range_facility: range) -> None: Parameters ---------- - range_clients: range + range_clients : range The range of demand points. - range_facility: range + range_facility : range The range of facility point. Returns @@ -138,7 +138,7 @@ def from_cost_matrix( Parameters ---------- - cost_matrix: numpy.array + cost_matrix : numpy.array A cost matrix in the form of a 2D array between origins and destinations. weights : numpy.array A 1D array of service load or population demand. @@ -229,13 +229,14 @@ def from_cost_matrix( 3.027 """ - r_cli = range(cost_matrix.shape[0]) + n_cli = cost_matrix.shape[0] + r_cli = range(n_cli) r_fac = range(cost_matrix.shape[1]) model = pulp.LpProblem(name, pulp.LpMinimize) weights_sum = weights.sum() - weights = np.reshape(weights, (cost_matrix.shape[0], 1)) + weights = np.reshape(weights, (n_cli, 1)) aij = weights * cost_matrix p_median = PMedian(name, model, aij, weights_sum) @@ -247,7 +248,7 @@ def from_cost_matrix( if predefined_facilities_arr is not None: FacilityModelBuilder.add_predefined_facility_constraint( - p_median, p_median.problem, predefined_facilities_arr + p_median, predefined_facilities_arr ) p_median.__add_obj(r_cli, r_fac) @@ -443,7 +444,7 @@ def facility_client_array(self) -> None: array_cli = [] if fac_vars[j].value() > 0: for i in range(len(cli_vars)): - if cli_vars[i][j].value() > 0: + if cli_vars[i, j].value() > 0: array_cli.append(i) self.fac2cli.append(array_cli) diff --git a/spopt/tests/test_locate.py b/spopt/tests/test_locate.py index 8938f85b..54357df5 100644 --- a/spopt/tests/test_locate.py +++ b/spopt/tests/test_locate.py @@ -869,10 +869,10 @@ def setup_method(self) -> None: def test_attribute_error_add_set_covering_constraint(self): with pytest.raises(AttributeError, match="Before setting coverage constraints"): dummy_class = LSCP("dummy", pulp.LpProblem("name")) - dummy_matrix = numpy.array([]) + dummy_class.aij = numpy.array([]) dummy_range = range(1) FacilityModelBuilder.add_set_covering_constraint( - dummy_class, dummy_class.problem, dummy_matrix, dummy_range, dummy_range + dummy_class, dummy_range, dummy_range ) def test_attribute_error_add_facility_constraint(self): From d283aa47d67efe7facd511d47276f3e3af72071e Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Thu, 22 Dec 2022 12:29:19 -0500 Subject: [PATCH 2/5] update facility constraint signature --- spopt/locate/base.py | 7 ++----- spopt/locate/coverage.py | 6 ++---- spopt/locate/p_center.py | 4 +--- spopt/locate/p_dispersion.py | 2 +- spopt/locate/p_median.py | 4 +--- spopt/tests/test_locate.py | 6 ++---- spopt/tests/test_p_dispersion.py | 10 ++-------- 7 files changed, 11 insertions(+), 28 deletions(-) diff --git a/spopt/locate/base.py b/spopt/locate/base.py index 62a3ee3d..a4fcc76f 100644 --- a/spopt/locate/base.py +++ b/spopt/locate/base.py @@ -417,9 +417,7 @@ def add_backup_covering_constraint( ) @staticmethod - def add_facility_constraint( - obj: T_FacModel, model: pulp.LpProblem, p_facilities: int - ) -> None: + def add_facility_constraint(obj: T_FacModel, p_facilities: int) -> None: """ Create the facility constraint. @@ -430,8 +428,6 @@ def add_facility_constraint( obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model : pulp.LpProblem - A ``pulp`` instance of an optimization model. p_facilities : int The number of facilities to be sited. @@ -443,6 +439,7 @@ def add_facility_constraint( """ if hasattr(obj, "fac_vars"): fac_vars = getattr(obj, "fac_vars") + model = getattr(obj, "problem") model += pulp.lpSum(fac_vars) == p_facilities else: raise AttributeError( diff --git a/spopt/locate/coverage.py b/spopt/locate/coverage.py index e8157081..28720a1c 100644 --- a/spopt/locate/coverage.py +++ b/spopt/locate/coverage.py @@ -680,9 +680,7 @@ def from_cost_matrix( ) lscpb.__add_obj() - FacilityModelBuilder.add_facility_constraint( - lscpb, lscpb.problem, lscpb.lscp_obj_value - ) + FacilityModelBuilder.add_facility_constraint(lscpb, lscpb.lscp_obj_value) FacilityModelBuilder.add_backup_covering_constraint( lscpb, lscpb.problem, lscpb.aij, r_fac, r_cli ) @@ -1121,7 +1119,7 @@ def from_cost_matrix( mclp, mclp.problem, mclp.aij, r_fac, r_cli ) - FacilityModelBuilder.add_facility_constraint(mclp, mclp.problem, p_facilities) + FacilityModelBuilder.add_facility_constraint(mclp, p_facilities) return mclp diff --git a/spopt/locate/p_center.py b/spopt/locate/p_center.py index f959a65a..58f16564 100644 --- a/spopt/locate/p_center.py +++ b/spopt/locate/p_center.py @@ -205,9 +205,7 @@ def from_cost_matrix( p_center.__add_obj() - FacilityModelBuilder.add_facility_constraint( - p_center, p_center.problem, p_facilities - ) + FacilityModelBuilder.add_facility_constraint(p_center, p_facilities) FacilityModelBuilder.add_assignment_constraint( p_center, p_center.problem, r_fac, r_cli ) diff --git a/spopt/locate/p_dispersion.py b/spopt/locate/p_dispersion.py index d4ae09ab..7f1d58c7 100644 --- a/spopt/locate/p_dispersion.py +++ b/spopt/locate/p_dispersion.py @@ -173,7 +173,7 @@ def from_cost_matrix( ) FacilityModelBuilder.add_facility_constraint( - p_dispersion, p_dispersion.problem, p_dispersion.p_facilities + p_dispersion, p_dispersion.p_facilities ) if predefined_facilities_arr is not None: diff --git a/spopt/locate/p_median.py b/spopt/locate/p_median.py index cbdf623f..d076da4a 100644 --- a/spopt/locate/p_median.py +++ b/spopt/locate/p_median.py @@ -253,9 +253,7 @@ def from_cost_matrix( p_median.__add_obj(r_cli, r_fac) - FacilityModelBuilder.add_facility_constraint( - p_median, p_median.problem, p_facilities - ) + FacilityModelBuilder.add_facility_constraint(p_median, p_facilities) FacilityModelBuilder.add_assignment_constraint( p_median, p_median.problem, r_fac, r_cli ) diff --git a/spopt/tests/test_locate.py b/spopt/tests/test_locate.py index 54357df5..d32a4f8f 100644 --- a/spopt/tests/test_locate.py +++ b/spopt/tests/test_locate.py @@ -877,11 +877,9 @@ def test_attribute_error_add_set_covering_constraint(self): def test_attribute_error_add_facility_constraint(self): with pytest.raises(AttributeError, match="Before setting facility constraint"): - dummy_class = LSCP("dummy", pulp.LpProblem("name")) + dummy_class = MCLP("dummy", pulp.LpProblem("name")) dummy_p_facility = 1 - FacilityModelBuilder.add_facility_constraint( - dummy_class, dummy_class.problem, 1 - ) + FacilityModelBuilder.add_facility_constraint(dummy_class, 1) def test_attribute_error_add_maximal_coverage_constraint(self): with pytest.raises( diff --git a/spopt/tests/test_p_dispersion.py b/spopt/tests/test_p_dispersion.py index c4eefbf9..04309391 100644 --- a/spopt/tests/test_p_dispersion.py +++ b/spopt/tests/test_p_dispersion.py @@ -192,11 +192,7 @@ def test_attribute_error_add_facility_constraint(self): with pytest.raises(AttributeError, match="Before setting facility constraint"): dummy_p_facility = 1 dummy_class = PDispersion("dummy", pulp.LpProblem("name"), dummy_p_facility) - FacilityModelBuilder.add_facility_constraint( - dummy_class, - dummy_class.problem, - dummy_p_facility, - ) + FacilityModelBuilder.add_facility_constraint(dummy_class, dummy_p_facility) def test_attribute_error_add_p_dispersion_interfacility_constraint(self): with pytest.raises( @@ -218,9 +214,7 @@ def test_attribute_error_add_predefined_facility_constraint(self): dummy_p_facility = 1 dummy_matrix = numpy.array([]) dummy_class = PDispersion("dummy", pulp.LpProblem("name"), dummy_p_facility) - FacilityModelBuilder.add_facility_constraint( - dummy_class, dummy_class.problem, dummy_matrix - ) + FacilityModelBuilder.add_facility_constraint(dummy_class, dummy_matrix) def test_warning_facility_geodataframe(self): with pytest.warns( From 5463b3f81ba596344a18b7c5a1e6ba3ad69cc948 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Thu, 22 Dec 2022 12:40:37 -0500 Subject: [PATCH 3/5] update backup covering constraint signature --- spopt/locate/base.py | 9 ++------- spopt/locate/coverage.py | 4 +--- spopt/tests/test_lscpb.py | 5 +---- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/spopt/locate/base.py b/spopt/locate/base.py index a4fcc76f..baf5d5e7 100644 --- a/spopt/locate/base.py +++ b/spopt/locate/base.py @@ -361,8 +361,6 @@ def add_set_covering_constraint( @staticmethod def add_backup_covering_constraint( obj: T_FacModel, - model: pulp.LpProblem, - ni: np.array, range_facility: range, range_client: range, ) -> None: @@ -376,11 +374,6 @@ def add_backup_covering_constraint( obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model : pulp.LpProblem - A ``pulp`` instance of an optimization model. - ni : numpy.array - A 2D array that defines candidate sites between facility - points within a distance to supply demand points. range_facility : range The range of facility points. range_client : range @@ -395,6 +388,8 @@ def add_backup_covering_constraint( if hasattr(obj, "fac_vars"): fac_vars = getattr(obj, "fac_vars") cli_vars = getattr(obj, "cli_vars") + model = getattr(obj, "problem") + ni = getattr(obj, "aij") for i in range_client: if sum(ni[i]) >= 2: model += ( diff --git a/spopt/locate/coverage.py b/spopt/locate/coverage.py index 28720a1c..6e06a19a 100644 --- a/spopt/locate/coverage.py +++ b/spopt/locate/coverage.py @@ -681,9 +681,7 @@ def from_cost_matrix( lscpb.__add_obj() FacilityModelBuilder.add_facility_constraint(lscpb, lscpb.lscp_obj_value) - FacilityModelBuilder.add_backup_covering_constraint( - lscpb, lscpb.problem, lscpb.aij, r_fac, r_cli - ) + FacilityModelBuilder.add_backup_covering_constraint(lscpb, r_fac, r_cli) return lscpb diff --git a/spopt/tests/test_lscpb.py b/spopt/tests/test_lscpb.py index 486e6064..93e70056 100644 --- a/spopt/tests/test_lscpb.py +++ b/spopt/tests/test_lscpb.py @@ -330,18 +330,15 @@ def test_warning_lscpb_demand_geodataframe(self): pulp.PULP_CBC_CMD(msg=False), ) - def test_attribute_error_add_facility_constraint(self): + def test_attribute_error_add_backup_covering_constraint(self): with pytest.raises(AttributeError, match="Before setting backup coverage"): dummy_class = LSCPB( "dummy", pulp.LpProblem("name"), pulp.PULP_CBC_CMD(msg=False) ) - dummy_p_facility = 1 dummy_fac_r = 0 dummy_cli_r = 0 FacilityModelBuilder.add_backup_covering_constraint( dummy_class, - dummy_class.problem, - dummy_p_facility, dummy_fac_r, dummy_cli_r, ) From bb4c21d95c6458a111cccbf96c3f94a1c662de75 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Thu, 22 Dec 2022 13:16:25 -0500 Subject: [PATCH 4/5] update assignment constraint signature --- spopt/locate/base.py | 19 ++++++------------- spopt/locate/coverage.py | 4 +--- spopt/locate/p_center.py | 4 +--- spopt/locate/p_median.py | 6 ++---- spopt/tests/test_locate.py | 10 +++++----- 5 files changed, 15 insertions(+), 28 deletions(-) diff --git a/spopt/locate/base.py b/spopt/locate/base.py index baf5d5e7..adcc0693 100644 --- a/spopt/locate/base.py +++ b/spopt/locate/base.py @@ -394,14 +394,14 @@ def add_backup_covering_constraint( if sum(ni[i]) >= 2: model += ( pulp.lpSum( - [int(ni[i][j]) * fac_vars[j] for j in range_facility] + [int(ni[i, j]) * fac_vars[j] for j in range_facility] ) >= 1 + 1 * cli_vars[i] ) else: model += ( pulp.lpSum( - [int(ni[i][j]) * fac_vars[j] for j in range_facility] + [int(ni[i, j]) * fac_vars[j] for j in range_facility] ) >= 1 + 0 * cli_vars[i] ) @@ -560,8 +560,6 @@ def add_client_demand_satisfaction_constraint( @staticmethod def add_maximal_coverage_constraint( obj: T_FacModel, - model: pulp.LpProblem, - ni: np.array, range_facility: range, range_client: range, ) -> None: @@ -575,11 +573,6 @@ def add_maximal_coverage_constraint( obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model : pulp.LpProblem - A ``pulp`` instance of an optimization model. - ni : numpy.array - A 2D array that defines candidate sites between facility - points within a distance to supply demand points. range_facility : range The range of facility points. range_client : range @@ -594,6 +587,8 @@ def add_maximal_coverage_constraint( if hasattr(obj, "fac_vars") and hasattr(obj, "cli_vars"): fac_vars = getattr(obj, "fac_vars") dem_vars = getattr(obj, "cli_vars") + model = getattr(obj, "problem") + ni = getattr(obj, "aij") for i in range_client: model += ( @@ -609,7 +604,6 @@ def add_maximal_coverage_constraint( @staticmethod def add_assignment_constraint( obj: T_FacModel, - model: pulp.LpProblem, range_facility: range, range_client: range, ) -> None: @@ -623,8 +617,6 @@ def add_assignment_constraint( obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model : pulp.LpProblem - A ``pulp`` instance of an optimization model. range_facility : range The range of facility points. range_client : range @@ -638,9 +630,10 @@ def add_assignment_constraint( """ if hasattr(obj, "cli_assgn_vars"): cli_assgn_vars = getattr(obj, "cli_assgn_vars") + model = getattr(obj, "problem") for i in range_client: - model += pulp.lpSum([cli_assgn_vars[i][j] for j in range_facility]) == 1 + model += pulp.lpSum([cli_assgn_vars[i, j] for j in range_facility]) == 1 else: raise AttributeError( "Before setting assignment constraints " diff --git a/spopt/locate/coverage.py b/spopt/locate/coverage.py index 6e06a19a..832fb51b 100644 --- a/spopt/locate/coverage.py +++ b/spopt/locate/coverage.py @@ -1113,9 +1113,7 @@ def from_cost_matrix( mclp, predefined_facilities_arr ) - FacilityModelBuilder.add_maximal_coverage_constraint( - mclp, mclp.problem, mclp.aij, r_fac, r_cli - ) + FacilityModelBuilder.add_maximal_coverage_constraint(mclp, r_fac, r_cli) FacilityModelBuilder.add_facility_constraint(mclp, p_facilities) diff --git a/spopt/locate/p_center.py b/spopt/locate/p_center.py index 58f16564..661394ca 100644 --- a/spopt/locate/p_center.py +++ b/spopt/locate/p_center.py @@ -206,9 +206,7 @@ def from_cost_matrix( p_center.__add_obj() FacilityModelBuilder.add_facility_constraint(p_center, p_facilities) - FacilityModelBuilder.add_assignment_constraint( - p_center, p_center.problem, r_fac, r_cli - ) + FacilityModelBuilder.add_assignment_constraint(p_center, r_fac, r_cli) FacilityModelBuilder.add_opening_constraint( p_center, p_center.problem, r_fac, r_cli ) diff --git a/spopt/locate/p_median.py b/spopt/locate/p_median.py index d076da4a..09ed2eae 100644 --- a/spopt/locate/p_median.py +++ b/spopt/locate/p_median.py @@ -115,7 +115,7 @@ def __add_obj(self, range_clients: range, range_facility: range) -> None: self.problem += ( pulp.lpSum( [ - self.aij[i][j] * cli_assgn_vars[i][j] + self.aij[i, j] * cli_assgn_vars[i, j] for i in range_clients for j in range_facility ] @@ -254,9 +254,7 @@ def from_cost_matrix( p_median.__add_obj(r_cli, r_fac) FacilityModelBuilder.add_facility_constraint(p_median, p_facilities) - FacilityModelBuilder.add_assignment_constraint( - p_median, p_median.problem, r_fac, r_cli - ) + FacilityModelBuilder.add_assignment_constraint(p_median, r_fac, r_cli) FacilityModelBuilder.add_opening_constraint( p_median, p_median.problem, r_fac, r_cli ) diff --git a/spopt/tests/test_locate.py b/spopt/tests/test_locate.py index d32a4f8f..574ba743 100644 --- a/spopt/tests/test_locate.py +++ b/spopt/tests/test_locate.py @@ -885,21 +885,21 @@ def test_attribute_error_add_maximal_coverage_constraint(self): with pytest.raises( AttributeError, match="Before setting maximal coverage constraints" ): - dummy_class = LSCP("dummy", pulp.LpProblem("name")) - dummy_matrix = numpy.array([]) + dummy_class = MCLP("dummy", pulp.LpProblem("name")) + dummy_class.aij = numpy.array([]) dummy_range = range(1) FacilityModelBuilder.add_maximal_coverage_constraint( - dummy_class, dummy_class.problem, dummy_matrix, dummy_range, dummy_range + dummy_class, dummy_range, dummy_range ) def test_attribute_error_add_assignment_constraint(self): with pytest.raises( AttributeError, match="Before setting assignment constraints" ): - dummy_class = LSCP("dummy", pulp.LpProblem("name")) + dummy_class = PMedian("dummy", pulp.LpProblem("name"), numpy.array([]), 1) dummy_range = range(1) FacilityModelBuilder.add_assignment_constraint( - dummy_class, dummy_class.problem, dummy_range, dummy_range + dummy_class, dummy_range, dummy_range ) def test_attribute_error_add_opening_constraint(self): From 4565f4ff29221e521d1ce532294f64b0a444f63b Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Thu, 22 Dec 2022 13:41:21 -0500 Subject: [PATCH 5/5] update opening, etc. constraint signature --- spopt/locate/base.py | 18 ++++++------------ spopt/locate/p_center.py | 6 ++---- spopt/locate/p_dispersion.py | 2 +- spopt/locate/p_median.py | 4 +--- spopt/tests/test_locate.py | 8 ++++---- spopt/tests/test_p_dispersion.py | 1 - 6 files changed, 14 insertions(+), 25 deletions(-) diff --git a/spopt/locate/base.py b/spopt/locate/base.py index adcc0693..b200518a 100644 --- a/spopt/locate/base.py +++ b/spopt/locate/base.py @@ -643,7 +643,6 @@ def add_assignment_constraint( @staticmethod def add_opening_constraint( obj: T_FacModel, - model: pulp.LpProblem, range_facility: range, range_client: range, ) -> None: @@ -657,8 +656,6 @@ def add_opening_constraint( obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model : pulp.LpProblem - A ``pulp`` instance of an optimization model. range_facility : range The range of facility points. range_client : range @@ -673,10 +670,11 @@ def add_opening_constraint( if hasattr(obj, "cli_assgn_vars"): cli_assgn_vars = getattr(obj, "cli_assgn_vars") fac_vars = getattr(obj, "fac_vars") + model = getattr(obj, "problem") for i in range_client: for j in range_facility: - model += fac_vars[j] - cli_assgn_vars[i][j] >= 0 + model += fac_vars[j] - cli_assgn_vars[i, j] >= 0 else: raise AttributeError( "Before setting opening constraints " @@ -686,7 +684,6 @@ def add_opening_constraint( @staticmethod def add_minimized_maximum_constraint( obj: T_FacModel, - model: pulp.LpProblem, cost_matrix: np.array, range_facility: range, range_client: range, @@ -701,8 +698,6 @@ def add_minimized_maximum_constraint( obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model : pulp.LpProblem - A ``pulp`` instance of an optimization model. cost_matrix : numpy.array A cost matrix in the form of a 2D array between origins and destinations. range_facility : range @@ -725,12 +720,13 @@ def add_minimized_maximum_constraint( if hasattr(obj, "cli_assgn_vars") and hasattr(obj, "weight_var"): cli_assgn_vars = getattr(obj, "cli_assgn_vars") weight_var = getattr(obj, "weight_var") + model = getattr(obj, "problem") for i in range_client: model += ( pulp.lpSum( [ - cli_assgn_vars[i][j] * cost_matrix[i][j] + cli_assgn_vars[i, j] * cost_matrix[i, j] for j in range_facility ] ) @@ -745,7 +741,6 @@ def add_minimized_maximum_constraint( @staticmethod def add_p_dispersion_interfacility_constraint( obj: T_FacModel, - model: pulp.LpProblem, cost_matrix: np.array, range_facility: range, ) -> None: @@ -759,8 +754,6 @@ def add_p_dispersion_interfacility_constraint( obj : T_FacModel A bounded type of the ``LocateSolver`` class. - model : pulp.LpProblem - A ``pulp`` instance of an optimization model. cost_matrix : numpy.array A cost matrix in the form of a 2D array between all facility points. range_facility : range @@ -774,13 +767,14 @@ def add_p_dispersion_interfacility_constraint( """ if hasattr(obj, "disperse_var") and hasattr(obj, "fac_vars"): M = cost_matrix.max() + model = getattr(obj, "problem") for i in range_facility: for j in range_facility: if j <= i: continue else: - dij = cost_matrix[i][j] + dij = cost_matrix[i, j] model += ( pulp.lpSum( [(dij + M * (2 - obj.fac_vars[i] - obj.fac_vars[j]))] diff --git a/spopt/locate/p_center.py b/spopt/locate/p_center.py index 661394ca..6b657c9c 100644 --- a/spopt/locate/p_center.py +++ b/spopt/locate/p_center.py @@ -207,11 +207,9 @@ def from_cost_matrix( FacilityModelBuilder.add_facility_constraint(p_center, p_facilities) FacilityModelBuilder.add_assignment_constraint(p_center, r_fac, r_cli) - FacilityModelBuilder.add_opening_constraint( - p_center, p_center.problem, r_fac, r_cli - ) + FacilityModelBuilder.add_opening_constraint(p_center, r_fac, r_cli) FacilityModelBuilder.add_minimized_maximum_constraint( - p_center, p_center.problem, cost_matrix, r_fac, r_cli + p_center, cost_matrix, r_fac, r_cli ) return p_center diff --git a/spopt/locate/p_dispersion.py b/spopt/locate/p_dispersion.py index 7f1d58c7..fc3c0c5d 100644 --- a/spopt/locate/p_dispersion.py +++ b/spopt/locate/p_dispersion.py @@ -182,7 +182,7 @@ def from_cost_matrix( ) FacilityModelBuilder.add_p_dispersion_interfacility_constraint( - p_dispersion, p_dispersion.problem, cost_matrix, r_fac + p_dispersion, cost_matrix, r_fac ) return p_dispersion diff --git a/spopt/locate/p_median.py b/spopt/locate/p_median.py index 09ed2eae..d8a30a5c 100644 --- a/spopt/locate/p_median.py +++ b/spopt/locate/p_median.py @@ -255,9 +255,7 @@ def from_cost_matrix( FacilityModelBuilder.add_facility_constraint(p_median, p_facilities) FacilityModelBuilder.add_assignment_constraint(p_median, r_fac, r_cli) - FacilityModelBuilder.add_opening_constraint( - p_median, p_median.problem, r_fac, r_cli - ) + FacilityModelBuilder.add_opening_constraint(p_median, r_fac, r_cli) return p_median diff --git a/spopt/tests/test_locate.py b/spopt/tests/test_locate.py index 574ba743..01ffe1b1 100644 --- a/spopt/tests/test_locate.py +++ b/spopt/tests/test_locate.py @@ -904,21 +904,21 @@ def test_attribute_error_add_assignment_constraint(self): def test_attribute_error_add_opening_constraint(self): with pytest.raises(AttributeError, match="Before setting opening constraints"): - dummy_class = LSCP("dummy", pulp.LpProblem("name")) + dummy_class = PMedian("dummy", pulp.LpProblem("name"), numpy.array([]), 1) dummy_range = range(1) FacilityModelBuilder.add_opening_constraint( - dummy_class, dummy_class.problem, dummy_range, dummy_range + dummy_class, dummy_range, dummy_range ) def test_attribute_error_add_minimized_maximum_constraint(self): with pytest.raises( AttributeError, match="Before setting minimized maximum constraints" ): - dummy_class = LSCP("dummy", pulp.LpProblem("name")) dummy_matrix = numpy.array([]) + dummy_class = PCenter("dummy", pulp.LpProblem("name"), dummy_matrix) dummy_range = range(1) FacilityModelBuilder.add_minimized_maximum_constraint( - dummy_class, dummy_class.problem, dummy_matrix, dummy_range, dummy_range + dummy_class, dummy_matrix, dummy_range, dummy_range ) def test_error_lscp_different_crs(self): diff --git a/spopt/tests/test_p_dispersion.py b/spopt/tests/test_p_dispersion.py index 04309391..22e31327 100644 --- a/spopt/tests/test_p_dispersion.py +++ b/spopt/tests/test_p_dispersion.py @@ -204,7 +204,6 @@ def test_attribute_error_add_p_dispersion_interfacility_constraint(self): dummy_class = PDispersion("dummy", pulp.LpProblem("name"), dummy_p_facility) FacilityModelBuilder.add_p_dispersion_interfacility_constraint( dummy_class, - dummy_class.problem, dummy_matrix, dummy_range, )