Skip to content
Snippets Groups Projects
Commit d4e1950c authored by David Sehnal's avatar David Sehnal
Browse files

multiset

parent 8ff4ae7a
No related branches found
No related tags found
No related merge requests found
......@@ -90,10 +90,12 @@ namespace MultiSet {
return subtractEE(a, b);
}
// TODO: union
export function union(a: MultiSet, b: MultiSet): MultiSet {
return findUnion([a, b]);
}
export function union(sets: ArrayLike<MultiSet>): MultiSet {
return 0 as any;
export function unionMany(sets: ArrayLike<MultiSet>): MultiSet {
return findUnion(sets);
}
class ElementsIterator implements Iterator<IntPair> {
......@@ -145,7 +147,6 @@ namespace MultiSet {
const pair = IntPair.zero();
function isArrayLike(x: any): x is ArrayLike<number> {
return x && (typeof x.length === 'number' && (x instanceof Array || !!x.buffer));
}
......@@ -198,6 +199,28 @@ function _createObjectOrdered(keys: OrderedSet, data: { [id: number]: OrderedSet
return ret;
}
function getUniqueElements(xs: number[]) {
let count = 1;
for (let i = 1, _i = xs.length; i < _i; i++) {
if (xs[i - 1] !== xs[i]) count++;
}
const ret = new (xs as any).constructor(count);
ret[0] = xs[0];
let offset = 1;
for (let i = 1, _i = xs.length; i < _i; i++) {
if (xs[i - 1] !== xs[i]) ret[offset++] = xs[i];
}
return ret;
}
function normalizeArray(xs: number[]) {
sortArray(xs);
for (let i = 1, _i = xs.length; i < _i; i++) {
if (xs[i - 1] === xs[i]) return getUniqueElements(xs);
}
return xs;
}
function ofPackedPairs(xs: ArrayLike<number>): MultiSet {
if (xs.length === 0) return MultiSet.Empty;
const sets: { [key: number]: number[] } = Object.create(null);
......@@ -213,7 +236,7 @@ function ofPackedPairs(xs: ArrayLike<number>): MultiSet {
for (const _k of Object.keys(sets)) {
const k = +_k;
keys[keys.length] = k;
ret[k] = OrderedSet.ofSortedArray(sortArray(sets[k]));
ret[k] = OrderedSet.ofSortedArray(normalizeArray(sets[k]));
}
return ofObject1(keys, ret);
}
......@@ -339,4 +362,62 @@ function subtractEE(a: MultiSetElements, b: MultiSetElements) {
return ofObjectOrdered(OrderedSet.ofSortedArray(keys), ret);
}
function findUnion(sets: ArrayLike<MultiSet>) {
if (!sets.length) return MultiSet.Empty;
if (sets.length === 1) return sets[0];
if (sets.length === 2 && sets[0] === sets[1]) return sets[0];
const eCount = { count: 0 };
const ns = unionN(sets, eCount);
if (!eCount.count) return ns;
const ret = Object.create(null);
for (let i = 0, _i = sets.length; i < _i; i++) {
const s = sets[i];
if (typeof s !== 'number') unionInto(ret, s);
}
if (MultiSet.size(ns) > 0) {
if (typeof ns === 'number') unionIntoN(ret, ns);
else unionInto(ret, ns);
}
return ofObject(ret);
}
function unionN(sets: ArrayLike<MultiSet>, eCount: { count: number }) {
let countN = 0, countE = 0;
for (let i = 0, _i = sets.length; i < _i; i++) {
if (typeof sets[i] === 'number') countN++;
else countE++;
}
eCount.count = countE;
if (!countN) return MultiSet.Empty;
if (countN === sets.length) return ofPackedPairs(sets as ArrayLike<number>);
const packed = new Float64Array(countN);
let offset = 0;
for (let i = 0, _i = sets.length; i < _i; i++) {
const s = sets[i];
if (typeof s === 'number') packed[offset++] = s;
}
return ofPackedPairs(packed);
}
function unionInto(data: { [key: number]: OrderedSet }, a: MultiSetElements) {
const keys = a.keys;
for (let i = 0, _i = keys.size; i < _i; i++) {
const k = keys.elementAt(i);
const set = data[k];
if (set) data[k] = OrderedSet.union(set, a[k]);
else data[k] = a[k];
}
}
function unionIntoN(data: { [key: number]: OrderedSet }, a: number) {
IntPair.unpack(a, pair);
const set = data[pair.fst];
if (set) {
data[pair.fst] = OrderedSet.union(set, OrderedSet.ofSingleton(pair.snd));
} else {
data[pair.fst] = OrderedSet.ofSingleton(pair.snd);
}
}
export default MultiSet
\ No newline at end of file
......@@ -404,4 +404,19 @@ describe('multiset', () => {
expect(setToPairs(MultiSet.subtract(c, a))).toEqual([]);
expect(setToPairs(MultiSet.subtract(d, a))).toEqual([p(2, 3)]);
});
it('union', () => {
const a = MultiSet.create([r(1, 3), r(0, 1)]);
const a1 = MultiSet.create([r(1, 3), r(0, 1)]);
const b = MultiSet.create([r(10, 3), r(0, 1)]);
const c = MultiSet.create([r(1, 3)]);
const d = MultiSet.create([r(2, 3)]);
expect(MultiSet.unionMany([a])).toBe(a);
expect(MultiSet.union(a, a)).toBe(a);
expect(setToPairs(MultiSet.union(a, a))).toEqual([p(0, 1), p(1, 3)]);
expect(setToPairs(MultiSet.union(a, a1))).toEqual([p(0, 1), p(1, 3)]);
expect(setToPairs(MultiSet.union(a, b))).toEqual([p(0, 1), p(1, 3), p(10, 3)]);
expect(setToPairs(MultiSet.union(c, d))).toEqual([p(1, 3), p(2, 3)]);
expect(setToPairs(MultiSet.unionMany([a, b, c, d]))).toEqual([p(0, 1), p(1, 3), p(2, 3), p(10, 3)]);
});
});
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment