diff --git a/miplearn/problems/stab.py b/miplearn/problems/stab.py new file mode 100644 index 0000000..24d9c76 --- /dev/null +++ b/miplearn/problems/stab.py @@ -0,0 +1,50 @@ +# MIPLearn: A Machine-Learning Framework for Mixed-Integer Optimization +# Copyright (C) 2019-2020 Argonne National Laboratory. All rights reserved. +# Written by Alinson S. Xavier + +import numpy as np +import pyomo.environ as pe +import networkx as nx +from miplearn import Instance +import random + + +class MaxStableSetGenerator: + def __init__(self, graph, base_weights, perturbation_scale=1.0): + self.graph = graph + self.base_weights = base_weights + self.perturbation_scale = perturbation_scale + + def generate(self): + perturbation = np.random.rand(self.graph.number_of_nodes()) * self.perturbation_scale + weights = self.base_weights + perturbation + return MaxStableSetInstance(self.graph, weights) + + +class MaxStableSetInstance(Instance): + def __init__(self, graph, weights): + self.graph = graph + self.weights = weights + self.model = None + + def to_model(self): + nodes = list(self.graph.nodes) + edges = list(self.graph.edges) + self.model = model = pe.ConcreteModel() + model.x = pe.Var(nodes, domain=pe.Binary) + model.OBJ = pe.Objective(rule=lambda m : sum(m.x[v] * self.weights[v] for v in nodes), + sense=pe.maximize) + model.edge_eqs = pe.ConstraintList() + for edge in edges: + model.edge_eqs.add(model.x[edge[0]] + model.x[edge[1]] <= 1) + + return model + + def get_instance_features(self): + return np.array(self.weights) + + def get_variable_features(self, var, index): + return np.ones(0) + + def get_variable_category(self, var, index): + return index diff --git a/miplearn/tests/test_stab.py b/miplearn/tests/test_stab.py new file mode 100644 index 0000000..e306b80 --- /dev/null +++ b/miplearn/tests/test_stab.py @@ -0,0 +1,31 @@ +# MIPLearn: A Machine-Learning Framework for Mixed-Integer Optimization +# Copyright (C) 2019-2020 Argonne National Laboratory. All rights reserved. +# Written by Alinson S. Xavier + +from miplearn import LearningSolver +from miplearn.problems.stab import MaxStableSetInstance, MaxStableSetGenerator +import networkx as nx +import numpy as np + + +def test_stab(): + graph = nx.cycle_graph(5) + weights = [1.0, 2.0, 3.0, 4.0, 5.0] + instance = MaxStableSetInstance(graph, weights) + solver = LearningSolver() + solver.solve(instance) + assert instance.model.OBJ() == 8.0 + + +def test_stab_generator(): + graph = nx.cycle_graph(5) + base_weights = [1.0, 2.0, 3.0, 4.0, 5.0] + generator = MaxStableSetGenerator(graph=graph, + base_weights=base_weights, + perturbation_scale=1.0) + instances = [generator.generate() for _ in range(100_000)] + weights = np.array([instance.weights for instance in instances]) + weights_avg = np.round(np.average(weights, axis=0), 2) + weights_std = np.round(np.std(weights, axis=0), 2) + assert list(weights_avg) == [1.50, 2.50, 3.50, 4.50, 5.50] + assert list(weights_std) == [0.29] * 5 diff --git a/requirements.txt b/requirements.txt index 048b09c..7a573c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ pyomo numpy pytest -sklearn \ No newline at end of file +sklearn +networkx \ No newline at end of file diff --git a/setup.py b/setup.py index a64f10f..9dc10a2 100644 --- a/setup.py +++ b/setup.py @@ -7,5 +7,5 @@ setup( author='Alinson S. Xavier', author_email='axavier@anl.gov', packages=['miplearn'], - install_requires=['pyomo', 'numpy', 'sklearn'], + install_requires=['pyomo', 'numpy', 'sklearn', 'networkx'], ) \ No newline at end of file