untitled notebook

node v10.24.1
version: 1.0.0
endpointsharetweet
const fc = require('fast-check'); function xyToIndex(x, y, datasetLength) { return x * datasetLength + y; } function indexToXY(index, datasetLength) { return {x: Math.floor(index / datasetLength), y: index % datasetLength}; } function computeF(x, y, datasetLength, outputForIndexes) { return outputForIndexes[xyToIndex(x, y, datasetLength)]; } function tryBuildAssociativeFunction(sourceOutputForIndexes, datasetLength, randNat) { const firstHoleIndex = sourceOutputForIndexes.findIndex(out => out === -1); if (firstHoleIndex === -1) { return sourceOutputForIndexes; } const possibilities = [...Array(datasetLength)].map((_, index) => index); while (possibilities.length !== 0) { // Take one of the possibilities we have not tried yet const outputForIndexes = [...sourceOutputForIndexes]; const possibilityIndex = randNat() % possibilities.length; outputForIndexes[firstHoleIndex] = possibilities.splice(possibilityIndex, 1)[0]; let illegalAssignment = false; // For each assignment try to infer linked assignment based on: // f(f(x,y),i) === f(x,f(y,i)) and f(i,f(x,y)) === f(f(i,x),y) const recentlyAssigned = new Set([firstHoleIndex]); while (recentlyAssigned.size !== 0) { const assignment = recentlyAssigned[Symbol.iterator]().next().value; recentlyAssigned.delete(assignment); const {x,y} = indexToXY(assignment, datasetLength); const fxy = computeF(x, y, datasetLength, outputForIndexes); for (let i = 0 ; i !== datasetLength ; ++i) { // f(f(x,y),i) === f(x,f(y,i)) const fxy_i = computeF(fxy, i, datasetLength, outputForIndexes); if (fxy_i !== -1) { const fyi = computeF(y, i, datasetLength, outputForIndexes); if (fyi !== -1) { const affectedIndex = xyToIndex(x, fyi, datasetLength); if (outputForIndexes[affectedIndex] === -1) { recentlyAssigned.add(affectedIndex); outputForIndexes[affectedIndex] = fxy_i; } else if (outputForIndexes[affectedIndex] !== fxy_i) { illegalAssignment = true; break; } } } // f(i,f(x,y)) === f(f(i,x),y) const fi_xy = computeF(i, fxy, datasetLength, outputForIndexes); if (fi_xy !== -1) { const fix = computeF(i, x, datasetLength, outputForIndexes); if (fix !== -1) { const affectedIndex = xyToIndex(fix, y, datasetLength); if (outputForIndexes[affectedIndex] === -1) { recentlyAssigned.add(affectedIndex); outputForIndexes[affectedIndex] = fi_xy; } else if (outputForIndexes[affectedIndex] !== fi_xy) { illegalAssignment = true; break; } } } } if (illegalAssignment) { break; } } // We added our value (taken from possibilities) and impacted the outputs based on it // We now need to try to add another value randomly by calling tryBuildAssociativeFunction const extended = !illegalAssignment ? tryBuildAssociativeFunction(outputForIndexes, datasetLength, randNat) : null; if (extended !== null) { return extended; } } return null; } function buildAssociativeFunction(datasetLength, randNat) { const outputForIndexes = tryBuildAssociativeFunction( Array(datasetLength * datasetLength).fill(-1), datasetLength, randNat); return (x, y) => computeF(x, y, datasetLength, outputForIndexes); } function binaryAssociativeFunction(arb) { return fc.tuple( fc.set(arb, {minLength: 1, compare: (a, b) => fc.stringify(a) === fc.stringify(b)}), fc.infiniteStream(fc.nat()).noBias() ) .map(([dataset, randomStream]) => { const associativeF = buildAssociativeFunction( dataset.length, () => randomStream.next().value ); const stringifiedDataset = dataset.map(d => fc.stringify(d)); return (a, b) => { // compute index for a const stringifiedA = fc.stringify(a); let indexA = stringifiedDataset.indexOf(stringifiedA); if (indexA === -1) indexA = fc.hash(stringifiedA) % dataset.length; // compute index for b const stringifiedB = fc.stringify(b); let indexB = stringifiedDataset.indexOf(stringifiedB); if (indexB === -1) indexB = fc.hash(stringifiedB) % dataset.length; // compute answer const indexResult = associativeF(indexA, indexB); if (!(indexA in dataset)) throw new Error('unexpected: invalid indexA'); if (!(indexB in dataset)) throw new Error('unexpected: invalid indexB'); if (!(indexResult in dataset)) throw new Error('unexpected: invalid indexResult'); return dataset[indexResult]; }; }) } // Just trying with one of the generated functions const a = 'a'; const b = 'b'; const c = 'c'; const f1 = fc.sample(binaryAssociativeFunction(fc.string()), 1)[0]; console.log('a,b -> ' + f1(a, b)); console.log('(a,b),c -> ' + f1(f1(a, b), c)); console.log('b,c -> ' + f1(b, c)); console.log('a,(b,c) -> ' + f1(a, f1(b, c))); // Property to confirm it works fc.assert(fc.property( binaryAssociativeFunction(fc.string()), fc.string(), fc.string(), fc.string(), (f, a, b, c) => f(f(a,b),c) === f(a,f(b,c))))
Loading…

no comments

    sign in to comment