Tackled infinite loop by changing float64Array
generator to
`float32Array` generator; gave up on avoiding `any` type in `Jstat_test.ts`
This commit is contained in:
parent
0ab1858c0e
commit
36f929b726
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
|
@ -9,3 +9,5 @@ updates:
|
|||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "daily"
|
||||
commit-message:
|
||||
prefix: "⬆️"
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
resultMap,
|
||||
squiggleExpression,
|
||||
errorValueToString,
|
||||
} from "../src/js/index";
|
||||
} from "../../src/js/index";
|
||||
|
||||
let testRun = (x: string): squiggleExpression => {
|
||||
let result = run(x, { sampleCount: 100, xyPointLength: 100 });
|
58
packages/squiggle-lang/__tests__/TS/Jstat_test.ts
Normal file
58
packages/squiggle-lang/__tests__/TS/Jstat_test.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
import {
|
||||
run,
|
||||
Distribution,
|
||||
squiggleExpression,
|
||||
errorValueToString,
|
||||
errorValue,
|
||||
result,
|
||||
} from "../../src/js/index";
|
||||
import * as fc from "fast-check";
|
||||
|
||||
let testRun = (x: string): any => {
|
||||
//result<squiggleExpression, errorValue> => {
|
||||
return run(x, { sampleCount: 1000, xyPointLength: 100 });
|
||||
};
|
||||
|
||||
let failDefault = () => expect("codepath should never").toBe("be reached");
|
||||
|
||||
describe("Jstat: cumulative density function", () => {
|
||||
test("of a normal distribution at 3 stdevs to the right of the mean is within epsilon of 1", () => {
|
||||
fc.assert(
|
||||
fc.property(fc.float(), fc.float({ min: 1e-7 }), (mean, stdev) => {
|
||||
let squiggleString = `cdf(normal(${mean}, ${stdev}), ${
|
||||
mean + 3 * stdev
|
||||
})`;
|
||||
let squiggleResult = testRun(squiggleString);
|
||||
let epsilon = 5e-3;
|
||||
switch (squiggleResult.tag) {
|
||||
case "Error":
|
||||
expect(errorValueToString(squiggleResult.value)).toEqual(
|
||||
"<Test cases don't seem to be finding this>"
|
||||
);
|
||||
case "Ok":
|
||||
expect(squiggleResult.value.value).toBeGreaterThan(1 - epsilon);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("of a normal distribution at 3 stdevs to the left of the mean is within epsilon of 0", () => {
|
||||
fc.assert(
|
||||
fc.property(fc.float(), fc.float({ min: 1e-7 }), (mean, stdev) => {
|
||||
let squiggleString = `cdf(normal(${mean}, ${stdev}), ${
|
||||
mean - 3 * stdev
|
||||
})`;
|
||||
let squiggleResult = testRun(squiggleString);
|
||||
let epsilon = 5e-3;
|
||||
switch (squiggleResult.tag) {
|
||||
case "Error":
|
||||
expect(errorValueToString(squiggleResult.value)).toEqual(
|
||||
"<Test cases don't seem to be finding this>"
|
||||
);
|
||||
case "Ok":
|
||||
expect(squiggleResult.value.value).toBeLessThan(epsilon);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
58
packages/squiggle-lang/__tests__/TS/Parser_test.ts
Normal file
58
packages/squiggle-lang/__tests__/TS/Parser_test.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
import {
|
||||
run,
|
||||
squiggleExpression,
|
||||
errorValue,
|
||||
result,
|
||||
} from "../../src/js/index";
|
||||
import * as fc from "fast-check";
|
||||
|
||||
let testRun = (x: string): result<squiggleExpression, errorValue> => {
|
||||
return run(x, { sampleCount: 1000, xyPointLength: 100 });
|
||||
};
|
||||
|
||||
describe("Squiggle is whitespace insensitive", () => {
|
||||
test("when assigning a distribution to a name and calling that name", () => {
|
||||
/*
|
||||
* intersperse varying amounts of whitespace in a squiggle string
|
||||
*/
|
||||
let squiggleString = (
|
||||
a: string,
|
||||
b: string,
|
||||
c: string,
|
||||
d: string,
|
||||
e: string,
|
||||
f: string,
|
||||
g: string,
|
||||
h: string
|
||||
): string => {
|
||||
return `theDist${a}=${b}beta(${c}4${d},${e}5e1)${f};${g}theDist${h}`;
|
||||
};
|
||||
let squiggleOutput = testRun(
|
||||
squiggleString("", "", "", "", "", "", "", "")
|
||||
);
|
||||
/*
|
||||
* Add "\n" to this when multiline is introduced.
|
||||
*/
|
||||
let whitespaceGen = () => {
|
||||
return fc.constantFrom("", " ", "\t", " ", " ", " ", " ");
|
||||
};
|
||||
|
||||
fc.assert(
|
||||
fc.property(
|
||||
whitespaceGen(),
|
||||
whitespaceGen(),
|
||||
whitespaceGen(),
|
||||
whitespaceGen(),
|
||||
whitespaceGen(),
|
||||
whitespaceGen(),
|
||||
whitespaceGen(),
|
||||
whitespaceGen(),
|
||||
(a, b, c, d, e, f, g, h) => {
|
||||
expect(testRun(squiggleString(a, b, c, d, e, f, g, h))).toEqual(
|
||||
squiggleOutput
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
238
packages/squiggle-lang/__tests__/TS/SampleSet_test.ts
Normal file
238
packages/squiggle-lang/__tests__/TS/SampleSet_test.ts
Normal file
|
@ -0,0 +1,238 @@
|
|||
import {
|
||||
run,
|
||||
Distribution,
|
||||
squiggleExpression,
|
||||
errorValueToString,
|
||||
errorValue,
|
||||
result,
|
||||
} from "../../src/js/index";
|
||||
import * as fc from "fast-check";
|
||||
|
||||
let testRun = (x: string): result<squiggleExpression, errorValue> => {
|
||||
return run(x, { sampleCount: 1000, xyPointLength: 100 });
|
||||
};
|
||||
|
||||
let failDefault = () => expect("codepath should never").toBe("be reached");
|
||||
|
||||
// Beware: float64Array makes it appear in an infinite loop.
|
||||
let arrayGen = () =>
|
||||
fc.float32Array({
|
||||
minLength: 10,
|
||||
maxLength: 10000,
|
||||
noDefaultInfinity: true,
|
||||
noNaN: true,
|
||||
});
|
||||
|
||||
describe("SampleSet: cdf", () => {
|
||||
let n = 10000
|
||||
test("at the highest number in the distribution is within epsilon of 1", () => {
|
||||
fc.assert(
|
||||
fc.property(arrayGen(), (xs) => {
|
||||
let ys = Array.from(xs);
|
||||
let max = Math.max(...ys);
|
||||
// Should compute with squiglge strings once interpreter has `sample`
|
||||
let dist = new Distribution(
|
||||
{ tag: "SampleSet", value: ys },
|
||||
{ sampleCount: n, xyPointLength: 100 }
|
||||
);
|
||||
let cdfValue = dist.cdf(max).value
|
||||
let min = Math.min(...ys)
|
||||
let epsilon = 5e-3;
|
||||
if (max - min < epsilon) {
|
||||
expect(cdfValue).toBeLessThan(1 - epsilon)
|
||||
} else {
|
||||
expect(dist.cdf(max).value).toBeGreaterThan(1 - epsilon);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("at the lowest number in the distribution is within epsilon of 0", () => {
|
||||
fc.assert(
|
||||
fc.property(arrayGen(), (xs) => {
|
||||
let ys = Array.from(xs);
|
||||
let min = Math.min(...ys);
|
||||
// Should compute with squiggle strings once interpreter has `sample`
|
||||
let dist = new Distribution(
|
||||
{ tag: "SampleSet", value: ys },
|
||||
{ sampleCount: n, xyPointLength: 100 }
|
||||
);
|
||||
let cdfValue = dist.cdf(min).value
|
||||
let max = Math.max(...ys);
|
||||
let epsilon = 5e-3;
|
||||
if (max - min < epsilon) {
|
||||
expect(cdfValue).toBeGreaterThan(epsilon)
|
||||
} else {
|
||||
expect(cdfValue).toBeLessThan(epsilon);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("is <= 1 everywhere with equality when x is higher than the max", () => {
|
||||
fc.assert(
|
||||
fc.property(arrayGen(), fc.float(), (xs, x) => {
|
||||
let ys = Array.from(xs)
|
||||
let dist = new Distribution(
|
||||
{ tag: "SampleSet", value: ys },
|
||||
{ sampleCount: n, xyPointLength: 100 }
|
||||
);
|
||||
let cdfValue = dist.cdf(x).value
|
||||
let epsilon = 1e-1
|
||||
if (x > Math.max(...ys)) { // The really good way to do this is to have epsilon be a function of the percentage by which x > max(ys)
|
||||
expect(cdfValue).toBeGreaterThan(1 - epsilon - epsilon ** 2)
|
||||
} else {
|
||||
expect(cdfValue).toBeLessThan(1);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("is >= 0 everywhere with equality when x is lower than the min", () => {
|
||||
fc.assert(
|
||||
fc.property(arrayGen(), fc.float(), (xs, x) => {
|
||||
let ys = Array.from(xs)
|
||||
let dist = new Distribution(
|
||||
{ tag: "SampleSet", value: ys },
|
||||
{ sampleCount: n, xyPointLength: 100 }
|
||||
);
|
||||
let cdfValue = dist.cdf(x).value
|
||||
if (x < Math.min(...ys)) {
|
||||
expect(cdfValue).toEqual(0)
|
||||
} else {
|
||||
expect(cdfValue).toBeGreaterThan(0);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("SampleSet: pdf of extremes is lower than pdf of mean.", () => {
|
||||
let n = 1000
|
||||
|
||||
test("a sampleset distribution's pdf assigns less weight to the max than to the mean", () => {
|
||||
fc.assert(
|
||||
fc.property(arrayGen(), (xs) => {
|
||||
let ys = Array.from(xs);
|
||||
let max = Math.max(...ys);
|
||||
let mean = ys.reduce((a, b) => a + b, 0.0) / ys.length;
|
||||
// Should be from squiggleString once interpreter exposes sampleset
|
||||
let dist = new Distribution(
|
||||
{ tag: "SampleSet", value: ys },
|
||||
{ sampleCount: n, xyPointLength: 100 }
|
||||
);
|
||||
let pdfMean = dist.pdf(mean);
|
||||
let pdfMax = dist.pdf(max);
|
||||
switch (pdfMax.tag) {
|
||||
case "Ok":
|
||||
let min = Math.min(...ys)
|
||||
switch (pdfMean.tag) {
|
||||
case "Ok":
|
||||
if (max == min) {
|
||||
expect(pdfMax.value).toBeLessThanOrEqual(pdfMean.value);
|
||||
} else {
|
||||
expect(pdfMax.value).toBeLessThan(pdfMean.value);
|
||||
}
|
||||
case "Error":
|
||||
if (max == min) {
|
||||
expect(pdfMean.value).toEqual(1);
|
||||
} else {
|
||||
expect(pdfMean.value).toEqual("error message");
|
||||
}
|
||||
default:
|
||||
failDefault();
|
||||
}
|
||||
case "Error":
|
||||
switch (pdfMean.tag) {
|
||||
case "Ok":
|
||||
expect(pdfMax.value).toEqual("error message");
|
||||
case "Error":
|
||||
expect(pdfMax.value).toEqual(pdfMean.value);
|
||||
default:
|
||||
failDefault();
|
||||
}
|
||||
default:
|
||||
failDefault();
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// describe("SampleSet: mean is mean", () => {
|
||||
// test("mean(samples(xs)) sampling twice as widely as the input", () => {
|
||||
// fc.assert(
|
||||
// fc.property(
|
||||
// fc.float64Array({ minLength: 10, maxLength: 100000 }),
|
||||
// (xs) => {
|
||||
// let ys = Array.from(xs);
|
||||
// let n = ys.length;
|
||||
// let dist = new Distribution(
|
||||
// { tag: "SampleSet", value: ys },
|
||||
// { sampleCount: 2 * n, xyPointLength: 4 * n }
|
||||
// );
|
||||
//
|
||||
// expect(dist.mean().value).toBeCloseTo(
|
||||
// ys.reduce((a, b) => a + b, 0.0) / n
|
||||
// );
|
||||
// }
|
||||
// )
|
||||
// );
|
||||
// });
|
||||
//
|
||||
// test("mean(samples(xs)) sampling half as widely as the input", () => {
|
||||
// fc.assert(
|
||||
// fc.property(
|
||||
// fc.float64Array({ minLength: 10, maxLength: 100000 }),
|
||||
// (xs) => {
|
||||
// let ys = Array.from(xs);
|
||||
// let n = ys.length;
|
||||
// let dist = new Distribution(
|
||||
// { tag: "SampleSet", value: ys },
|
||||
// { sampleCount: Math.floor(5 / 2), xyPointLength: 4 * n }
|
||||
// );
|
||||
//
|
||||
// expect(dist.mean().value).toBeCloseTo(
|
||||
// ys.reduce((a, b) => a + b, 0.0) / n
|
||||
// );
|
||||
// }
|
||||
// )
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
|
||||
// describe("Mean of mixture is weighted average of means", () => {
|
||||
// test("mx(beta(a,b), lognormal(m,s), [x,y])", () => {
|
||||
// fc.assert(
|
||||
// fc.property(
|
||||
// fc.float({ min: 1e-1 }), // alpha
|
||||
// fc.float({ min: 1 }), // beta
|
||||
// fc.float(), // mu
|
||||
// fc.float({ min: 1e-1 }), // sigma
|
||||
// fc.float({ min: 1e-7 }),
|
||||
// fc.float({ min: 1e-7 }),
|
||||
// (a, b, m, s, x, y) => {
|
||||
// let squiggleString = `mean(mx(beta(${a},${b}), lognormal(${m},${s}), [${x}, ${y}]))`;
|
||||
// let res = testRun(squiggleString);
|
||||
// switch (res.tag) {
|
||||
// case "Error":
|
||||
// expect(errorValueToString(res.value)).toEqual(
|
||||
// "<I wonder if test cases will find this>"
|
||||
// );
|
||||
// case "Ok":
|
||||
// let betaWeight = x / (x + y);
|
||||
// let lognormalWeight = y / (x + y);
|
||||
// let betaMean = 1 / (1 + b / a);
|
||||
// let lognormalMean = m + s ** 2 / 2;
|
||||
// expect(res.value).toEqual({
|
||||
// tag: "number",
|
||||
// value: betaWeight * betaMean + lognormalWeight * lognormalMean,
|
||||
// });
|
||||
// default:
|
||||
// expect("mean returned").toBe(`something other than a number`);
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
// );
|
||||
// });
|
||||
// });
|
62
packages/squiggle-lang/__tests__/TS/Scalars_test.ts
Normal file
62
packages/squiggle-lang/__tests__/TS/Scalars_test.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
import {
|
||||
run,
|
||||
Distribution,
|
||||
resultMap,
|
||||
squiggleExpression,
|
||||
errorValueToString,
|
||||
errorValue,
|
||||
result,
|
||||
} from "../../src/js/index";
|
||||
import * as fc from "fast-check";
|
||||
|
||||
let testRun = (x: string): result<squiggleExpression, errorValue> => {
|
||||
return run(x, { sampleCount: 100, xyPointLength: 100 });
|
||||
};
|
||||
|
||||
describe("Scalar manipulation is well-modeled by javascript math", () => {
|
||||
test("in the case of logarithms (with assignment)", () => {
|
||||
fc.assert(
|
||||
fc.property(fc.float(), (x) => {
|
||||
let squiggleString = `x = log(${x}); x`;
|
||||
let squiggleResult = testRun(squiggleString);
|
||||
if (x == 0) {
|
||||
expect(squiggleResult.value).toEqual({
|
||||
tag: "number",
|
||||
value: -Infinity,
|
||||
});
|
||||
} else if (x < 0) {
|
||||
expect(squiggleResult.value).toEqual({
|
||||
tag: "RETodo",
|
||||
value:
|
||||
"somemessage (confused why a test case hasn't pointed out to me that this message is bogus)",
|
||||
});
|
||||
} else {
|
||||
expect(squiggleResult.value).toEqual({
|
||||
tag: "number",
|
||||
value: Math.log(x),
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("in the case of addition (with assignment)", () => {
|
||||
fc.assert(
|
||||
fc.property(fc.float(), fc.float(), fc.float(), (x, y, z) => {
|
||||
let squiggleString = `x = ${x}; y = ${y}; z = ${z}; x + y + z`;
|
||||
let squiggleResult = testRun(squiggleString);
|
||||
switch (squiggleResult.tag) {
|
||||
case "Error":
|
||||
expect(errorValueToString(squiggleResult.value)).toEqual(
|
||||
"some message (hopefully a test case points it out to me)"
|
||||
);
|
||||
case "Ok":
|
||||
expect(squiggleResult.value).toEqual({
|
||||
tag: "number",
|
||||
value: x + y + z,
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
44
packages/squiggle-lang/__tests__/TS/Symbolic_test.ts
Normal file
44
packages/squiggle-lang/__tests__/TS/Symbolic_test.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import {
|
||||
run,
|
||||
squiggleExpression,
|
||||
errorValueToString,
|
||||
errorValue,
|
||||
result,
|
||||
} from "../../src/js/index";
|
||||
import * as fc from "fast-check";
|
||||
|
||||
let testRun = (x: string): result<squiggleExpression, errorValue> => {
|
||||
return run(x, { sampleCount: 100, xyPointLength: 100 });
|
||||
};
|
||||
|
||||
describe("Symbolic mean", () => {
|
||||
let triangularInputError = {
|
||||
tag: "Error",
|
||||
value: {
|
||||
tag: "RETodo",
|
||||
value: "Triangular values must be increasing order.",
|
||||
},
|
||||
};
|
||||
test("mean(triangular(x,y,z))", () => {
|
||||
fc.assert(
|
||||
fc.property(fc.float(), fc.float(), fc.float(), (x, y, z) => {
|
||||
let res = testRun(`mean(triangular(${x},${y},${z}))`);
|
||||
if (!(x < y && y < z)) {
|
||||
expect(res).toEqual(triangularInputError);
|
||||
} else {
|
||||
switch (res.tag) {
|
||||
case "Error":
|
||||
expect(errorValueToString(res.value)).toEqual(
|
||||
"<Test cases don't seem to be finding this>"
|
||||
);
|
||||
case "Ok":
|
||||
expect(res.value).toEqual({
|
||||
tag: "number",
|
||||
value: (x + y + z) / 3,
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
|
@ -44,6 +44,7 @@
|
|||
"moduleserve": "0.9.1",
|
||||
"ts-jest": "^27.1.4",
|
||||
"ts-loader": "^9.2.8",
|
||||
"fast-check": "2.24.0",
|
||||
"typescript": "^4.6.3",
|
||||
"webpack": "^5.72.0",
|
||||
"webpack-cli": "^4.9.2"
|
||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -8417,6 +8417,13 @@ extglob@^2.0.4:
|
|||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
fast-check@2.24.0:
|
||||
version "2.24.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.24.0.tgz#39f85586862108a4de6394c5196ebcf8b76b6c8b"
|
||||
integrity sha512-iNXbN90lbabaCUfnW5jyXYPwMJLFYl09eJDkXA9ZoidFlBK63gNRvcKxv+8D1OJ1kIYjwBef4bO/K3qesUeWLQ==
|
||||
dependencies:
|
||||
pure-rand "^5.0.1"
|
||||
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3, fast-deep-equal@~3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
|
@ -13573,6 +13580,11 @@ pure-color@^1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
|
||||
integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=
|
||||
|
||||
pure-rand@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-5.0.1.tgz#97a287b4b4960b2a3448c0932bf28f2405cac51d"
|
||||
integrity sha512-ksWccjmXOHU2gJBnH0cK1lSYdvSZ0zLoCMSz/nTGh6hDvCSgcRxDyIcOBD6KNxFz3xhMPm/T267Tbe2JRymKEQ==
|
||||
|
||||
q@^1.1.2:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
||||
|
|
Loading…
Reference in New Issue
Block a user