Public
Edited
Jan 19, 2024
Importers
Insert cell
Insert cell
Insert cell
function getConjugacyClasses(arity) {
let seen = new BitSet(2 ** (2 ** arity));
let classes = [];
for (let code = 0; code < 2 ** (2 ** arity); code++) {
if (seen.has(code)) {
continue;
}
let cls = new Set([code]);
for (let invMap of _.range(2 ** arity)) {
let fn = withInvMap(arity, code, invMap);
for (let invFn of [fn, inverseFn(arity, fn)]) {
for (let perm of permutations(_.range(arity))) {
let permedFn = getPermed(arity, invFn, perm);
cls.add(permedFn);
seen.add(permedFn);
}
}
}
classes.push(cls);
}
return classes;
}
Insert cell
function* permutations(list) {
if (list.length === 0) {
} else if (list.length === 1) {
yield list;
} else {
for (let [index, item] of list.entries()) {
let copy = [...list];
copy.splice(index, 1);
for (let perm of permutations(copy)) {
yield [item, ...perm];
}
}
}
}
Insert cell
function* combinations(list, n) {
if (n === 0) {
yield [];
} else if (list.length === n) {
yield list;
} else {
let [head, ...tail] = list;
for (let item of combinations(tail, n - 1)) {
yield [head, ...item];
}
yield* combinations(tail, n);
}
}
Insert cell
[...combinationsWithRepeats([1, 2, 3, 4], 3)]
Insert cell
function* combinationsWithRepeats(list, n) {
if (n === 0) {
yield [];
} else if (list.length === 0) {
} else if (n === 1) {
yield* list.map((l) => [l]);
} else {
let [head, ...tail] = list;
for (let item of combinationsWithRepeats(list, n - 1)) {
yield [head, ...item];
}
yield* combinationsWithRepeats(tail, n);
}
}
Insert cell
function inverseFn(arity, code) {
return (~code % 2 ** (2 ** arity)) + 2 ** (2 ** arity);
}
Insert cell
// Get the code of the function represented by `code` but with the arguments
function withInvMap(arity, code, invMap) {
let newCode = 0;
for (let i of _.range(2 ** arity - 1, -1, -1)) {
newCode <<= 1;
let inverted = i ^ invMap;
newCode |= getIndex(code, inverted);
}
return newCode;
}
Insert cell
function getPermed(arity, code, perm) {
let newCode = 0;
for (let i of _.range(2 ** arity - 1, -1, -1)) {
newCode <<= 1;
let permed = permuteBits(arity, i, perm);
newCode |= getIndex(code, permed);
}
return newCode;
}
Insert cell
function permuteBits(arity, digits, permutation) {
let newBits = 0;
for (let i of _.range(arity)) {
newBits |= getIndex(digits, permutation[i]) << i;
}
return newBits;
}
Insert cell
function getIndex(code, index) {
return (code >> index) % 2;
}
Insert cell
class BitSet {
constructor(length) {
this.set = new Uint32Array(Math.floor(length / 32) + 1);
}

add(uint) {
let index = Math.floor(uint / 32);
let pos = uint % 32;
this.set[index] |= 1 << pos;
}

has(uint) {
let index = Math.floor(uint / 32);
let pos = uint % 32;
return !!((this.set[index] >> pos) % 2);
}
}
Insert cell
function getCode(arity, f) {
let code = 0;
for (let i = 0; i < 2 ** arity; i++) {
let args = _.range(arity).map((j) => getIndex(i, j));
code |= f(...args) << i;
}
return code;
}
Insert cell
trueFn = withFormat(
() => true,
() => "true"
)
Insert cell
falseFn = withFormat(
() => false,
() => "false"
)
Insert cell
idFn = withFormat(
(a) => a,
(a) => `${a}`
)
Insert cell
notFn = withFormat(
(a) => !a,
(a) => `!${a}`
)
Insert cell
andFn = withFormat(
(...args) => args.every((x) => x),
(...args) => args.join(" & ")
)
Insert cell
orFn = withFormat(
(...args) => args.some((x) => x),
(...args) => args.join(" | ")
)
Insert cell
xor2 = withFormat(
(a, b) => !!a !== !!b,
(a, b) => `${a} ^ ${b}`
)
Insert cell
eq2 = withFormat(
(a, b) => !!a === !!b,
(a, b) => `${a} = ${b}`
)
Insert cell
oddFn = withFormat(
(...args) => _.sum(args) % 2 === 1,
(...args) => args.join(" ^ ")
)
Insert cell
evenFn = withFormat(
(...args) => _.sum(args) % 2 === 0,
(...args) => `!(${args.join(" ^ ")})`
)
Insert cell
eqFn = withFormat(
(...args) => args.every((arg) => !!arg === !!args[0]),
(...args) => args.join(" == ")
)
Insert cell
neqFn = negateFn(eqFn)
Insert cell
function widen(fn, arity, indices) {
if (typeof indices === "number") {
indices = [indices];
}
return withFormat(
(...args) => fn(...getIndices(args, indices)),
(...args) => fn.format(...getIndices(args, indices))
);
}
Insert cell
function negateFn(fn) {
return withFormat(
(...args) => !fn(...args),
(...args) => `!(${fn.format(...args)})`
);
}
Insert cell
function permuteFn(fn, order) {
return withFormat(
(...args) => fn(...order.map((i) => args[i])),
(...args) => fn.format(...order.map((i) => args[i]))
);
}
Insert cell
function applyNegations(fn, code) {
return withFormat(
(...args) => fn(...args.map((arg, i) => (getIndex(code, i) ? !arg : arg))),
(...args) =>
fn.format(...args.map((arg, i) => (getIndex(code, i) ? `!${arg}` : arg)))
);
}
Insert cell
function getIndices(array, indices) {
return indices.map((i) => array[i]);
}
Insert cell
function withFormat(fn, format) {
fn.format = format;
return fn;
}
Insert cell
function countBits(bits) {
let sum = 0;
while (bits) {
sum += bits % 2;
bits >>= 1;
}
return sum;
}
Insert cell
Insert cell
Var = {
let result = (a) => a;
result.format = (a) => `${a}`;
result.arity = 1;
return result;
}
Insert cell
And = makeCombinationFunction((els) => els.every((x) => !!x), "&")
Insert cell
Or = makeCombinationFunction((els) => els.some((x) => !!x), "|")
Insert cell
Odd = makeCombinationFunction((els) => _.sum(els) % 2 === 1, "^")
Insert cell
Even = makeCombinationFunction((els) => _.sum(els) % 2 === 0, "_")
Insert cell
Xor = Odd
Insert cell
Eq = makeCombinationFunction((els) => els.every((el) => el == els[0]), "==")
Insert cell
Neq = makeCombinationFunction((els) => els.some((el) => el != els[0]), "!=")
Insert cell
function CountEq(...n) {
let nFormat = n.length === 1 ? `${n}` : `{${n.join(",")}}`;
return makeCombinationFunction(
(args) => n.some((i) => _.sum(args) === i),
(args) => `[${args.join(",")}] = ${nFormat}`
);
}
Insert cell
function CountNeq(...n) {
let nFormat = n.length === 1 ? `${n}` : `{${n.join(",")}}`;
return makeCombinationFunction(
(args) => n.every((i) => _.sum(args) !== i),
(args) => `[${args.join(",")}] != ${nFormat}`
);
}
Insert cell
function CountGeq(n) {
return makeCombinationFunction(
(args) => _.sum(args) >= n,
(args) => `[${args.join(",")}] >= ${n}`
);
}
Insert cell
function CountLeq(n) {
return makeCombinationFunction(
(args) => _.sum(args) <= n,
(args) => `[${args.join(",")}] <= ${n}`
);
}
Insert cell
function makeCombinationFunction(combiner, format) {
let formatFn =
typeof format === "string"
? (subFormats) => subFormats.join(` ${format} `)
: format;
function Combiner(...subFns) {
let arities = subFns.map((fn) => fn.arity);
// apply each of the sub functions to the appropriate number of arguments
// and then pass the result to the combiner
let fn = (...args) => {
let chunked = chunkArray(args, arities);
return combiner(subFns.map((fn, i) => fn(...chunked[i])));
};
fn.format = (...args) => {
let chunked = chunkArray(args, arities);
return formatFn(
subFns.map((fn, i) => {
let base = fn.format(...chunked[i]);
if (fn.wrapParen) {
base = `(${base})`;
}
return base;
})
);
};
fn.arity = _.sum(arities);
fn.wrapParen = true;
return fn;
}

return Combiner;
}
Insert cell
function makeNegated(Base) {
function Negated(...args) {
let orig = Base(...args);
let fn = (...args) => !orig(...args);
fn.format = (...args) =>
orig.wrapParen
? `!(${orig.format(...args)})`
: `!${orig.format(...args)}`;
fn.arity = orig.arity;
return fn;
}
return Negated;
}
Insert cell
function chunkArray(array, segments) {
if (array.length !== _.sum(segments)) {
throw new Error(
`Expected ${_.sum(segments)} elements but got ${array.length}`
);
}
let result = [];
for (let index of segments) {
let [head, tail] = splitAt(array, index);
result.push(head);
array = tail;
}
return result;
}
Insert cell
function splitAt(list, index) {
return [list.slice(0, index), list.slice(index, list.length)];
}
Insert cell
function* cycle(list) {
for (let i = 0; i < list.length; i++) {
let head = list.slice(0, i);
let tail = list.slice(i);
yield [...tail, ...head];
}
}
Insert cell
## n-ary fill functions
Insert cell
function populateNullary(setAsRepr, setList) {
setAsRepr(trueFn);
setList(trueFn);
setList(falseFn);
}
Insert cell
function populateUnary(setAsRepr, setList, arity) {
setAsRepr(idFn);
for (let i = 0; i < arity; i++) {
setList(widen(idFn, arity, i));
setList(widen(notFn, arity, i));
}
}
Insert cell
function fillBinary(setList) {
setList(xor2);
setList(eq2);
for (let inv of _.range(2 ** 2)) {
setList(applyNegations(andFn, inv));
setList(applyNegations(orFn, inv));
}
}
Insert cell
function setRepsBinary(setAsRepr) {
setAsRepr(andFn);
setAsRepr(xor2);
}
Insert cell
function getWidenedFn(setRepsFn, fillFn, origArity) {
return (setAsRepr, setList, arity) => {
setRepsFn((fn) => {
setAsRepr(widen(fn, arity, _.range(origArity)));
});
for (let idxCombo of combinations(_.range(arity), origArity)) {
fillFn((fn) => {
setList(widen(fn, arity, idxCombo));
});
}
};
}
Insert cell
populateBinary = getWidenedFn(setRepsBinary, fillBinary, 2)
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more