Skip to content

Commit 21699cb

Browse files
✨ feat(integerWeightKnapsackUnbounded): First draft.
1 parent c405126 commit 21699cb

File tree

3 files changed

+94
-1
lines changed

3 files changed

+94
-1
lines changed

src/index.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import integerValuesKnapsack from './integerValuesKnapsack';
22
import integerWeightsKnapsack from './integerWeightsKnapsack';
3+
import integerWeightsKnapsackUnbounded from './integerWeightsKnapsackUnbounded';
34
import knapsackApprox from './knapsackApprox';
45

56
/* eslint import/no-anonymous-default-export: [2, {"allowObject": true}] */
67
export default {
78
integerValuesKnapsack,
89
integerWeightsKnapsack,
10+
integerWeightsKnapsackUnbounded,
911
knapsackApprox,
1012
};
1113

12-
export {integerValuesKnapsack, integerWeightsKnapsack, knapsackApprox};
14+
export {
15+
integerValuesKnapsack,
16+
integerWeightsKnapsack,
17+
integerWeightsKnapsackUnbounded,
18+
knapsackApprox,
19+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import assert from 'assert';
2+
3+
const integerWeightsKnapsackUnbounded = (
4+
v,
5+
w,
6+
n,
7+
W,
8+
m = new v.constructor(W + 1).fill(0),
9+
) => {
10+
assert(v.length === n);
11+
assert(w.length === n);
12+
assert(Number.isInteger(W) && W >= 0);
13+
assert(m.length >= W + 1);
14+
for (let j = 1; j <= W; ++j) {
15+
let temporary = m[j];
16+
for (let i = 0; i < n; ++i) {
17+
const wi = w[i];
18+
const vi = v[i];
19+
assert(Number.isInteger(wi) && wi >= 0 && wi <= W);
20+
const k = j - wi;
21+
// TODO sort by weight to avoid branching
22+
// from larger to smaller so that m is scanned
23+
// from left to right
24+
if (k >= 0) temporary = Math.max(temporary, m[k] + vi);
25+
}
26+
27+
m[j] = temporary;
28+
}
29+
30+
return m[W];
31+
};
32+
33+
export default integerWeightsKnapsackUnbounded;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import test from 'ava';
2+
3+
import {all, map} from '@aureooms/js-itertools';
4+
5+
import {integerWeightsKnapsackUnbounded} from '../../src';
6+
7+
const macro = (t, solve, _name, v, w, n, W, opt, approx) => {
8+
t.is(n, v.length);
9+
t.is(n, w.length);
10+
const result = solve(v, w, n, W);
11+
if (approx === undefined) {
12+
t.is(opt, result);
13+
} else {
14+
t.true(result >= approx * opt);
15+
}
16+
};
17+
18+
macro.title = (title, solve, name, v, w, n, W, opt, approx) =>
19+
title
20+
? `${title} (${name || solve.name})`
21+
: approx === undefined
22+
? `${name || solve.name}(${JSON.stringify(v)}, ${JSON.stringify(
23+
w,
24+
)}, ${n}, ${W}) = ${opt}`
25+
: `${name || solve.name}(${JSON.stringify(v)}, ${JSON.stringify(
26+
w,
27+
)}, ${n}, ${W}) >= ${approx} * ${opt}`;
28+
29+
const solvers = [
30+
{
31+
solve: integerWeightsKnapsackUnbounded,
32+
hypothesis: (_, w) => all(map((x) => Number.isInteger(x), w)),
33+
},
34+
];
35+
36+
const instances = [
37+
{
38+
title: 'wikipedia illustration',
39+
v: [4, 2, 2, 1, 10],
40+
w: [12, 2, 1, 1, 4],
41+
n: 5,
42+
W: 15,
43+
opt: 36,
44+
},
45+
];
46+
47+
for (const {title, v, w, n, W, opt} of instances) {
48+
for (const {solve, name, hypothesis, approx} of solvers) {
49+
if (!hypothesis || hypothesis(v, w, n, W)) {
50+
test(title, macro, solve, name, v, w, n, W, opt, approx);
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)