Skip to content

Commit

Permalink
✨ feat(knapsackGreedy): First draft.
Browse files Browse the repository at this point in the history
Fixes #3.
  • Loading branch information
make-github-pseudonymous-again committed Oct 16, 2020
1 parent d860624 commit 6f2e9b3
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import integerValuesKnapsackUnbounded from './integerValuesKnapsackUnbounded';
import integerWeightsKnapsack from './integerWeightsKnapsack';
import integerWeightsKnapsackUnbounded from './integerWeightsKnapsackUnbounded';
import knapsackApprox from './knapsackApprox';
import knapsackGreedy from './knapsackGreedy';
import knapsackUnboundedGreedy from './knapsackUnboundedGreedy';
import orderedByDecreasingUtility from './orderedByDecreasingUtility';

Expand All @@ -15,6 +16,7 @@ export default {
integerWeightsKnapsack,
integerWeightsKnapsackUnbounded,
knapsackApprox,
knapsackGreedy,
knapsackUnboundedGreedy,
orderedByDecreasingUtility,
};
Expand All @@ -26,6 +28,7 @@ export {
integerWeightsKnapsack,
integerWeightsKnapsackUnbounded,
knapsackApprox,
knapsackGreedy,
knapsackUnboundedGreedy,
orderedByDecreasingUtility,
};
52 changes: 52 additions & 0 deletions src/knapsackGreedy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import assert from 'assert';
import {map, range, sorted, filter} from '@aureooms/js-itertools';

import Item from './Item';
import orderedByDecreasingUtility from './orderedByDecreasingUtility';

/**
* 1/2-approximation to the 0-1 knapsack problem.
* Runs in O(n log n) time.
*
* Let OPT' be the value of the LP relaxation.
* Let v_i be the values of the items ordered by utility.
* Let k be the largest k such that sum(v[:k]) <= W.
* Let t = (W-sum(w[:k])) / w_{k+1},
* we have t < 1 and OPT' = sum(v[:k]) + t * v_{k+1}.
* Hence sum(v[:k+1]) > OPT' >= OPT.
* By partition one of { sum(v[:k]) , v_{k+1} } is at least OPT / 2.
* Assuming w_i <= W for all i in [N] each of these is feasible.
*
* @param {Array} v Values.
* @param {Array} w Weights.
* @param {Number} n Size of the problem.
* @param {Number} W Size of the knapsack.
*/
const knapsackGreedy = (v, w, n, W) => {
assert(v.length === n);
assert(w.length === n);
assert(W >= 0);

const items = sorted(
orderedByDecreasingUtility,
filter(
(item) => item.w <= W,
map((i) => new Item(w[i], v[i]), range(n)),
),
);
return subroutine(W, items);
};

const subroutine = (W, items) => {
let value = 0;
let capacity = W;
for (const {v, w} of items) {
if (capacity < w) return Math.max(v, value);
capacity -= w;
value += v;
}

return value;
};

export default knapsackGreedy;
5 changes: 5 additions & 0 deletions test/src/0-1-knapsack-problem.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {all, map} from '@aureooms/js-itertools';
import {
integerValuesKnapsack,
integerWeightsKnapsack,
knapsackGreedy,
knapsackApprox,
} from '../../src';

Expand Down Expand Up @@ -52,6 +53,10 @@ const solvers = [
solve: integerWeightsKnapsack,
hypothesis: (_, w) => all(map((x) => Number.isInteger(x), w)),
},
{
solve: knapsackGreedy,
approx: 1 / 2,
},
approx(1 / 2),
approx(2 / 3),
approx(3 / 4),
Expand Down

0 comments on commit 6f2e9b3

Please sign in to comment.