Skip to content

Commit

Permalink
🚧 progress: First draft.
Browse files Browse the repository at this point in the history
  • Loading branch information
make-github-pseudonymous-again committed May 6, 2021
1 parent 9cbd9ff commit cf2641d
Show file tree
Hide file tree
Showing 8 changed files with 10,303 additions and 8 deletions.
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,22 @@
"release": "np --message ':hatching_chick: release: Bumping to v%s.'",
"test": "ava"
},
"dependencies": {},
"dependencies": {
"@iterable-iterator/filter": "^0.1.2",
"@iterable-iterator/iter": "^0.0.2",
"@iterable-iterator/list": "^0.0.2",
"@iterable-iterator/map": "^0.1.0",
"@iterable-iterator/next": "^1.0.1",
"@iterable-iterator/reversed": "^0.0.2"
},
"devDependencies": {
"@babel/core": "7.14.0",
"@babel/preset-env": "7.14.0",
"@babel/register": "7.13.16",
"@commitlint/cli": "12.1.1",
"@iterable-iterator/count": "^0.0.1",
"@iterable-iterator/range": "^1.0.0",
"@iterable-iterator/slice": "^0.0.1",
"@js-library/commitlint-config": "0.0.4",
"ava": "3.15.0",
"babel-plugin-transform-remove-console": "6.9.4",
Expand Down
35 changes: 35 additions & 0 deletions src/_bitsets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export default function* _bitsets() {
const bitset = [];
while (true) {
yield new Progress(VALUE, bitset);
yield* _increment(bitset);
}
}

function* _increment(bitset) {
const n = bitset.length;
for (let i = 0; i < n; ++i) {
if (bitset[i] === 0) {
bitset[i] = 1;
yield new Progress(ADD, i);
return;
}

bitset[i] = 0;
yield new Progress(REMOVE, i);
}

bitset.push(1);
yield new Progress(ADD, n);
}

class Progress {
constructor(type, value) {
this.type = type;
this.value = value;
}
}

export const VALUE = 0;
export const ADD = 1;
export const REMOVE = 2;
41 changes: 41 additions & 0 deletions src/_powerset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import assert from 'assert';
import _bitsets, {ADD, REMOVE, VALUE} from './_bitsets.js';

import {iter} from '@iterable-iterator/iter';
import {next, StopIteration} from '@iterable-iterator/next';
import {filter} from '@iterable-iterator/filter';

export default function* _powerset(set) {
const source = iter(set);
const buffer = [];
const stack = [];
yield stack;
for (const progress of filter(({type}) => type !== VALUE, _bitsets())) {
switch (progress.type) {
case ADD:
if (progress.value === buffer.length) {
try {
buffer.push(next(source));
} catch (error) {
if (error instanceof StopIteration) {
assert(stack.length === 0);
return;
}

throw error;
}
}

assert(progress.value < buffer.length);
stack.push(buffer[progress.value]);
yield stack;
break;
default:
assert(progress.type === REMOVE);
assert(stack.length > 0);
assert(stack[stack.length - 1] === buffer[progress.value]);
stack.pop();
break;
}
}
}
5 changes: 3 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
const answer = 42;
export default answer;
export {default as _bitsets} from './_bitsets.js';
export {default as _powerset} from './_powerset.js';
export {default as powerset} from './powerset.js';
8 changes: 8 additions & 0 deletions src/powerset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {map} from '@iterable-iterator/map';
import {list} from '@iterable-iterator/list';
import {reversed} from '@iterable-iterator/reversed';
import _powerset from './_powerset.js';

const powerset = (set) =>
map((subset) => list(reversed(subset)), _powerset(set));
export default powerset;
5 changes: 0 additions & 5 deletions test/src/api.js

This file was deleted.

52 changes: 52 additions & 0 deletions test/src/powerset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import test from 'ava';

import {powerset} from '../../src/index.js';
import {list} from '@iterable-iterator/list';
import {range} from '@iterable-iterator/range';
import {count} from '@iterable-iterator/count';
import {take} from '@iterable-iterator/slice';

const repr = (x) => (Array.isArray(x) ? JSON.stringify(x) : x.toString());

const whole = (t, set, expected) => {
const result = list(powerset(set));
t.deepEqual(result, expected);
};

whole.title = (title, set, expected) =>
title ?? `powerset(${repr(set)}) is ${repr(expected)}`;

test(whole, range(0), [[]]);

test(whole, range(1), [[], [0]]);

test(whole, range(2), [[], [0], [1], [0, 1]]);

test(whole, range(3), [[], [0], [1], [0, 1], [2], [0, 2], [1, 2], [0, 1, 2]]);

const startsWith = (t, set, expected) => {
const result = list(take(powerset(set), expected.length));
t.deepEqual(result, expected);
};

startsWith.title = (title, set, expected) =>
title ?? `powerset(${repr(set)}) starts with ${repr(expected)}`;

test('All subsets of NN!', startsWith, count(), [
[],
[0],
[1],
[0, 1],
[2],
[0, 2],
[1, 2],
[0, 1, 2],
[3],
[0, 3],
[1, 3],
[0, 1, 3],
[2, 3],
[0, 2, 3],
[1, 2, 3],
[0, 1, 2, 3],
]);
Loading

0 comments on commit cf2641d

Please sign in to comment.