import { Node, NodeType } from "../model/Argument"; import { CertusContext, FZ } from "../model/Context"; import { EvaluationError } from "../parser/Evaluator"; import { DeductiveMacro } from "./DeductiveMacro"; abstract class MinMaxMacro extends DeductiveMacro { constructor(name: string) { super(name); } protected evaluateInner(ctx: CertusContext, op: "min" | "max", revOp: "min" | "max"): FZ { let opFun: (X: number[]) => number = X => 0; if (op === "min") { opFun = (X: number[]) => Math.min(...X) } else { opFun = (X: number[]) => Math.max(...X) } let revFun: (X: number[]) => number = X => 0; if (revOp === "min") { revFun = (X: number[]) => Math.min(...X) } else { revFun = (X: number[]) => Math.max(...X) } const root: Node = ctx.getRoot(); const nodes = this.getNodesFromContext(ctx); const P = nodes.filter(n => NodeType.checkSubType(NodeType.PREMISE, n.type)); const D = nodes.filter(n => NodeType.checkSubType(NodeType.DEFEATER, n.type)); if (P.length == 0 && D.length == 0) { return ctx.getDefaultCanonical(root.type); } else { const CS = ctx.getCanonicalSets(); const pScores = P.map(x => this.scoreNode(ctx, x, CS)); const dScores = D.map(x => this.scoreNode(ctx, x, CS)); let result: number = 0; if (NodeType.checkSubType(NodeType.PREMISE, root.type)) { let p: number; let d: number; if (dScores.length > 0 && pScores.length > 0) { d = revFun(dScores); p = opFun(pScores); } else if (dScores.length > 0 && pScores.length == 0) { d = revFun(dScores); p = 0; } else if (dScores.length == 0 && pScores.length > 0) { d = 0; p = opFun(pScores); } else { throw new EvaluationError(`Unsupported alternative when evaluating ${this.name} macro`) } if (d > 0) { result = Math.max(p - d, -4); } else { result = Math.max(p, -4); } } else if (NodeType.checkSubType(NodeType.DEFEATER, root.type)) { let p: number; let d: number; if (dScores.length > 0 && pScores.length > 0) { d = opFun(dScores); p = revFun(pScores); } else if (dScores.length > 0 && pScores.length == 0) { d = opFun(dScores); p = 0; } else if (dScores.length == 0 && pScores.length > 0) { d = 0; p = revFun(pScores); } else { throw new EvaluationError(`Unsupported alternative when evaluating ${this.name} macro`) } if (p > 0) { result = Math.max(d - p, -4); } else { result = Math.max(d, -4); } } else { throw new EvaluationError(`Unsupported parent node type ${root.type} when evaluating ${this.name} macro`) } return this.scoreToSet(result, CS); } } protected expandInner(ctx: CertusContext, target?: string, op?: string, revOp?: string): string { const root: Node = ctx.getRoot(); const nodes = this.getNodesFromContext(ctx); const premises = nodes.filter(n => NodeType.checkSubType(NodeType.PREMISE, n.type)).map(p => p.id); const defeaters = nodes.filter(n => NodeType.checkSubType(NodeType.DEFEATER, n.type)).map(d => d.id); if (target) { if (NodeType.checkSubType(NodeType.PREMISE, root.type)) { if (premises.length == 0 && defeaters.length == 0) { return `${target} is ${ctx.getDefaultCanonical(root.type)}`; } else if (premises.length > 0 && defeaters.length == 0) { return `${target} is ${op}(${premises.join(", ")})`; } else if (premises.length == 0 && defeaters.length > 0) { const expr = this.generateCases(root.type, [], ["d"], ctx.getCanonicalSets(), ctx.getCanonicalSet("uncert")); return `with\n\td as ${revOp}(${defeaters.join(", ")})\nend\n${target} is ${expr}`; } else { const expr = this.generateCases(root.type, ["c"], ["d"], ctx.getCanonicalSets(), ctx.getCanonicalSet("uncert")); return `with\n\tc as ${op}(${premises.join(",")});\n\td as ${revOp}(${defeaters.join(",")})\nend\n${target} is ${expr}`; } } else if (NodeType.checkSubType(NodeType.DEFEATER, root.type)) { if (premises.length == 0 && defeaters.length == 0) { return `${target} is ${ctx.getDefaultCanonical(root.type)}`; } else if (defeaters.length > 0 && premises.length == 0) { return `${target} is ${op}(${defeaters.join(", ")})`; } else if (defeaters.length == 0 && premises.length > 0) { const expr = this.generateCases(root.type, ["c"], [], ctx.getCanonicalSets(), ctx.getCanonicalSet("uncert")); return `with\n\tc as ${revOp}(${premises.join(", ")})\nend\n${target} is ${expr}`; } else { const expr = this.generateCases(root.type, ["c"], ["d"], ctx.getCanonicalSets(), ctx.getCanonicalSet("uncert")); return `with\n\td as ${op}(${defeaters.join(",")});\n\tc as ${revOp}(${premises.join(",")})\nend\n${target} is ${expr}`; } } else { throw new EvaluationError(`Unsupported parent node type '${root.type.toString()}' for ${this.name} macro expansion.`) } } else { throw new EvaluationError(`${this.name} macro expansion requires an assignment target, none provided.`) } } } export class MinMacro extends MinMaxMacro { constructor(name?: string | undefined) { super(name || "min"); } public evaluate(ctx: CertusContext): FZ { return this.evaluateInner(ctx, "min", "max"); } public expand(ctx: CertusContext, target?: string): string { return this.expandInner(ctx, target, "min", "max"); } } export class MaxMacro extends MinMaxMacro { constructor(name?: string | undefined) { super(name || "max"); } public evaluate(ctx: CertusContext): FZ { return this.evaluateInner(ctx, "max", "min"); } public expand(ctx: CertusContext, target?: string): string { return this.expandInner(ctx, target, "max", "min"); } }