From c1ede58fbefd6567561a1051362b78c1107cacca Mon Sep 17 00:00:00 2001 From: Alinson S Xavier Date: Fri, 31 Jan 2020 10:30:45 -0600 Subject: [PATCH] Adjust knapsack challenge; introduce round option --- docs/problems.md | 2 ++ miplearn/problems/knapsack.py | 40 ++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/docs/problems.md b/docs/problems.md index 5fa04f6..678cae0 100644 --- a/docs/problems.md +++ b/docs/problems.md @@ -93,6 +93,8 @@ If `fix_w=True` is provided, then $w_{ij}$ are kept the same in all generated in If a probability distribution `w_jitter` is provided, then item weights will be set to $w_{ij} + \gamma_{ij}$ where $\gamma_{ij}$ is sampled from `w_jitter`. When combined with `fix_w=True`, this argument may be used to generate instances where the weight of each item is roughly the same, but not exactly identical, across all instances. The prices of the items and the capacities of the knapsacks will be calculated as above, but using these perturbed weights instead. +By default, all generated prices, weights and capacities are rounded to the nearest number. If `round=False` is provided, this rounding will be disabled. + !!! note "References" * Freville, Arnaud, and Gérard Plateau. *An efficient preprocessing procedure for the multidimensional 0–1 knapsack problem.* Discrete applied mathematics 49.1-3 (1994): 189-212. * Fréville, Arnaud. *The multidimensional 0–1 knapsack problem: An overview.* European Journal of Operational Research 155.1 (2004): 1-21. \ No newline at end of file diff --git a/miplearn/problems/knapsack.py b/miplearn/problems/knapsack.py index a451c60..366d19f 100644 --- a/miplearn/problems/knapsack.py +++ b/miplearn/problems/knapsack.py @@ -11,19 +11,32 @@ from scipy.stats.distributions import rv_frozen class ChallengeA: - def __init__(self, seed=0): + """ + - 250 variables, 10 constraints, fixed weights + - w ~ U(100, 900), jitter ~ U(-100, 100) + - K = 500, u ~ U(0., 1.) + - alpha = 0.25 + """ + def __init__(self, + seed=42, + n_training_instances=300, + n_test_instances=50): + np.random.seed(seed) - self.gen = MultiKnapsackGenerator(n=randint(low=50, high=51), - m=randint(low=3, high=4), - w=uniform(loc=0.0, scale=200.0), - K=uniform(loc=1.0, scale=0.0), - u=uniform(loc=1.0, scale=0.0), + self.gen = MultiKnapsackGenerator(n=randint(low=250, high=251), + m=randint(low=10, high=11), + w=uniform(loc=100.0, scale=900.0), + K=uniform(loc=500.0, scale=0.0), + u=uniform(loc=0.0, scale=1.0), alpha=uniform(loc=0.25, scale=0.0), fix_w=True, - w_jitter=uniform(loc=-10.0, scale=20.0), + w_jitter=uniform(loc=-100.0, scale=200.0), ) - self.training_instances = self.gen.generate(300) - self.test_instances = self.gen.generate(50) + np.random.seed(seed + 1) + self.training_instances = self.gen.generate(n_training_instances) + + np.random.seed(seed + 2) + self.test_instances = self.gen.generate(n_test_instances) class MultiKnapsackInstance(Instance): @@ -90,7 +103,7 @@ class MultiKnapsackGenerator: alpha=uniform(loc=0.25, scale=0.0), fix_w=False, w_jitter=randint(low=0, high=1), - seed=None, + round=True, ): """Initialize the problem generator. @@ -143,6 +156,8 @@ class MultiKnapsackGenerator: If true, weights are kept the same (minus the noise from w_jitter) in all instances w_jitter: rv_continuous Probability distribution for random noise added to the weights + round: boolean + If true, all prices, weights and capacities are rounded to the nearest integer """ assert isinstance(n, rv_frozen), "n should be a SciPy probability distribution" assert isinstance(m, rv_frozen), "m should be a SciPy probability distribution" @@ -161,6 +176,7 @@ class MultiKnapsackGenerator: self.u = u self.alpha = alpha self.w_jitter = w_jitter + self.round = round if fix_w: self.fix_n = self.n.rvs() @@ -187,6 +203,10 @@ class MultiKnapsackGenerator: alpha = self.alpha.rvs(m) p = np.array([w[:,j].sum() / m + K * u[j] for j in range(n)]) b = np.array([w[i,:].sum() * alpha[i] for i in range(m)]) + if self.round: + p = p.round() + b = b.round() + w = w.round() return MultiKnapsackInstance(p, b, w) return [_sample() for _ in range(n_samples)]