Refactor (1)
This commit is contained in:
30
packages/kripke/tests/sat.test.ts
Normal file
30
packages/kripke/tests/sat.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { expect, test } from "vitest";
|
||||
import { validWorlds } from "../sat";
|
||||
import { validWorlds as validWorldsNaive } from "../semantics";
|
||||
import { prettyPrint } from "../syntax";
|
||||
import { randomFormula, randomFrame, testFormulas } from "./utils";
|
||||
|
||||
const elapsed = <T>(f: () => T) => {
|
||||
const start = Date.now();
|
||||
const value = f();
|
||||
const end = Date.now();
|
||||
return { value, elapsed: end - start };
|
||||
};
|
||||
|
||||
for (const fml of testFormulas.concat(
|
||||
[...Array(50)].map(() => randomFormula()),
|
||||
)) {
|
||||
test(`SAT works for ${prettyPrint(fml)}`, () => {
|
||||
const count = 100;
|
||||
let diff = 0;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const frame = randomFrame();
|
||||
const expected = elapsed(() => validWorldsNaive(frame, fml));
|
||||
const actual = elapsed(() => validWorlds(frame, fml));
|
||||
|
||||
expect(actual.value.sort()).toStrictEqual(expected.value.sort());
|
||||
diff += actual.elapsed - expected.elapsed;
|
||||
}
|
||||
expect(diff / count).toBeLessThanOrEqual(10);
|
||||
});
|
||||
}
|
||||
96
packages/kripke/tests/utils.ts
Normal file
96
packages/kripke/tests/utils.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { sample } from "@cannorin/utils/array";
|
||||
import { parse } from "../parser";
|
||||
import { getFrame, nontrivials } from "../semantics";
|
||||
import {
|
||||
type Formula,
|
||||
and,
|
||||
bot,
|
||||
box,
|
||||
diamond,
|
||||
eq,
|
||||
not,
|
||||
or,
|
||||
propvar,
|
||||
to,
|
||||
top,
|
||||
} from "../syntax";
|
||||
|
||||
const formulaTypes = [
|
||||
"top",
|
||||
"bot",
|
||||
"propvar",
|
||||
"not",
|
||||
"and",
|
||||
"or",
|
||||
"to",
|
||||
"eq",
|
||||
"box",
|
||||
"diamond",
|
||||
] as const satisfies Formula["type"][];
|
||||
|
||||
export const testFormulas: Formula[] = [
|
||||
parse("L(p -> q) -> (Lp -> Lq)"),
|
||||
parse("Lp -> p"),
|
||||
parse("LLp -> Lp"),
|
||||
parse("Lp -> LLp"),
|
||||
parse("Lp -> Mp"),
|
||||
parse("p -> LMp"),
|
||||
parse("Mp -> LMp"),
|
||||
parse("L(Lp -> p) -> Lp"),
|
||||
parse("L(L(p -> Lp) -> p) -> p"),
|
||||
parse("L(Lp -> q) v L(Lq -> p)"),
|
||||
parse("LMp -> MLp"),
|
||||
parse("MLp -> LMp"),
|
||||
parse("p -> Lp"),
|
||||
parse("Mp -> Lp"),
|
||||
parse("Mp <-> Lp"),
|
||||
parse("Lp"),
|
||||
parse("Lp v L(p -> q)"),
|
||||
parse("Lp v L(p -> q) v L(p&q -> r)"),
|
||||
|
||||
parse("L(Lp -> p)"),
|
||||
parse("LLp -> p"),
|
||||
parse("p -> LLp"),
|
||||
|
||||
// pathological
|
||||
parse("L(M(1 & p) v LM1) -> (s <-> 1)"),
|
||||
parse("L(M((q v ~q) & p) v LM(s v ~s)) -> (s <-> (p v ~p))"),
|
||||
];
|
||||
|
||||
export function randomFormula(depth = 5): Formula {
|
||||
const types = new Map([
|
||||
[5, ["not", "and", "or", "to", "eq", "box", "diamond"] as const],
|
||||
[4, ["not", "and", "or", "to", "eq", "box", "diamond"] as const],
|
||||
[0, ["top", "bot", "propvar", "propvar", "propvar", "propvar"] as const],
|
||||
]);
|
||||
|
||||
const type = sample(types.get(depth) ?? formulaTypes);
|
||||
switch (type) {
|
||||
case "top":
|
||||
return top;
|
||||
case "bot":
|
||||
return bot;
|
||||
case "propvar":
|
||||
return propvar(sample(["p", "q", "r"]));
|
||||
case "not":
|
||||
return not(randomFormula(depth - 1));
|
||||
case "and":
|
||||
return and(randomFormula(depth - 1), randomFormula(depth - 1));
|
||||
case "or":
|
||||
return or(randomFormula(depth - 1), randomFormula(depth - 1));
|
||||
case "to":
|
||||
return to(randomFormula(depth - 1), randomFormula(depth - 1));
|
||||
case "eq":
|
||||
return eq(randomFormula(depth - 1), randomFormula(depth - 1));
|
||||
case "box":
|
||||
return box(randomFormula(depth - 1));
|
||||
case "diamond":
|
||||
return diamond(randomFormula(depth - 1));
|
||||
default:
|
||||
throw new Error(`impossible: ${type}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function randomFrame() {
|
||||
return getFrame(sample(nontrivials));
|
||||
}
|
||||
Reference in New Issue
Block a user