mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 09:28:51 -06:00
DropRedundant: Update for new classifier interface
This commit is contained in:
@@ -45,6 +45,10 @@ class DropRedundantInequalitiesStep(Component):
|
|||||||
self.violation_tolerance = violation_tolerance
|
self.violation_tolerance = violation_tolerance
|
||||||
self.max_iterations = max_iterations
|
self.max_iterations = max_iterations
|
||||||
self.current_iteration = 0
|
self.current_iteration = 0
|
||||||
|
self.total_dropped = 0
|
||||||
|
self.total_restored = 0
|
||||||
|
self.total_kept = 0
|
||||||
|
self.total_iterations = 0
|
||||||
|
|
||||||
def before_solve(self, solver, instance, _):
|
def before_solve(self, solver, instance, _):
|
||||||
self.current_iteration = 0
|
self.current_iteration = 0
|
||||||
@@ -62,7 +66,7 @@ class DropRedundantInequalitiesStep(Component):
|
|||||||
self.total_iterations = 0
|
self.total_iterations = 0
|
||||||
for category in y.keys():
|
for category in y.keys():
|
||||||
for i in range(len(y[category])):
|
for i in range(len(y[category])):
|
||||||
if y[category][i][0] == 1:
|
if y[category][i][1] == 1:
|
||||||
cid = constraints[category][i]
|
cid = constraints[category][i]
|
||||||
c = LazyConstraint(
|
c = LazyConstraint(
|
||||||
cid=cid,
|
cid=cid,
|
||||||
@@ -101,7 +105,7 @@ class DropRedundantInequalitiesStep(Component):
|
|||||||
for category in tqdm(x.keys(), desc="Fit (rlx:drop_ineq)"):
|
for category in tqdm(x.keys(), desc="Fit (rlx:drop_ineq)"):
|
||||||
if category not in self.classifiers:
|
if category not in self.classifiers:
|
||||||
self.classifiers[category] = deepcopy(self.classifier_prototype)
|
self.classifiers[category] = deepcopy(self.classifier_prototype)
|
||||||
self.classifiers[category].fit(x[category], y[category])
|
self.classifiers[category].fit(x[category], np.array(y[category]))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _x_test(instance, constraint_ids):
|
def _x_test(instance, constraint_ids):
|
||||||
@@ -160,9 +164,9 @@ class DropRedundantInequalitiesStep(Component):
|
|||||||
if category not in y:
|
if category not in y:
|
||||||
y[category] = []
|
y[category] = []
|
||||||
if slack > self.slack_tolerance:
|
if slack > self.slack_tolerance:
|
||||||
y[category] += [[1]]
|
y[category] += [[False, True]]
|
||||||
else:
|
else:
|
||||||
y[category] += [[0]]
|
y[category] += [[True, False]]
|
||||||
return y
|
return y
|
||||||
|
|
||||||
def predict(self, x):
|
def predict(self, x):
|
||||||
@@ -175,9 +179,9 @@ class DropRedundantInequalitiesStep(Component):
|
|||||||
proba = self.classifiers[category].predict_proba(x_cat)
|
proba = self.classifiers[category].predict_proba(x_cat)
|
||||||
for i in range(len(proba)):
|
for i in range(len(proba)):
|
||||||
if proba[i][1] >= self.threshold:
|
if proba[i][1] >= self.threshold:
|
||||||
y[category] += [[1]]
|
y[category] += [[False, True]]
|
||||||
else:
|
else:
|
||||||
y[category] += [[0]]
|
y[category] += [[True, False]]
|
||||||
return y
|
return y
|
||||||
|
|
||||||
def evaluate(self, instance):
|
def evaluate(self, instance):
|
||||||
@@ -187,13 +191,13 @@ class DropRedundantInequalitiesStep(Component):
|
|||||||
tp, tn, fp, fn = 0, 0, 0, 0
|
tp, tn, fp, fn = 0, 0, 0, 0
|
||||||
for category in y_true.keys():
|
for category in y_true.keys():
|
||||||
for i in range(len(y_true[category])):
|
for i in range(len(y_true[category])):
|
||||||
if y_pred[category][i][0] == 1:
|
if y_pred[category][i][1] == 1:
|
||||||
if y_true[category][i][0] == 1:
|
if y_true[category][i][1] == 1:
|
||||||
tp += 1
|
tp += 1
|
||||||
else:
|
else:
|
||||||
fp += 1
|
fp += 1
|
||||||
else:
|
else:
|
||||||
if y_true[category][i][0] == 1:
|
if y_true[category][i][1] == 1:
|
||||||
fn += 1
|
fn += 1
|
||||||
else:
|
else:
|
||||||
tn += 1
|
tn += 1
|
||||||
|
|||||||
@@ -6,11 +6,13 @@ from unittest.mock import Mock, call
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
from miplearn import RelaxIntegralityStep, BasePyomoSolver
|
||||||
from miplearn.classifiers import Classifier
|
from miplearn.classifiers import Classifier
|
||||||
from miplearn.components.steps.drop_redundant import DropRedundantInequalitiesStep
|
from miplearn.components.steps.drop_redundant import DropRedundantInequalitiesStep
|
||||||
from miplearn.instance import Instance
|
from miplearn.instance import Instance
|
||||||
from miplearn.solvers.internal import InternalSolver
|
from miplearn.solvers.internal import InternalSolver
|
||||||
from miplearn.solvers.learning import LearningSolver
|
from miplearn.solvers.learning import LearningSolver
|
||||||
|
from tests.solvers import _get_knapsack_instance
|
||||||
|
|
||||||
|
|
||||||
def _setup():
|
def _setup():
|
||||||
@@ -268,8 +270,20 @@ def test_x_y_fit_predict_evaluate():
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
expected_y = {
|
expected_y = {
|
||||||
"type-a": np.array([[0], [0], [1]]),
|
"type-a": np.array(
|
||||||
"type-b": np.array([[1], [0], [0]]),
|
[
|
||||||
|
[True, False],
|
||||||
|
[True, False],
|
||||||
|
[False, True],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
"type-b": np.array(
|
||||||
|
[
|
||||||
|
[False, True],
|
||||||
|
[True, False],
|
||||||
|
[True, False],
|
||||||
|
]
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Should build X and Y matrices correctly
|
# Should build X and Y matrices correctly
|
||||||
@@ -287,7 +301,15 @@ def test_x_y_fit_predict_evaluate():
|
|||||||
np.testing.assert_array_equal(actual_x, expected_x[category])
|
np.testing.assert_array_equal(actual_x, expected_x[category])
|
||||||
np.testing.assert_array_equal(actual_y, expected_y[category])
|
np.testing.assert_array_equal(actual_y, expected_y[category])
|
||||||
|
|
||||||
assert component.predict(expected_x) == {"type-a": [[1]], "type-b": [[0], [1]]}
|
assert component.predict(expected_x) == {
|
||||||
|
"type-a": [
|
||||||
|
[False, True],
|
||||||
|
],
|
||||||
|
"type-b": [
|
||||||
|
[True, False],
|
||||||
|
[False, True],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
ev = component.evaluate(instances[1])
|
ev = component.evaluate(instances[1])
|
||||||
assert ev["True positive"] == 1
|
assert ev["True positive"] == 1
|
||||||
@@ -350,8 +372,20 @@ def test_x_multiple_solves():
|
|||||||
}
|
}
|
||||||
|
|
||||||
expected_y = {
|
expected_y = {
|
||||||
"type-a": np.array([[1], [0], [0], [1]]),
|
"type-a": np.array(
|
||||||
"type-b": np.array([[1], [0]]),
|
[
|
||||||
|
[False, True],
|
||||||
|
[True, False],
|
||||||
|
[True, False],
|
||||||
|
[False, True],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
"type-b": np.array(
|
||||||
|
[
|
||||||
|
[False, True],
|
||||||
|
[True, False],
|
||||||
|
]
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Should build X and Y matrices correctly
|
# Should build X and Y matrices correctly
|
||||||
@@ -362,3 +396,17 @@ def test_x_multiple_solves():
|
|||||||
for category in ["type-a", "type-b"]:
|
for category in ["type-a", "type-b"]:
|
||||||
np.testing.assert_array_equal(actual_x[category], expected_x[category])
|
np.testing.assert_array_equal(actual_x[category], expected_x[category])
|
||||||
np.testing.assert_array_equal(actual_y[category], expected_y[category])
|
np.testing.assert_array_equal(actual_y[category], expected_y[category])
|
||||||
|
|
||||||
|
|
||||||
|
def test_usage():
|
||||||
|
solver = LearningSolver(
|
||||||
|
components=[
|
||||||
|
RelaxIntegralityStep(),
|
||||||
|
DropRedundantInequalitiesStep(),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
instance = _get_knapsack_instance(BasePyomoSolver)
|
||||||
|
# The following should not crash
|
||||||
|
solver.solve(instance)
|
||||||
|
solver.fit([instance])
|
||||||
|
solver.solve(instance)
|
||||||
|
|||||||
Reference in New Issue
Block a user