import { Node, NodeType } from "../model/Argument"; import { CertusContext, FZ } from "../model/Context"; import { EvaluationError } from "../parser/Evaluator"; import { DeductiveMacro } from "./DeductiveMacro"; abstract class MinMaxStrictMacro extends DeductiveMacro { 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)) { if (dScores.some(d => d > -4)) { result = -4; } else if (pScores.length == 0) { result = 0; } else { result = opFun(pScores); } } else if (NodeType.checkSubType(NodeType.DEFEATER, root.type)) { if (dScores.every(d => d <= -4) && pScores.every(p => p >= 4)) { result = -4; } else if (pScores.length == 0 && dScores.length > 0) { result = opFun(dScores); } else if (pScores.length > 0 && dScores.length == 0) { result = revFun(pScores.map(p => p * -1)); } else { result = opFun(dScores.concat([revFun(pScores.map(p => -1 * p))])); } } else { throw new EvaluationError(`Unsupported parent node type ${root.type} when evaluating ${this.name} macro`) } return this.scoreToSet(result, CS); } } protected innerExpand(ctx: CertusContext, op: "min" | "max", revOp: "min" | "max", target?: string): string { const root: Node = ctx.getRoot(); const nodes = this.getNodesFromContext(ctx); const premises = nodes.filter(n => NodeType.checkSubType(NodeType.PREMISE, n.type)).map(x => x.id); const defeaters = nodes.filter(n => NodeType.checkSubType(NodeType.DEFEATER, n.type)).map(x => x.id); const C = ctx.getCanonicalSets() const reject = C[0].name; const cert = C[C.length - 1].name; if (target) { if (premises.length == 0 && defeaters.length == 0) { return `${target} is ${ctx.getDefaultCanonical(root.type)}`; } if (NodeType.checkSubType(NodeType.PREMISE, root.type)) { if (premises.length == 0 && defeaters.length > 0) { const dCond = defeaters.map(d => d + ` > ${reject}`).join(" or "); return `${target} is cases\n\t${dCond} -> ${reject},\n\totherwise ${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 dCond = defeaters.map(d => d + ` > ${reject}`).join(" or "); return `${target} is cases\n\t${dCond} -> ${reject},\n\totherwise ${op}(${premises.join(", ")})` } else { throw new EvaluationError(`${this.name} macro expansion fails for unknown alternative`); } } else if (NodeType.checkSubType(NodeType.DEFEATER, root.type)) { if (premises.length == 0 && defeaters.length > 0) { return `${target} is ${op}(${defeaters.join(", ")})`; } else if (premises.length > 0 && defeaters.length == 0) { const pArgs = premises.map(p => `invert ${p}`).join(", ") return `${target} is ${revOp}(${pArgs})`; } else if (premises.length > 0 && defeaters.length > 0) { // for certain case const cond: string[] = []; defeaters.forEach(d => cond.push(`${d} is ${reject}`)); premises.forEach(p => cond.push(`${p} is ${cert}`)); // for otherwise case const pArgs = premises.map(p => `invert ${p}`); const args = defeaters.concat([`${revOp}(${pArgs.join(", ")})`]); const A = args.join(", "); return `${target} is cases\n\t${cond.join(" and ")} -> ${reject},\n\totherwise ${op}(${A})` } else { throw new EvaluationError(`${this.name} macro expansion fails for unknown alternative`); } } } else { throw new EvaluationError(`${this.name} macro expansion requires an assignment target, none provided.`) } } } export class MinStrictMacro extends MinMaxStrictMacro { constructor(name?: string | undefined) { super(name || "min_strict"); } public evaluate(ctx: CertusContext): FZ { return this.evaluateInner(ctx, "min", "max"); } public expand(ctx: CertusContext, target?: string): string { return this.innerExpand(ctx, "min", "max", target); } } export class MaxStrictMacro extends MinMaxStrictMacro { constructor(name?: string | undefined) { super(name || "max_strict"); } public evaluate(ctx: CertusContext): FZ { return this.evaluateInner(ctx, "max", "min"); } public expand(ctx: CertusContext, target?: string): string { return this.innerExpand(ctx, "max", "min", target); } }