Refactor (1)

This commit is contained in:
2025-09-19 18:54:12 +09:00
committed by cannorin
parent 6b15542c40
commit c3b1bf39a4
26 changed files with 1684 additions and 105 deletions

View File

@@ -1,6 +1,6 @@
export type PropVar = "p" | "q" | "r" | "s";
export const propVars: PropVar[] = ["p", "q", "r", "s"];
export const propVars = ["p", "q", "r", "s"] as const satisfies PropVar[];
export type Formula =
| { type: "top" | "bot" }
@@ -149,3 +149,226 @@ export function prettyPrint(
}
}
}
export function simplify(fml: Formula): Formula {
switch (fml.type) {
case "top":
case "bot":
case "propvar":
return fml;
case "not":
case "box":
case "diamond": {
const inner = simplify(fml.fml);
if (fml.type === "not" && inner.type === "not") return inner.fml;
if (fml.type === "not" && inner.type === "top") return bot;
if (fml.type === "not" && inner.type === "bot") return top;
if (fml.type === "box" && inner.type === "top") return top;
if (fml.type === "diamond" && inner.type === "bot") return bot;
return {
type: fml.type,
fml: inner,
};
}
case "or":
case "and":
case "to":
case "eq": {
const innerLeft = simplify(fml.left);
const innerRight = simplify(fml.right);
if (fml.type === "and" && innerLeft.type === "top") return innerRight;
if (fml.type === "and" && innerRight.type === "top") return innerLeft;
if (
fml.type === "and" &&
(innerLeft.type === "bot" || innerRight.type === "bot")
)
return bot;
if (fml.type === "or" && innerLeft.type === "bot") return innerRight;
if (fml.type === "or" && innerRight.type === "bot") return innerLeft;
if (
fml.type === "or" &&
(innerLeft.type === "top" || innerRight.type === "top")
)
return top;
if (fml.type === "to" && innerLeft.type === "top") return innerRight;
if (fml.type === "to" && innerLeft.type === "bot") return top;
if (fml.type === "to" && innerRight.type === "top") return top;
if (fml.type === "to" && innerRight.type === "bot")
return simplify(not(innerLeft));
if (fml.type === "eq" && innerLeft.type === "top") return innerRight;
if (fml.type === "eq" && innerRight.type === "top") return innerLeft;
if (fml.type === "eq" && innerRight.type === "bot")
return simplify(not(innerLeft));
if (fml.type === "eq" && innerLeft.type === "bot")
return simplify(not(innerRight));
return {
type: fml.type,
left: innerLeft,
right: innerRight,
};
}
}
}
export type NNFFormula<T = undefined> =
| { type: "top" | "bot"; tag: T }
| { type: "propvar"; name: PropVar; tag: T }
| { type: "not"; fml: { type: "propvar"; name: PropVar; tag: T }; tag: T }
| { type: "box" | "diamond"; fml: NNFFormula<T>; tag: T }
| {
type: "and" | "or";
left: NNFFormula<T>;
right: NNFFormula<T>;
tag: T;
};
export function toNNF(fml: Formula): NNFFormula {
switch (fml.type) {
case "top":
return { ...fml, tag: undefined };
case "bot":
return { ...fml, tag: undefined };
case "propvar":
return { ...fml, tag: undefined };
case "box": {
return {
type: "box",
fml: toNNF(fml.fml),
tag: undefined,
};
}
case "diamond": {
return {
type: "diamond",
fml: toNNF(fml.fml),
tag: undefined,
};
}
case "to": {
return toNNF(or(not(fml.left), fml.right));
}
case "eq": {
return toNNF(
and(or(not(fml.left), fml.right), or(not(fml.right), fml.left)),
);
}
case "or": {
return {
type: "or",
left: toNNF(fml.left),
right: toNNF(fml.right),
tag: undefined,
};
}
case "and": {
return {
type: "and",
left: toNNF(fml.left),
right: toNNF(fml.right),
tag: undefined,
};
}
case "not": {
switch (fml.fml.type) {
case "top":
return { ...bot, tag: undefined };
case "bot":
return { ...top, tag: undefined };
case "propvar":
return {
type: "not",
fml: { ...fml.fml, tag: undefined },
tag: undefined,
};
case "not":
return toNNF(fml.fml.fml);
case "box":
return {
type: "diamond",
fml: toNNF(not(fml.fml.fml)),
tag: undefined,
};
case "diamond":
return { type: "box", fml: toNNF(not(fml.fml.fml)), tag: undefined };
case "or":
return {
type: "and",
left: toNNF(not(fml.fml.left)),
right: toNNF(not(fml.fml.right)),
tag: undefined,
};
case "and":
return {
type: "or",
left: toNNF(not(fml.fml.left)),
right: toNNF(not(fml.fml.right)),
tag: undefined,
};
case "to":
return {
type: "and",
left: toNNF(fml.fml.left),
right: toNNF(not(fml.fml.right)),
tag: undefined,
};
case "eq":
return {
type: "or",
left: {
type: "and",
left: toNNF(fml.fml.left),
right: toNNF(not(fml.fml.right)),
tag: undefined,
},
right: {
type: "and",
left: toNNF(not(fml.fml.left)),
right: toNNF(fml.fml.right),
tag: undefined,
},
tag: undefined,
};
}
}
}
}
export function tagNNF<T, U>(
fml: NNFFormula<T>,
tagger: (fml: Omit<NNFFormula<T>, "tag">, tag: T) => U,
): NNFFormula<U> {
switch (fml.type) {
case "top":
case "bot":
case "propvar":
return { ...fml, tag: tagger(fml, fml.tag) };
case "not":
return {
type: "not",
fml: {
type: "propvar",
name: fml.fml.name,
tag: tagger(fml.fml, fml.fml.tag),
},
tag: tagger(fml, fml.tag),
};
case "box":
case "diamond":
return {
type: fml.type,
fml: tagNNF(fml.fml, tagger),
tag: tagger(fml, fml.tag),
};
case "and":
case "or":
return {
type: fml.type,
left: tagNNF(fml.left, tagger),
right: tagNNF(fml.right, tagger),
tag: tagger(fml, fml.tag),
};
}
}